Make mpp tests gutters aware of different platforms run

Behaviour is similar to the test suite gutters:
- simple triangle when there is no history
- triangle + red circle if some runs failed
- triangle + green circle if all runs passed

^KMM-100 Fixed.
This commit is contained in:
Kirill Shmakov
2020-11-17 16:58:17 +03:00
parent 0d50ccc42d
commit 8ede19811d
7 changed files with 186 additions and 57 deletions
@@ -1,15 +1,17 @@
/* /*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* that can be found in the license/LICENSE.txt file. * 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.platform package org.jetbrains.kotlin.platform
import kotlin.reflect.KClass
inline fun <reified T : SimplePlatform> TargetPlatform.subplatformsOfType(): List<T> = componentPlatforms.filterIsInstance<T>() inline fun <reified T : SimplePlatform> TargetPlatform.subplatformsOfType(): List<T> = componentPlatforms.filterIsInstance<T>()
fun <T> TargetPlatform.subplatformsOfType(klass: Class<T>): List<T> = componentPlatforms.filterIsInstance(klass) fun <T> TargetPlatform.subplatformsOfType(klass: Class<T>): List<T> = componentPlatforms.filterIsInstance(klass)
inline fun <reified T : SimplePlatform> TargetPlatform?.has(): Boolean = this != null && subplatformsOfType<T>().isNotEmpty() inline fun <reified T : SimplePlatform> TargetPlatform?.has(): Boolean = this != null && subplatformsOfType<T>().isNotEmpty()
fun <T> TargetPlatform?.has(klass: Class<T>): Boolean = this != null && subplatformsOfType(klass).isNotEmpty() fun TargetPlatform?.has(klass: KClass<*>): Boolean = this != null && subplatformsOfType(klass.java).isNotEmpty()
/** /**
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@@ -25,16 +25,22 @@ import org.jetbrains.kotlin.gradle.KotlinCompilation
import org.jetbrains.kotlin.gradle.KotlinModule import org.jetbrains.kotlin.gradle.KotlinModule
import org.jetbrains.kotlin.gradle.KotlinPlatform import org.jetbrains.kotlin.gradle.KotlinPlatform
import org.jetbrains.kotlin.gradle.KotlinSourceSet import org.jetbrains.kotlin.gradle.KotlinSourceSet
import org.jetbrains.kotlin.idea.configuration.KotlinSourceSetDataService.Companion.isRelevantFor
import org.jetbrains.kotlin.idea.facet.* import org.jetbrains.kotlin.idea.facet.*
import org.jetbrains.kotlin.idea.inspections.gradle.findAll import org.jetbrains.kotlin.idea.inspections.gradle.findAll
import org.jetbrains.kotlin.idea.inspections.gradle.findKotlinPluginVersion import org.jetbrains.kotlin.idea.inspections.gradle.findKotlinPluginVersion
import org.jetbrains.kotlin.idea.platform.IdePlatformKindTooling import org.jetbrains.kotlin.idea.platform.IdePlatformKindTooling
import org.jetbrains.kotlin.idea.roots.migrateNonJvmSourceFolders import org.jetbrains.kotlin.idea.roots.migrateNonJvmSourceFolders
import org.jetbrains.kotlin.idea.roots.populateNonJvmSourceRootTypes import org.jetbrains.kotlin.idea.roots.populateNonJvmSourceRootTypes
import org.jetbrains.kotlin.platform.IdePlatformKind
import org.jetbrains.kotlin.platform.SimplePlatform
import org.jetbrains.kotlin.platform.TargetPlatform import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.impl.JvmIdePlatformKind import org.jetbrains.kotlin.platform.impl.JvmIdePlatformKind
import org.jetbrains.kotlin.platform.impl.NativeIdePlatformKind import org.jetbrains.kotlin.platform.impl.NativeIdePlatformKind
import org.jetbrains.kotlin.platform.js.JsPlatform
import org.jetbrains.kotlin.platform.jvm.JvmPlatform
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.platform.konan.NativePlatform
import org.jetbrains.kotlin.platform.konan.NativePlatforms import org.jetbrains.kotlin.platform.konan.NativePlatforms
import org.jetbrains.plugins.gradle.model.data.BuildScriptClasspathData import org.jetbrains.plugins.gradle.model.data.BuildScriptClasspathData
import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData
@@ -43,12 +49,30 @@ import org.jetbrains.plugins.gradle.util.GradleConstants
class KotlinSourceSetDataService : AbstractProjectDataService<GradleSourceSetData, Void>() { class KotlinSourceSetDataService : AbstractProjectDataService<GradleSourceSetData, Void>() {
override fun getTargetDataKey() = GradleSourceSetData.KEY override fun getTargetDataKey() = GradleSourceSetData.KEY
private fun getProjectPlatforms(toImport: MutableCollection<DataNode<GradleSourceSetData>>): List<KotlinPlatform> {
val platforms = HashSet<KotlinPlatform>()
for (nodeToImport in toImport) {
nodeToImport.kotlinSourceSet?.also {
platforms += it.actualPlatforms.platforms
}
if (nodeToImport.parent?.children?.any { it.key.dataType.contains("Android") } == true) {
platforms += KotlinPlatform.ANDROID
}
}
return platforms.toList()
}
override fun postProcess( override fun postProcess(
toImport: MutableCollection<DataNode<GradleSourceSetData>>, toImport: MutableCollection<DataNode<GradleSourceSetData>>,
projectData: ProjectData?, projectData: ProjectData?,
project: Project, project: Project,
modelsProvider: IdeModifiableModelsProvider modelsProvider: IdeModifiableModelsProvider
) { ) {
val projectPlatforms = getProjectPlatforms(toImport)
for (nodeToImport in toImport) { for (nodeToImport in toImport) {
val mainModuleData = ExternalSystemApiUtil.findParent( val mainModuleData = ExternalSystemApiUtil.findParent(
nodeToImport, nodeToImport,
@@ -65,7 +89,7 @@ class KotlinSourceSetDataService : AbstractProjectDataService<GradleSourceSetDat
populateNonJvmSourceRootTypes(nodeToImport, ideModule) populateNonJvmSourceRootTypes(nodeToImport, ideModule)
} }
configureFacet(sourceSetData, kotlinSourceSet, mainModuleData, ideModule, modelsProvider)?.let { facet -> configureFacet(sourceSetData, kotlinSourceSet, mainModuleData, ideModule, modelsProvider, projectPlatforms)?.let { facet ->
GradleProjectImportHandler.getInstances(project).forEach { it.importBySourceSet(facet, nodeToImport) } GradleProjectImportHandler.getInstances(project).forEach { it.importBySourceSet(facet, nodeToImport) }
} }
@@ -92,12 +116,59 @@ class KotlinSourceSetDataService : AbstractProjectDataService<GradleSourceSetDat
else -> KotlinModuleKind.DEFAULT else -> KotlinModuleKind.DEFAULT
} }
private fun SimplePlatform.isRelevantFor(projectPlatforms: List<KotlinPlatform>): Boolean {
val jvmPlatforms = listOf(KotlinPlatform.ANDROID, KotlinPlatform.JVM, KotlinPlatform.COMMON)
return when (this) {
is JvmPlatform -> projectPlatforms.intersect(jvmPlatforms).isNotEmpty()
is JsPlatform -> KotlinPlatform.JS in projectPlatforms
is NativePlatform -> KotlinPlatform.NATIVE in projectPlatforms
else -> true
}
}
private fun IdePlatformKind<*>.toSimplePlatforms(
moduleData: ModuleData,
isHmppModule: Boolean,
projectPlatforms: List<KotlinPlatform>
): Collection<SimplePlatform> {
if (this is JvmIdePlatformKind) {
val jvmTarget = JvmTarget.fromString(moduleData.targetCompatibility ?: "") ?: JvmTarget.DEFAULT
return JvmPlatforms.jvmPlatformByTargetVersion(jvmTarget)
}
if (this is NativeIdePlatformKind) {
return NativePlatforms.nativePlatformByTargetNames(moduleData.konanTargets)
}
return if (isHmppModule) {
this.defaultPlatform.filter { it.isRelevantFor(projectPlatforms) }
} else {
this.defaultPlatform
}
}
fun configureFacet( fun configureFacet(
moduleData: ModuleData, moduleData: ModuleData,
kotlinSourceSet: KotlinSourceSetInfo, kotlinSourceSet: KotlinSourceSetInfo,
mainModuleNode: DataNode<ModuleData>, mainModuleNode: DataNode<ModuleData>,
ideModule: Module, ideModule: Module,
modelsProvider: IdeModifiableModelsProvider modelsProvider: IdeModifiableModelsProvider
) = configureFacet(
moduleData,
kotlinSourceSet,
mainModuleNode,
ideModule,
modelsProvider,
enumValues<KotlinPlatform>().toList()
)
fun configureFacet(
moduleData: ModuleData,
kotlinSourceSet: KotlinSourceSetInfo,
mainModuleNode: DataNode<ModuleData>,
ideModule: Module,
modelsProvider: IdeModifiableModelsProvider,
projectPlatforms: List<KotlinPlatform>
): KotlinFacet? { ): KotlinFacet? {
val compilerVersion = mainModuleNode val compilerVersion = mainModuleNode
.findAll(BuildScriptClasspathData.KEY) .findAll(BuildScriptClasspathData.KEY)
@@ -107,16 +178,7 @@ class KotlinSourceSetDataService : AbstractProjectDataService<GradleSourceSetDat
val platformKinds = kotlinSourceSet.actualPlatforms.platforms //TODO(auskov): fix calculation of jvm target val platformKinds = kotlinSourceSet.actualPlatforms.platforms //TODO(auskov): fix calculation of jvm target
.map { IdePlatformKindTooling.getTooling(it).kind } .map { IdePlatformKindTooling.getTooling(it).kind }
.flatMap { platformKind -> .flatMap { it.toSimplePlatforms(moduleData, mainModuleNode.isHmpp, projectPlatforms) }
when (platformKind) {
is JvmIdePlatformKind -> {
val jvmTarget = JvmTarget.fromString(moduleData.targetCompatibility ?: "") ?: JvmTarget.DEFAULT
JvmPlatforms.jvmPlatformByTargetVersion(jvmTarget).componentPlatforms
}
is NativeIdePlatformKind -> NativePlatforms.nativePlatformByTargetNames(moduleData.konanTargets)
else -> platformKind.defaultPlatform.componentPlatforms
}
}
.distinct() .distinct()
.toSet() .toSet()
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@@ -16,9 +16,12 @@ import org.jetbrains.kotlin.idea.framework.CommonLibraryKind
import org.jetbrains.kotlin.idea.framework.CommonStandardLibraryDescription import org.jetbrains.kotlin.idea.framework.CommonStandardLibraryDescription
import org.jetbrains.kotlin.idea.framework.getCommonRuntimeLibraryVersion import org.jetbrains.kotlin.idea.framework.getCommonRuntimeLibraryVersion
import org.jetbrains.kotlin.idea.platform.IdePlatformKindTooling import org.jetbrains.kotlin.idea.platform.IdePlatformKindTooling
import org.jetbrains.kotlin.idea.platform.isCompatibleWith
import org.jetbrains.kotlin.idea.platform.tooling import org.jetbrains.kotlin.idea.platform.tooling
import org.jetbrains.kotlin.idea.project.platform import org.jetbrains.kotlin.idea.project.platform
import org.jetbrains.kotlin.idea.util.module import org.jetbrains.kotlin.idea.util.module
import org.jetbrains.kotlin.platform.SimplePlatform
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.idePlatformKind import org.jetbrains.kotlin.platform.idePlatformKind
import org.jetbrains.kotlin.platform.impl.CommonIdePlatformKind import org.jetbrains.kotlin.platform.impl.CommonIdePlatformKind
import org.jetbrains.kotlin.platform.impl.isCommon import org.jetbrains.kotlin.platform.impl.isCommon
@@ -45,9 +48,14 @@ object CommonIdePlatformKindTooling : IdePlatformKindTooling() {
return ::getCommonRuntimeLibraryVersion return ::getCommonRuntimeLibraryVersion
} }
override fun getTestIcon(declaration: KtNamedDeclaration, descriptor: DeclarationDescriptor): Icon? { private fun getRelevantToolings(platform: TargetPlatform?): List<IdePlatformKindTooling> {
val icons = getInstances() return getInstances()
.filter { it != this } .filter { it != this }
.filter { platform == null || it.kind.isCompatibleWith(platform) }
}
override fun getTestIcon(declaration: KtNamedDeclaration, descriptor: DeclarationDescriptor): Icon? {
val icons = getRelevantToolings(declaration.module?.platform)
.mapNotNull { it.getTestIcon(declaration, descriptor) } .mapNotNull { it.getTestIcon(declaration, descriptor) }
.distinct() .distinct()
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@@ -9,6 +9,8 @@ import com.intellij.codeInsight.TestFrameworks
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.libraries.Library import com.intellij.openapi.roots.libraries.Library
import com.intellij.openapi.roots.libraries.PersistentLibraryKind import com.intellij.openapi.roots.libraries.PersistentLibraryKind
import com.intellij.psi.PsiMethod
import com.intellij.testIntegration.TestFramework
import org.jetbrains.kotlin.asJava.classes.KtLightClass import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.toLightClass import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.asJava.toLightMethods import org.jetbrains.kotlin.asJava.toLightMethods
@@ -19,6 +21,7 @@ import org.jetbrains.kotlin.idea.framework.JavaRuntimeDetectionUtil
import org.jetbrains.kotlin.idea.framework.JavaRuntimeLibraryDescription import org.jetbrains.kotlin.idea.framework.JavaRuntimeLibraryDescription
import org.jetbrains.kotlin.idea.highlighter.KotlinTestRunLineMarkerContributor.Companion.getTestStateIcon import org.jetbrains.kotlin.idea.highlighter.KotlinTestRunLineMarkerContributor.Companion.getTestStateIcon
import org.jetbrains.kotlin.idea.platform.IdePlatformKindTooling import org.jetbrains.kotlin.idea.platform.IdePlatformKindTooling
import org.jetbrains.kotlin.idea.platform.isKotlinTestDeclaration
import org.jetbrains.kotlin.platform.impl.JvmIdePlatformKind import org.jetbrains.kotlin.platform.impl.JvmIdePlatformKind
import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtFunction import org.jetbrains.kotlin.psi.KtFunction
@@ -51,28 +54,41 @@ class JvmIdePlatformKindTooling : IdePlatformKindTooling() {
} }
override fun getTestIcon(declaration: KtNamedDeclaration, descriptor: DeclarationDescriptor): Icon? { override fun getTestIcon(declaration: KtNamedDeclaration, descriptor: DeclarationDescriptor): Icon? {
val (url, framework) = when (declaration) { val (urls, framework) = when (declaration) {
is KtClassOrObject -> { is KtClassOrObject -> {
val lightClass = declaration.toLightClass() ?: return null val lightClass = declaration.toLightClass() ?: return null
val framework = TestFrameworks.detectFramework(lightClass) ?: return null val framework = TestFrameworks.detectFramework(lightClass)
if (!framework.isTestClass(lightClass)) return null if (framework?.isTestClass(lightClass) == false) {
val qualifiedName = lightClass.qualifiedName ?: return null return null
}
"java:suite://$qualifiedName" to framework listOf("java:suite://${lightClass.qualifiedName}") to framework
} }
is KtNamedFunction -> { is KtNamedFunction -> {
val lightMethod = declaration.toLightMethods().firstOrNull() ?: return null val lightMethod = declaration.toLightMethods().firstOrNull() ?: return null
val lightClass = lightMethod.containingClass as? KtLightClass ?: return null val lightClass = lightMethod.containingClass as? KtLightClass ?: return null
val framework = TestFrameworks.detectFramework(lightClass) ?: return null val framework = TestFrameworks.detectFramework(lightClass)
if (!framework.isTestMethod(lightMethod, /*checkAbstract = */ false)) return null if (framework?.isTestMethod(lightMethod, false) == false) {
return null
"java:test://${lightClass.qualifiedName}/${lightMethod.name}" to framework }
listOf(
"java:test://${lightClass.qualifiedName}/${lightMethod.name}",
"java:test://${lightClass.qualifiedName}.${lightMethod.name}"
) to framework
} }
else -> return null else -> return null
} }
return getTestStateIcon(url, declaration.project, strict = false) ?: framework.icon
if (framework != null) {
return getTestStateIcon(urls, declaration.project, strict = false, framework.icon)
}
if (!descriptor.isKotlinTestDeclaration()) {
return null
}
return getTestStateIcon(urls, declaration.project, strict = false)
} }
override fun acceptsAsEntryPoint(function: KtFunction) = true override fun acceptsAsEntryPoint(function: KtFunction) = true
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@@ -11,6 +11,16 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.idea.highlighter.KotlinTestRunLineMarkerContributor.Companion.getTestStateIcon import org.jetbrains.kotlin.idea.highlighter.KotlinTestRunLineMarkerContributor.Companion.getTestStateIcon
import org.jetbrains.kotlin.idea.util.string.joinWithEscape import org.jetbrains.kotlin.idea.util.string.joinWithEscape
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.platform.IdePlatformKind
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.has
import org.jetbrains.kotlin.platform.impl.CommonIdePlatformKind
import org.jetbrains.kotlin.platform.impl.JsIdePlatformKind
import org.jetbrains.kotlin.platform.impl.JvmIdePlatformKind
import org.jetbrains.kotlin.platform.impl.NativeIdePlatformKind
import org.jetbrains.kotlin.platform.js.JsPlatform
import org.jetbrains.kotlin.platform.jvm.JvmPlatform
import org.jetbrains.kotlin.platform.konan.NativePlatform
import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtNamedDeclaration import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.KtNamedFunction import org.jetbrains.kotlin.psi.KtNamedFunction
@@ -43,10 +53,8 @@ fun getGenericTestIcon(declaration: KtNamedDeclaration, descriptor: DeclarationD
val prefix = if (testName != null) "test://" else "suite://" val prefix = if (testName != null) "test://" else "suite://"
val url = prefix + locations.joinWithEscape('.') val url = prefix + locations.joinWithEscape('.')
val javaUrl = "java:$url"
val project = declaration.project return getTestStateIcon(listOf("java:$url", url), declaration.project, strict = false)
return getTestStateIcon(javaUrl, project, strict = true) ?: getTestStateIcon(url, project, strict = false)
} }
private tailrec fun DeclarationDescriptor.isIgnored(): Boolean { private tailrec fun DeclarationDescriptor.isIgnored(): Boolean {
@@ -69,4 +77,14 @@ fun DeclarationDescriptor.isKotlinTestDeclaration(): Boolean {
val classDescriptor = this as? ClassDescriptorWithResolutionScopes ?: return false val classDescriptor = this as? ClassDescriptorWithResolutionScopes ?: return false
return classDescriptor.declaredCallableMembers.any { it.isKotlinTestDeclaration() } return classDescriptor.declaredCallableMembers.any { it.isKotlinTestDeclaration() }
}
internal fun IdePlatformKind<*>.isCompatibleWith(platform: TargetPlatform): Boolean {
return when (this) {
is JvmIdePlatformKind -> platform.has(JvmPlatform::class)
is NativeIdePlatformKind -> platform.has(NativePlatform::class)
is JsIdePlatformKind -> platform.has(JsPlatform::class)
is CommonIdePlatformKind -> true
else -> false
}
} }
@@ -1,33 +1,40 @@
/* /*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * 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.ide.konan package org.jetbrains.kotlin.ide.konan
import com.intellij.execution.TestStateStorage
import com.intellij.execution.actions.RunConfigurationProducer import com.intellij.execution.actions.RunConfigurationProducer
import com.intellij.icons.AllIcons
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.libraries.DummyLibraryProperties import com.intellij.openapi.roots.libraries.DummyLibraryProperties
import com.intellij.openapi.roots.libraries.Library import com.intellij.openapi.roots.libraries.Library
import com.intellij.openapi.roots.libraries.PersistentLibraryKind import com.intellij.openapi.roots.libraries.PersistentLibraryKind
import com.intellij.openapi.roots.ui.configuration.libraries.CustomLibraryDescription import com.intellij.openapi.roots.ui.configuration.libraries.CustomLibraryDescription
import com.intellij.psi.util.parentOfType import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.asJava.toLightMethods
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.config.KotlinFacetSettingsProvider
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.gradle.KotlinPlatform import org.jetbrains.kotlin.gradle.KotlinPlatform
import org.jetbrains.kotlin.idea.caches.project.isTestModule import org.jetbrains.kotlin.idea.caches.project.isTestModule
import org.jetbrains.kotlin.idea.facet.externalSystemNativeMainRunTasks import org.jetbrains.kotlin.idea.facet.externalSystemNativeMainRunTasks
import org.jetbrains.kotlin.idea.framework.KotlinLibraryKind import org.jetbrains.kotlin.idea.framework.KotlinLibraryKind
import org.jetbrains.kotlin.idea.highlighter.KotlinTestRunLineMarkerContributor.Companion.getTestStateIcon
import org.jetbrains.kotlin.idea.isMainFunction import org.jetbrains.kotlin.idea.isMainFunction
import org.jetbrains.kotlin.idea.platform.IdePlatformKindTooling import org.jetbrains.kotlin.idea.platform.IdePlatformKindTooling
import org.jetbrains.kotlin.idea.platform.getGenericTestIcon import org.jetbrains.kotlin.idea.platform.isKotlinTestDeclaration
import org.jetbrains.kotlin.idea.util.module import org.jetbrains.kotlin.idea.util.module
import org.jetbrains.kotlin.platform.impl.NativeIdePlatformKind import org.jetbrains.kotlin.platform.impl.NativeIdePlatformKind
import org.jetbrains.kotlin.psi.KtFunction import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtNamedDeclaration import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.platform.TargetPlatform import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.konan.NativePlatforms import org.jetbrains.kotlin.platform.konan.NativePlatforms
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import javax.swing.Icon import javax.swing.Icon
class NativeIdePlatformKindTooling : IdePlatformKindTooling() { class NativeIdePlatformKindTooling : IdePlatformKindTooling() {
@@ -45,19 +52,28 @@ class NativeIdePlatformKindTooling : IdePlatformKindTooling() {
override fun getLibraryVersionProvider(project: Project): (Library) -> String? = { null } override fun getLibraryVersionProvider(project: Project): (Library) -> String? = { null }
override fun getTestIcon(declaration: KtNamedDeclaration, descriptor: DeclarationDescriptor): Icon? { override fun getTestIcon(declaration: KtNamedDeclaration, descriptor: DeclarationDescriptor): Icon? {
return getGenericTestIcon(declaration, descriptor) { if (!descriptor.isKotlinTestDeclaration()) return null
val availableRunConfigurations = RunConfigurationProducer
.getProducers(declaration.project)
.asSequence()
.filterIsInstance<KotlinNativeRunConfigurationProvider>()
.filter { it.isForTests }
if (availableRunConfigurations.firstOrNull() == null) { val moduleName = descriptor.module.stableName?.asString() ?: ""
return@getGenericTestIcon null val targetName = moduleName.substringAfterLast(".").removeSuffix("Test>")
val urls = when (declaration) {
is KtClassOrObject -> {
val lightClass = declaration.toLightClass() ?: return null
listOf("java:suite://${lightClass.qualifiedName}")
} }
return@getGenericTestIcon emptyList() is KtNamedFunction -> {
val lightMethod = declaration.toLightMethods().firstOrNull() ?: return null
val lightClass = lightMethod.containingClass as? KtLightClass ?: return null
val baseName = "java:test://${lightClass.qualifiedName}.${lightMethod.name}"
listOf("$baseName[${targetName}X64]", "$baseName[$targetName]", baseName)
}
else -> return null
} }
return getTestStateIcon(urls, declaration.project, strict = false)
} }
override fun acceptsAsEntryPoint(function: KtFunction): Boolean { override fun acceptsAsEntryPoint(function: KtFunction): Boolean {
@@ -34,18 +34,25 @@ import javax.swing.Icon
class KotlinTestRunLineMarkerContributor : RunLineMarkerContributor() { class KotlinTestRunLineMarkerContributor : RunLineMarkerContributor() {
companion object { companion object {
fun getTestStateIcon(url: String, project: Project, strict: Boolean): Icon? { fun getTestStateIcon(
val defaultIcon = AllIcons.RunConfigurations.TestState.Run urls: List<String>,
val state = TestStateStorage.getInstance(project).getState(url) project: Project,
?: return if (strict) null else defaultIcon strict: Boolean,
defaultIcon: Icon = AllIcons.RunConfigurations.TestState.Run
): Icon? {
for (url in urls) {
val state = TestStateStorage.getInstance(project).getState(url) ?: continue
return when (TestIconMapper.getMagnitude(state.magnitude)) { return when (TestIconMapper.getMagnitude(state.magnitude)) {
TestStateInfo.Magnitude.ERROR_INDEX, TestStateInfo.Magnitude.ERROR_INDEX,
TestStateInfo.Magnitude.FAILED_INDEX -> AllIcons.RunConfigurations.TestState.Red2 TestStateInfo.Magnitude.FAILED_INDEX -> AllIcons.RunConfigurations.TestState.Red2
TestStateInfo.Magnitude.PASSED_INDEX, TestStateInfo.Magnitude.PASSED_INDEX,
TestStateInfo.Magnitude.COMPLETE_INDEX -> AllIcons.RunConfigurations.TestState.Green2 TestStateInfo.Magnitude.COMPLETE_INDEX -> AllIcons.RunConfigurations.TestState.Green2
else -> defaultIcon else -> defaultIcon
}
} }
return if (strict) null else defaultIcon
} }
fun SimplePlatform.providesRunnableTests(): Boolean { fun SimplePlatform.providesRunnableTests(): Boolean {