Test Support: KT-22306

Do not show run markers in JS modules when no relevant run configurations are available

 #KT-22306 Fixed
This commit is contained in:
Alexey Sedunov
2018-03-22 19:59:22 +03:00
parent 3e91346240
commit b52b07ec79
13 changed files with 294 additions and 144 deletions
@@ -49,6 +49,16 @@ public class ForTestCompileRuntime {
return assertExists(new File("dist/kotlinc/lib/kotlin-test.jar"));
}
@NotNull
public static File kotlinTestJUnitJarForTests() {
return assertExists(new File("dist/kotlinc/lib/kotlin-test-junit.jar"));
}
@NotNull
public static File kotlinTestJsJarForTests() {
return assertExists(new File("dist/kotlinc/lib/kotlin-test-js.jar"));
}
@NotNull
public static File reflectJarForTests() {
return assertExists(new File("dist/kotlinc/lib/kotlin-reflect.jar"));
@@ -16,14 +16,19 @@
package org.jetbrains.kotlin.idea.highlighter
import com.intellij.execution.actions.RunConfigurationProducer
import com.intellij.execution.lineMarker.ExecutorAction
import com.intellij.execution.lineMarker.RunLineMarkerContributor
import com.intellij.icons.AllIcons
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.MainFunctionDetector
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.js.KotlinJSRunConfigurationDataProvider
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
import org.jetbrains.kotlin.js.resolve.JsPlatform
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.resolve.TargetPlatform
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
class KotlinRunLineMarkerContributor : RunLineMarkerContributor() {
override fun getInfo(element: PsiElement): Info? {
@@ -36,6 +41,22 @@ class KotlinRunLineMarkerContributor : RunLineMarkerContributor() {
}
if (detector.isMain(function)) {
val platform = TargetPlatformDetector.getPlatform(function.containingKtFile)
val isAvailable = when (platform) {
is JvmPlatform -> true
is JsPlatform, is TargetPlatform.Common -> {
RunConfigurationProducer
.getProducers(function.project)
.asSequence()
.filterIsInstance<KotlinJSRunConfigurationDataProvider<*>>()
.filter { !it.isForTests }
.mapNotNull { it.getConfigurationData(function) }
.firstOrNull() != null
}
else -> false
}
if (!isAvailable) return null
return RunLineMarkerContributor.Info(AllIcons.RunConfigurations.TestState.Run, null, ExecutorAction.getActions(0))
}
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.idea.highlighter
import com.intellij.codeInsight.TestFrameworks
import com.intellij.execution.TestStateStorage
import com.intellij.execution.actions.RunConfigurationProducer
import com.intellij.execution.lineMarker.ExecutorAction
import com.intellij.execution.lineMarker.RunLineMarkerContributor
import com.intellij.execution.testframework.TestIconMapper
@@ -33,10 +34,8 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptorWithResolutionScopes
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.js.jsOrJsImpl
import org.jetbrains.kotlin.idea.js.jsTestOutputFilePath
import org.jetbrains.kotlin.idea.js.KotlinJSRunConfigurationDataProvider
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
import org.jetbrains.kotlin.idea.util.module
import org.jetbrains.kotlin.idea.util.string.joinWithEscape
import org.jetbrains.kotlin.js.resolve.JsPlatform
import org.jetbrains.kotlin.name.FqName
@@ -110,12 +109,17 @@ class KotlinTestRunLineMarkerContributor : RunLineMarkerContributor() {
private fun getJavaScriptTestIcon(declaration: KtNamedDeclaration, descriptor: DeclarationDescriptor): Icon? {
if (!descriptor.isTest()) return null
val module = declaration.module?.jsOrJsImpl() ?: return null
val testFilePath = module.jsTestOutputFilePath ?: return null
val runConfigData = RunConfigurationProducer
.getProducers(declaration.project)
.asSequence()
.filterIsInstance<KotlinJSRunConfigurationDataProvider<*>>()
.filter { it.isForTests }
.mapNotNull { it.getConfigurationData(declaration) }
.firstOrNull() ?: return null
val locations = ArrayList<String>()
locations += FileUtil.toSystemDependentName(testFilePath)
locations += FileUtil.toSystemDependentName(runConfigData.jsOutputFilePath)
val klass = when (declaration) {
is KtClassOrObject -> declaration
@@ -0,0 +1,20 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.js
import com.intellij.openapi.module.Module
import com.intellij.psi.PsiElement
interface KotlinJSRunConfigurationData {
val element: PsiElement
val module: Module
val jsOutputFilePath: String
}
interface KotlinJSRunConfigurationDataProvider<out T : KotlinJSRunConfigurationData> {
val isForTests: Boolean
fun getConfigurationData(element: PsiElement): T?
}
@@ -1,6 +1,3 @@
// !CHECK_HIGHLIGHTING
package kotlin.test
annotation class Test
annotation class Ignore
package test
@@ -0,0 +1,18 @@
import kotlin.test.*
class SimpleTest {
@Test fun testFoo() {
// Will run
}
@Ignore fun testFooWrong() {
// Will not run
}
}
@Ignore
class TestTest {
@Test fun emptyTest() {
// Will not run
}
}
@@ -11,8 +11,8 @@ class <lineMarker descr="Run Test">SimpleTest</lineMarker> {
}
@Ignore
class TestTest {
@Test fun emptyTest() {
class <lineMarker descr="Run Test">TestTest</lineMarker> {
@Test fun <lineMarker descr="Run Test">emptyTest</lineMarker>() {
// Will not run
}
}
@@ -55,6 +55,10 @@ fun AbstractMultiModuleTest.setupMppProjectFromDirStructure(testRoot: File) {
})
}
is CoroutinesDependency -> module.enableCoroutines()
is KotlinTestDependency -> when (id.platform) {
is TargetPlatformKind.Jvm -> module.addLibrary(ForTestCompileRuntime.kotlinTestJUnitJarForTests())
is TargetPlatformKind.JavaScript -> module.addLibrary(ForTestCompileRuntime.kotlinTestJsJarForTests(), kind = JSLibraryKind)
}
}
}
}
@@ -142,6 +146,7 @@ private fun parseDependency(it: String): Dependency {
dependencyString.equals("stdlib", ignoreCase = true) -> StdlibDependency
dependencyString.equals("fulljdk", ignoreCase = true) -> FullJdkDependency
dependencyString.equals("coroutines", ignoreCase = true) -> CoroutinesDependency
dependencyString.equals("kotlin-test", ignoreCase = true) -> KotlinTestDependency
else -> ModuleDependency(parseModuleId(dependencyString.split("-")))
}
}
@@ -190,4 +195,5 @@ private sealed class Dependency
private class ModuleDependency(val moduleId: ModuleId) : Dependency()
private object StdlibDependency : Dependency()
private object FullJdkDependency : Dependency()
private object CoroutinesDependency : Dependency()
private object CoroutinesDependency : Dependency()
private object KotlinTestDependency : Dependency()
@@ -55,6 +55,10 @@ fun AbstractMultiModuleTest.setupMppProjectFromDirStructure(testRoot: File) {
})
}
is CoroutinesDependency -> module.enableCoroutines()
is KotlinTestDependency -> when (id.platform) {
is TargetPlatformKind.Jvm -> module.addLibrary(ForTestCompileRuntime.kotlinTestJUnitJarForTests())
is TargetPlatformKind.JavaScript -> module.addLibrary(ForTestCompileRuntime.kotlinTestJsJarForTests(), kind = JSLibraryKind)
}
}
}
}
@@ -142,6 +146,7 @@ private fun parseDependency(it: String): Dependency {
dependencyString.equals("stdlib", ignoreCase = true) -> StdlibDependency
dependencyString.equals("fulljdk", ignoreCase = true) -> FullJdkDependency
dependencyString.equals("coroutines", ignoreCase = true) -> CoroutinesDependency
dependencyString.equals("kotlin-test", ignoreCase = true) -> KotlinTestDependency
else -> ModuleDependency(parseModuleId(dependencyString.split("-")))
}
}
@@ -190,4 +195,5 @@ private sealed class Dependency
private class ModuleDependency(val moduleId: ModuleId) : Dependency()
private object StdlibDependency : Dependency()
private object FullJdkDependency : Dependency()
private object CoroutinesDependency : Dependency()
private object CoroutinesDependency : Dependency()
private object KotlinTestDependency : Dependency()
@@ -7,14 +7,16 @@ package org.jetbrains.kotlin.idea.nodejs.cli
import com.intellij.execution.actions.ConfigurationContext
import com.intellij.execution.actions.RunConfigurationProducer
import com.intellij.openapi.module.Module
import com.intellij.openapi.util.Ref
import com.intellij.openapi.util.io.FileUtil
import com.intellij.psi.PsiElement
import com.jetbrains.nodejs.run.NodeJsRunConfiguration
import com.jetbrains.nodejs.run.NodeJsRunConfigurationType
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.MainFunctionDetector
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.js.KotlinJSRunConfigurationData
import org.jetbrains.kotlin.idea.js.KotlinJSRunConfigurationDataProvider
import org.jetbrains.kotlin.idea.js.jsOrJsImpl
import org.jetbrains.kotlin.idea.js.jsProductionOutputFilePath
import org.jetbrains.kotlin.idea.nodejs.TestElementPath
@@ -25,40 +27,51 @@ import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
class NodeJsConfigData(
override val element: PsiElement,
override val module: Module,
override val jsOutputFilePath: String
) : KotlinJSRunConfigurationData
private class KotlinNodeJsRunConfigurationProducer :
RunConfigurationProducer<NodeJsRunConfiguration>(NodeJsRunConfigurationType.getInstance()) {
RunConfigurationProducer<NodeJsRunConfiguration>(NodeJsRunConfigurationType.getInstance()),
KotlinJSRunConfigurationDataProvider<NodeJsConfigData> {
private val ConfigurationContext?.isAcceptable: Boolean
get() {
val original = this?.getOriginalConfiguration(null)
return original == null || original is NodeJsRunConfiguration
}
override val isForTests: Boolean
get() = false
private fun getConfigurationData(element: PsiElement, context: ConfigurationContext?): NodeJsConfigData? {
if (context != null && !context.isAcceptable) return null
val jsModule = element.module?.jsOrJsImpl() ?: return null
val jsFilePath = jsModule.jsProductionOutputFilePath ?: return null
val declaration = element.getNonStrictParentOfType<KtNamedDeclaration>()
if (declaration is KtNamedFunction) {
val detector = MainFunctionDetector { it.resolveToDescriptorIfAny() }
if (!detector.isMain(declaration, false)) return null
} else if (!TestElementPath.isModuleAssociatedDir(element, jsModule)) return null
return NodeJsConfigData(element, jsModule, jsFilePath)
}
override fun getConfigurationData(element: PsiElement) = getConfigurationData(element, null)
override fun setupConfigurationFromContext(
configuration: NodeJsRunConfiguration,
context: ConfigurationContext,
sourceElement: Ref<PsiElement>
): Boolean {
if (!context.isAcceptable) return false
val psiElement = sourceElement.get() ?: return false
val psiFile = psiElement.containingFile ?: return false
val jsModule = psiFile.module?.jsOrJsImpl() ?: return false
val project = psiFile.project
val declaration = psiElement.getNonStrictParentOfType<KtNamedDeclaration>()
if (declaration is KtNamedFunction) {
val detector = MainFunctionDetector { it.resolveToDescriptorIfAny() }
if (!detector.isMain(declaration, false)) return false
}
else if (!TestElementPath.isModuleAssociatedDir(psiElement, jsModule)) return false
val jsFilePath = jsModule.jsProductionOutputFilePath ?: return false
val configData = getConfigurationData(psiElement, context) ?: return false
if (configuration.workingDirectory.isNullOrBlank()) {
configuration.workingDirectory = FileUtil.toSystemDependentName(project.baseDir.path)
configuration.workingDirectory = FileUtil.toSystemDependentName(psiElement.project.baseDir.path)
}
configuration.inputPath = jsFilePath
configuration.envs = jsModule.getNodeJsEnvironmentVars(false).envs
configuration.inputPath = configData.jsOutputFilePath
configuration.envs = configData.module.getNodeJsEnvironmentVars(false).envs
configuration.setGeneratedName()
configuration.addBuildTask()
@@ -66,11 +79,8 @@ private class KotlinNodeJsRunConfigurationProducer :
}
override fun isConfigurationFromContext(configuration: NodeJsRunConfiguration, context: ConfigurationContext): Boolean {
if (!context.isAcceptable) return false
val contextPsi = context.psiLocation ?: return false
val jsModule = contextPsi.module?.jsOrJsImpl() ?: return false
val jsFilePath = jsModule.jsProductionOutputFilePath ?: return false
return configuration.inputPath == jsFilePath
val configData = getConfigurationData(contextPsi, context) ?: return false
return configuration.inputPath == configData.jsOutputFilePath
}
}
@@ -10,35 +10,49 @@ import com.intellij.javascript.jest.JestRunConfiguration
import com.intellij.javascript.jest.JestRunConfigurationProducer
import com.intellij.javascript.jest.JestRunSettings
import com.intellij.javascript.jest.scope.JestScopeKind
import com.intellij.openapi.module.Module
import com.intellij.openapi.util.Ref
import com.intellij.openapi.util.io.FileUtil
import com.intellij.psi.PsiElement
import com.intellij.psi.util.PsiUtilCore
import org.jetbrains.kotlin.idea.js.KotlinJSRunConfigurationData
import org.jetbrains.kotlin.idea.js.jsOrJsImpl
import org.jetbrains.kotlin.idea.js.jsTestOutputFilePath
import org.jetbrains.kotlin.idea.js.KotlinJSRunConfigurationDataProvider
import org.jetbrains.kotlin.idea.nodejs.TestElementInfo
import org.jetbrains.kotlin.idea.nodejs.TestElementPath
import org.jetbrains.kotlin.idea.nodejs.getNodeJsEnvironmentVars
import org.jetbrains.kotlin.idea.run.addBuildTask
import org.jetbrains.kotlin.idea.util.projectStructure.module
private typealias JestTestElementInfo = TestElementInfo<JestRunSettings>
typealias JestTestElementInfo = TestElementInfo<JestRunSettings>
class JestConfigData(
override val element: PsiElement,
override val module: Module,
override val jsOutputFilePath: String,
val testElementPath: TestElementPath
) : KotlinJSRunConfigurationData
class KotlinJestRunConfigurationProducer :
JestRunConfigurationProducer(),
KotlinJSRunConfigurationDataProvider<JestConfigData> {
private fun createTestElementRunInfo(
configData: JestConfigData,
originalSettings: JestRunSettings
): JestTestElementInfo {
val project = configData.module.project
class KotlinJestRunConfigurationProducer : JestRunConfigurationProducer() {
private fun createTestElementRunInfo(element: PsiElement, originalSettings: JestRunSettings): JestTestElementInfo? {
val module = element.module?.jsOrJsImpl() ?: return null
val project = module.project
val testFilePath = module.jsTestOutputFilePath ?: return null
val settings = if (originalSettings.workingDirSystemDependentPath.isBlank()) {
val workingDir = FileUtil.toSystemDependentName(project.baseDir.path)
originalSettings.toBuilder().setWorkingDir(workingDir).build()
} else originalSettings
val testElementPath = TestElementPath.forElement(element, module) ?: return null
val builder = settings.toBuilder()
builder.setTestFilePath(testFilePath)
when (testElementPath) {
builder.setTestFilePath(configData.jsOutputFilePath)
when (configData.testElementPath) {
is TestElementPath.BySuite -> {
val (suiteNames, testName) = testElementPath
val (suiteNames, testName) = configData.testElementPath
if (testName == null) {
builder.setScopeKind(JestScopeKind.SUITE)
builder.setTestNames(suiteNames)
@@ -52,14 +66,38 @@ class KotlinJestRunConfigurationProducer : JestRunConfigurationProducer() {
builder.setScopeKind(JestScopeKind.TEST_FILE)
}
}
builder.setEnvData(module.getNodeJsEnvironmentVars(true))
builder.setEnvData(configData.module.getNodeJsEnvironmentVars(true))
return JestTestElementInfo(builder.build(), element)
return JestTestElementInfo(builder.build(), configData.element)
}
override val isForTests: Boolean
get() = true
override fun getConfigurationData(element: PsiElement): JestConfigData? {
val module = element.module
val jsModule = module?.jsOrJsImpl() ?: return null
val file = if (jsModule != module) {
jsModule.moduleFile
} else {
PsiUtilCore.getVirtualFile(element)
} ?: return null
val project = module.project
if (!isTestRunnerPackageAvailableFor(project, file)) return null
val testFilePath = module.jsTestOutputFilePath ?: return null
val testElementPath = TestElementPath.forElement(element, module) ?: return null
return JestConfigData(element, jsModule, testFilePath, testElementPath)
}
override fun isConfigurationFromCompatibleContext(configuration: JestRunConfiguration, context: ConfigurationContext): Boolean {
val element = context.psiLocation ?: return false
val (thisRunSettings, _) = createTestElementRunInfo(element, configuration.runSettings) ?: return false
val configData = getConfigurationData(element) ?: return false
val (thisRunSettings, _) = createTestElementRunInfo(configData, configuration.runSettings)
val thatRunSettings = configuration.runSettings
if (thisRunSettings.configFileSystemDependentPath != thatRunSettings.configFileSystemDependentPath) return false
@@ -80,18 +118,8 @@ class KotlinJestRunConfigurationProducer : JestRunConfigurationProducer() {
sourceElement: Ref<PsiElement>
): Boolean {
val element = context.psiLocation ?: return false
val module = element.module
val jsModule = module?.jsOrJsImpl() ?: return false
val file = if (jsModule != module) {
jsModule.moduleFile
} else {
PsiUtilCore.getVirtualFile(element)
} ?: return false
val project = module.project
if (!isTestRunnerPackageAvailableFor(project, file)) return false
val (runSettings, enclosingTestElement) = createTestElementRunInfo(element, configuration.runSettings) ?: return false
val configData = getConfigurationData(element) ?: return false
val (runSettings, enclosingTestElement) = createTestElementRunInfo(configData, configuration.runSettings)
configuration.runSettings = runSettings
sourceElement.set(enclosingTestElement)
configuration.setGeneratedName()
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.idea.nodejs.mocha
import com.intellij.execution.RunManager
import com.intellij.execution.actions.ConfigurationContext
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Ref
import com.intellij.openapi.util.io.FileUtil
@@ -30,6 +31,8 @@ import com.intellij.util.SmartList
import com.intellij.util.containers.SmartHashSet
import com.jetbrains.nodejs.mocha.MochaUtil
import com.jetbrains.nodejs.mocha.execution.*
import org.jetbrains.kotlin.idea.js.KotlinJSRunConfigurationData
import org.jetbrains.kotlin.idea.js.KotlinJSRunConfigurationDataProvider
import org.jetbrains.kotlin.idea.js.jsOrJsImpl
import org.jetbrains.kotlin.idea.js.jsTestOutputFilePath
import org.jetbrains.kotlin.idea.nodejs.TestElementInfo
@@ -40,79 +43,52 @@ import org.jetbrains.kotlin.idea.util.projectStructure.module
private typealias MochaTestElementInfo = TestElementInfo<MochaRunSettings>
class KotlinMochaRunConfigurationProducer : MochaRunConfigurationProducer() {
class MochaConfigData(
override val element: PsiElement,
override val module: Module,
override val jsOutputFilePath: String,
val testElementPath: TestElementPath
) : KotlinJSRunConfigurationData
class KotlinMochaRunConfigurationProducer : MochaRunConfigurationProducer(), KotlinJSRunConfigurationDataProvider<MochaConfigData> {
// Copied from MochaRunConfigurationProducer.collectMochaTestRoots()
private fun collectMochaTestRoots(project: Project): List<VirtualFile> {
return RunManager
.getInstance(project)
.getConfigurationsList(MochaConfigurationType.getInstance())
.filterIsInstance<MochaRunConfiguration>()
.mapNotNullTo(SmartList<VirtualFile>()) { configuration ->
val settings = configuration.runSettings
val path = when (settings.testKind) {
MochaTestKind.DIRECTORY -> settings.testDirPath
MochaTestKind.TEST_FILE,
MochaTestKind.SUITE,
MochaTestKind.TEST -> settings.testFilePath
else -> null
}
if (path.isNullOrBlank()) return@mapNotNullTo null
LocalFileSystem.getInstance().findFileByPath(path!!)
.getInstance(project)
.getConfigurationsList(MochaConfigurationType.getInstance())
.filterIsInstance<MochaRunConfiguration>()
.mapNotNullTo(SmartList<VirtualFile>()) { configuration ->
val settings = configuration.runSettings
val path = when (settings.testKind) {
MochaTestKind.DIRECTORY -> settings.testDirPath
MochaTestKind.TEST_FILE,
MochaTestKind.SUITE,
MochaTestKind.TEST -> settings.testFilePath
else -> null
}
}
// Copied from MochaRunConfigurationProducer.isActiveFor()
private fun isActiveFor(element: PsiElement, context: ConfigurationContext): Boolean {
val module = element.module
val jsModule = module?.jsOrJsImpl() ?: return false
val file = if (jsModule != module) {
jsModule.moduleFile
}
else {
PsiUtilCore.getVirtualFile(element)
} ?: return false
val project = module.project
if (isTestRunnerPackageAvailableFor(project, file)) return true
if (context.getOriginalConfiguration(MochaConfigurationType.getInstance()) is MochaRunConfiguration) return true
val roots = collectMochaTestRoots(project)
if (roots.isEmpty()) return false
val dirs = SmartHashSet<VirtualFile>()
for (root in roots) {
if (root.isDirectory) {
dirs.add(root)
if (path.isNullOrBlank()) return@mapNotNullTo null
LocalFileSystem.getInstance().findFileByPath(path!!)
}
else if (root == file) return true
}
return VfsUtilCore.isUnder(file, dirs)
}
private fun createTestElementRunInfo(element: PsiElement, originalSettings: MochaRunSettings): MochaTestElementInfo? {
val module = element.module?.jsOrJsImpl() ?: return null
val project = module.project
val testFilePath = module.jsTestOutputFilePath ?: return null
private fun createTestElementRunInfo(configData: MochaConfigData, originalSettings: MochaRunSettings): MochaTestElementInfo {
val project = configData.module.project
val settings = if (originalSettings.workingDir.isBlank()) {
val workingDir = FileUtil.toSystemDependentName(project.baseDir.path)
originalSettings.builder().setWorkingDir(workingDir).build()
}
else originalSettings
val testElementPath = TestElementPath.forElement(element, module) ?: return null
} else originalSettings
val builder = settings.builder()
builder.setTestFilePath(testFilePath)
builder.setTestFilePath(configData.jsOutputFilePath)
if (settings.ui.isEmpty()) {
builder.setUi(MochaUtil.UI_BDD)
}
when (testElementPath) {
when (configData.testElementPath) {
is TestElementPath.BySuite -> {
val (suiteNames, testName) = testElementPath
val (suiteNames, testName) = configData.testElementPath
if (testName == null) {
builder.setTestKind(MochaTestKind.SUITE)
builder.setSuiteNames(suiteNames)
}
else {
} else {
builder.setTestKind(MochaTestKind.TEST)
builder.setTestNames(suiteNames + testName)
}
@@ -123,14 +99,53 @@ class KotlinMochaRunConfigurationProducer : MochaRunConfigurationProducer() {
}
}
builder.setEnvData(module.getNodeJsEnvironmentVars(true))
builder.setEnvData(configData.module.getNodeJsEnvironmentVars(true))
return MochaTestElementInfo(builder.build(), element)
return MochaTestElementInfo(builder.build(), configData.element)
}
private fun getConfigurationData(element: PsiElement, context: ConfigurationContext?): MochaConfigData? {
val module = element.module
val jsModule = module?.jsOrJsImpl() ?: return null
val file = if (jsModule != module) {
jsModule.moduleFile
} else {
PsiUtilCore.getVirtualFile(element)
} ?: return null
val project = module.project
if (isTestRunnerPackageAvailableFor(project, file)) return null
val testFilePath = module.jsTestOutputFilePath ?: return null
val testElementPath = TestElementPath.forElement(element, module) ?: return null
val configData = MochaConfigData(element, jsModule, testFilePath, testElementPath)
if (context?.getOriginalConfiguration(MochaConfigurationType.getInstance()) is MochaRunConfiguration) return configData
val roots = collectMochaTestRoots(project)
if (roots.isEmpty()) return null
val dirs = SmartHashSet<VirtualFile>()
for (root in roots) {
if (root.isDirectory) {
dirs.add(root)
} else if (root == file) return configData
}
return if (VfsUtilCore.isUnder(file, dirs)) configData else configData
}
override val isForTests: Boolean
get() = true
override fun getConfigurationData(element: PsiElement): MochaConfigData? {
return getConfigurationData(element)
}
override fun isConfigurationFromCompatibleContext(configuration: MochaRunConfiguration, context: ConfigurationContext): Boolean {
val element = context.psiLocation ?: return false
val (thisRunSettings, _) = createTestElementRunInfo(element, configuration.runSettings) ?: return false
val configData = getConfigurationData(element) ?: return false
val (thisRunSettings, _) = createTestElementRunInfo(configData, configuration.runSettings)
val thatRunSettings = configuration.runSettings
val thisTestKind = thisRunSettings.testKind
if (thisTestKind != thatRunSettings.testKind) return false
@@ -145,13 +160,13 @@ class KotlinMochaRunConfigurationProducer : MochaRunConfigurationProducer() {
}
override fun setupConfigurationFromCompatibleContext(
configuration: MochaRunConfiguration,
context: ConfigurationContext,
sourceElement: Ref<PsiElement>
configuration: MochaRunConfiguration,
context: ConfigurationContext,
sourceElement: Ref<PsiElement>
): Boolean {
val element = context.psiLocation ?: return false
if (!isActiveFor(element, context)) return false
val (runSettings, enclosingTestElement) = createTestElementRunInfo(element, configuration.runSettings) ?: return false
val configData = getConfigurationData(element, context) ?: return false
val (runSettings, enclosingTestElement) = createTestElementRunInfo(configData, configuration.runSettings)
if (runSettings.testKind == MochaTestKind.DIRECTORY) return false
configuration.runSettings = runSettings
sourceElement.set(enclosingTestElement)
@@ -18,44 +18,59 @@ package org.jetbrains.kotlin.idea.nodejs.protractor
import com.intellij.execution.actions.CompatibleRunConfigurationProducer
import com.intellij.execution.actions.ConfigurationContext
import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleUtilCore
import com.intellij.openapi.util.Ref
import com.intellij.openapi.util.io.FileUtil
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.js.KotlinJSRunConfigurationData
import org.jetbrains.kotlin.idea.js.KotlinJSRunConfigurationDataProvider
import org.jetbrains.kotlin.idea.js.jsOrJsImpl
import org.jetbrains.kotlin.idea.js.jsTestOutputFilePath
import org.jetbrains.kotlin.idea.nodejs.TestElementPath
import org.jetbrains.kotlin.idea.nodejs.getNodeJsEnvironmentVars
import org.jetbrains.kotlin.idea.run.addBuildTask
import org.jetbrains.kotlin.idea.util.projectStructure.module
class ProtractorConfigData(
override val element: PsiElement,
override val module: Module,
override val jsOutputFilePath: String
) : KotlinJSRunConfigurationData
class KotlinProtractorRunConfigurationProducer :
CompatibleRunConfigurationProducer<KotlinProtractorRunConfiguration>(KotlinProtractorConfigurationType.getInstance()) {
CompatibleRunConfigurationProducer<KotlinProtractorRunConfiguration>(KotlinProtractorConfigurationType.getInstance()),
KotlinJSRunConfigurationDataProvider<ProtractorConfigData> {
override val isForTests: Boolean
get() = true
override fun getConfigurationData(element: PsiElement): ProtractorConfigData? {
val module = ModuleUtilCore.findModuleForPsiElement(element) ?: return null
if (!TestElementPath.isModuleAssociatedDir(element, module)) return null
val jsModule = module.jsOrJsImpl() ?: return null
val testFilePath = jsModule.jsTestOutputFilePath ?: return null
return ProtractorConfigData(element, module, testFilePath)
}
override fun isConfigurationFromCompatibleContext(
configuration: KotlinProtractorRunConfiguration,
context: ConfigurationContext
configuration: KotlinProtractorRunConfiguration,
context: ConfigurationContext
): Boolean {
val contextPsi = context.psiLocation ?: return false
val jsModule = contextPsi.module?.jsOrJsImpl() ?: return false
val testFilePath = jsModule.jsTestOutputFilePath ?: return false
return configuration.runSettings.testFileSystemDependentPath == FileUtil.toSystemDependentName(testFilePath)
val configData = getConfigurationData(contextPsi) ?: return false
return configuration.runSettings.testFileSystemDependentPath == FileUtil.toSystemDependentName(configData.jsOutputFilePath)
}
override fun setupConfigurationFromCompatibleContext(
configuration: KotlinProtractorRunConfiguration,
context: ConfigurationContext,
sourceElement: Ref<PsiElement>
configuration: KotlinProtractorRunConfiguration,
context: ConfigurationContext,
sourceElement: Ref<PsiElement>
): Boolean {
val element = context.psiLocation ?: return false
val module = ModuleUtilCore.findModuleForPsiElement(element) ?: return false
if (!TestElementPath.isModuleAssociatedDir(element, module)) return false
val jsModule = module.jsOrJsImpl() ?: return false
val testFilePath = jsModule.jsTestOutputFilePath ?: return false
val configData = getConfigurationData(element) ?: return false
sourceElement.set(element)
configuration.runSettings = configuration.runSettings.copy(
testFilePath = testFilePath,
envData = jsModule.getNodeJsEnvironmentVars(true)
testFilePath = configData.jsOutputFilePath,
envData = configData.module.getNodeJsEnvironmentVars(true)
)
configuration.name = configuration.suggestedName()
configuration.addBuildTask()