mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-03-22 15:19:59 +07:00
[kotlin] Implement 'genericKotlinTestUrls' & fix GenericTestIconProvider's test location URLs
GitOrigin-RevId: 5071955afa9a40f085a0342cd02764fe049e9ff4
This commit is contained in:
committed by
intellij-monorepo-bot
parent
32050b0c36
commit
f412fe5046
@@ -388,6 +388,7 @@ org.jetbrains.kotlin.idea.*.k2.*
|
||||
org.jetbrains.kotlin.idea.*.k2
|
||||
org.jetbrains.fir.uast.test.*
|
||||
org.jetbrains.kotlin.j2k.k2.*
|
||||
org.jetbrains.kotlin.idea.testIntegration.*
|
||||
|
||||
[KOTLIN_COMPOSE_K2_TESTS]
|
||||
org.jetbrains.kotlin.idea.compose.k2.*
|
||||
|
||||
@@ -4,6 +4,7 @@ package org.jetbrains.kotlin.idea.base.codeInsight.tooling
|
||||
import org.jetbrains.kotlin.idea.base.codeInsight.KotlinTestAvailabilityChecker
|
||||
import org.jetbrains.kotlin.idea.base.codeInsight.isFrameworkAvailable
|
||||
import org.jetbrains.kotlin.idea.highlighter.KotlinTestRunLineMarkerContributor
|
||||
import org.jetbrains.kotlin.idea.testIntegration.genericKotlinTestUrls
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
@@ -24,8 +25,6 @@ abstract class AbstractGenericTestIconProvider {
|
||||
}
|
||||
|
||||
fun getGenericTestIcon(declaration: KtNamedDeclaration, initialLocations: List<String>): Icon? {
|
||||
val locations = initialLocations.toMutableList()
|
||||
|
||||
if (!isFrameworkAvailable<KotlinTestAvailabilityChecker>(declaration)) {
|
||||
return null
|
||||
}
|
||||
@@ -41,19 +40,7 @@ abstract class AbstractGenericTestIconProvider {
|
||||
return null
|
||||
}
|
||||
|
||||
locations += testContainer.parentsWithSelf.filterIsInstance<KtNamedDeclaration>()
|
||||
.mapNotNull { it.name }
|
||||
.toList().asReversed()
|
||||
|
||||
val testName = (declaration as? KtNamedFunction)?.name
|
||||
if (testName != null) {
|
||||
locations += "$testName"
|
||||
}
|
||||
|
||||
val prefix = if (testName != null) "test://" else "suite://"
|
||||
val url = prefix + locations.joinWithEscape('.')
|
||||
|
||||
return KotlinTestRunLineMarkerContributor.getTestStateIcon(listOf("java:$url", url), declaration)
|
||||
return KotlinTestRunLineMarkerContributor.getTestStateIcon(declaration.genericKotlinTestUrls(), declaration)
|
||||
}
|
||||
|
||||
private fun Collection<String>.joinWithEscape(delimiterChar: Char): String {
|
||||
|
||||
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.idea.base.platforms.KotlinNativeLibraryKind
|
||||
import org.jetbrains.kotlin.idea.base.util.module
|
||||
import org.jetbrains.kotlin.idea.highlighter.KotlinTestRunLineMarkerContributor
|
||||
import org.jetbrains.kotlin.idea.projectModel.KotlinPlatform
|
||||
import org.jetbrains.kotlin.idea.testIntegration.genericKotlinTestUrls
|
||||
import org.jetbrains.kotlin.platform.impl.NativeIdePlatformKind
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtFunction
|
||||
@@ -49,26 +50,4 @@ abstract class AbstractNativeIdePlatformKindTooling : IdePlatformKindTooling() {
|
||||
|
||||
return hasRunConfigurations
|
||||
}
|
||||
|
||||
protected fun getTestIcon(declaration: KtNamedDeclaration, moduleName: String): Icon? {
|
||||
val targetName = moduleName.substringAfterLast(".").removeSuffix("Test>")
|
||||
|
||||
val urls = when (declaration) {
|
||||
is KtClassOrObject -> {
|
||||
val lightClass = declaration.toLightClass() ?: return null
|
||||
listOf("java:suite://${lightClass.qualifiedName}")
|
||||
}
|
||||
|
||||
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 KotlinTestRunLineMarkerContributor.getTestStateIcon(urls, declaration)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.kotlin.idea.testIntegration
|
||||
|
||||
import com.intellij.execution.TestStateStorage
|
||||
import com.intellij.openapi.util.IntellijInternalApi
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
import org.jetbrains.kotlin.psi.psiUtil.containingClass
|
||||
|
||||
/**
|
||||
* Returns urls which can be used to query the [TestStateStorage].
|
||||
* This is a generic implementation; More specialized versions might exist.
|
||||
*
|
||||
* Will return
|
||||
* ```
|
||||
* package foo.bar
|
||||
*
|
||||
* class MyTest { // <- 'java:suite://foo.bar.MyTest'
|
||||
* @Test
|
||||
* fun doTest() // <- 'java:suite://foo.bar.MyTest/doTest
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
@IntellijInternalApi
|
||||
fun KtDeclaration.genericKotlinTestUrls(): List<String> {
|
||||
return when (this) {
|
||||
is KtClassOrObject -> listOf("java:suite://${this.fqName?.asString()}")
|
||||
is KtNamedFunction -> {
|
||||
val containingClass = this.containingClass()
|
||||
listOf("java:test://${containingClass?.fqName?.asString()}/${this.name}")
|
||||
}
|
||||
|
||||
else -> emptyList()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.kotlin.idea.testIntegration
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.idea.test.KotlinPluginUnitTest
|
||||
import org.jetbrains.kotlin.psi.KtClass
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.psi.psiUtil.findFunctionByName
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
|
||||
class GenericKotlinTestUrlsTest {
|
||||
|
||||
@KotlinPluginUnitTest
|
||||
fun testSimpleClass(project: Project) = ApplicationManager.getApplication().runReadAction {
|
||||
val ktClass = KtPsiFactory(project).createClass("class A")
|
||||
assertEquals(listOf("java:suite://A"), ktClass.genericKotlinTestUrls())
|
||||
}
|
||||
|
||||
@KotlinPluginUnitTest
|
||||
fun testClassInPackage(project: Project) = ApplicationManager.getApplication().runReadAction {
|
||||
val ktClass = KtPsiFactory(project).createClass("package a.b.c; class A")
|
||||
assertEquals(listOf("java:suite://a.b.c.A"), ktClass.genericKotlinTestUrls())
|
||||
}
|
||||
|
||||
@KotlinPluginUnitTest
|
||||
fun testNestedClass(project: Project) = ApplicationManager.getApplication().runReadAction {
|
||||
val ktClass = KtPsiFactory(project).createClass("class A { class B }")
|
||||
val bKtClass = ktClass.declarations.find { it.name == "B" } as? KtClass ?: error("Cannot find B")
|
||||
assertEquals(listOf("java:suite://A.B"), bKtClass.genericKotlinTestUrls())
|
||||
}
|
||||
|
||||
@KotlinPluginUnitTest
|
||||
fun testFun(project: Project) = ApplicationManager.getApplication().runReadAction {
|
||||
val ktClass = KtPsiFactory(project).createClass(
|
||||
"""
|
||||
package a.b.c
|
||||
class Foo {
|
||||
fun foo()
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
val foo = ktClass.findFunctionByName("foo") ?: error("Cannot find foo()")
|
||||
assertEquals(listOf("java:test://a.b.c.Foo/foo"), foo.genericKotlinTestUrls())
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,8 @@ import org.jetbrains.kotlin.idea.base.codeInsight.tooling.AbstractGenericTestIco
|
||||
import org.jetbrains.kotlin.idea.base.codeInsight.tooling.AbstractNativeIdePlatformKindTooling
|
||||
import org.jetbrains.kotlin.idea.base.projectStructure.languageVersionSettings
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||
import org.jetbrains.kotlin.idea.highlighter.KotlinTestRunLineMarkerContributor
|
||||
import org.jetbrains.kotlin.idea.testIntegration.genericKotlinTestUrls
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtFunction
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
@@ -36,8 +38,7 @@ class Fe10NativeIdePlatformKindTooling : AbstractNativeIdePlatformKindTooling()
|
||||
val descriptor = declaration.resolveToDescriptorIfAny() ?: return null
|
||||
if (!Fe10GenericTestIconProvider.isKotlinTestDeclaration(descriptor)) return null
|
||||
|
||||
val moduleName = descriptor.module.stableName?.asString() ?: ""
|
||||
return getTestIcon(declaration, moduleName)
|
||||
return KotlinTestRunLineMarkerContributor.getTestStateIcon(declaration.genericKotlinTestUrls(), declaration)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import org.jetbrains.kotlin.idea.base.codeInsight.tooling.AbstractNativeIdePlatf
|
||||
import org.jetbrains.kotlin.idea.base.facet.implementingModules
|
||||
import org.jetbrains.kotlin.idea.base.util.module
|
||||
import org.jetbrains.kotlin.idea.highlighter.KotlinTestRunLineMarkerContributor
|
||||
import org.jetbrains.kotlin.idea.testIntegration.genericKotlinTestUrls
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtFunction
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
@@ -35,16 +36,6 @@ internal class FirNativeIdePlatformKindTooling : AbstractNativeIdePlatformKindTo
|
||||
return null
|
||||
}
|
||||
|
||||
val urls = when (declaration) {
|
||||
is KtClassOrObject -> listOf("java:suite://${declaration.fqName?.asString()}")
|
||||
is KtNamedFunction -> {
|
||||
val containingClass = declaration.containingClass()
|
||||
listOf("java:test://${containingClass?.fqName?.asString()}/${declaration.name}")
|
||||
}
|
||||
|
||||
else -> return null
|
||||
}
|
||||
|
||||
return KotlinTestRunLineMarkerContributor.getTestStateIcon(urls, declaration)
|
||||
return KotlinTestRunLineMarkerContributor.getTestStateIcon(declaration.genericKotlinTestUrls(), declaration)
|
||||
}
|
||||
}
|
||||
@@ -1,27 +1,22 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.kotlin.gradle.idea.importing.multiplatformTests
|
||||
|
||||
import com.intellij.codeInsight.daemon.LineMarkerInfo
|
||||
import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl
|
||||
import com.intellij.execution.lineMarker.RunLineMarkerContributor
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.intellij.lang.annotation.HighlightSeverity
|
||||
import com.intellij.openapi.vfs.findFile
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.testFramework.runInEdtAndWait
|
||||
import com.intellij.testIntegration.TestRunLineMarkerProvider
|
||||
import com.intellij.util.containers.ContainerUtil.filterIsInstance
|
||||
import org.jetbrains.kotlin.gradle.multiplatformTests.AbstractKotlinMppGradleImportingTest
|
||||
import org.jetbrains.kotlin.gradle.multiplatformTests.TestConfigurationDslScope
|
||||
import org.jetbrains.kotlin.gradle.multiplatformTests.testFeatures.CustomChecksDsl
|
||||
import org.jetbrains.kotlin.gradle.multiplatformTests.testFeatures.CustomGradleProperties
|
||||
import org.jetbrains.kotlin.gradle.multiplatformTests.testFeatures.CustomGradlePropertiesTestFeature
|
||||
import org.jetbrains.kotlin.gradle.multiplatformTests.testFeatures.checkers.highlighting.HighlightingChecker
|
||||
import org.jetbrains.kotlin.gradle.multiplatformTests.testFeatures.checkers.hooks.TestHooks
|
||||
import org.jetbrains.kotlin.gradle.multiplatformTests.testFeatures.checkers.runConfigurations.ExecuteRunConfigurationsChecker
|
||||
import org.jetbrains.kotlin.gradle.multiplatformTests.testFeatures.checkers.runConfigurations.RunConfigurationsChecker
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginMode
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
|
||||
import org.jetbrains.kotlin.test.TestMetadata
|
||||
import org.jetbrains.kotlin.tooling.core.compareTo
|
||||
import org.jetbrains.plugins.gradle.tooling.annotation.PluginTargetVersions
|
||||
@@ -66,6 +61,7 @@ class KotlinMppRunConfigurationsTest : AbstractKotlinMppGradleImportingTest(), C
|
||||
setRegistryPropertyForTest("gradle.testLauncherAPI.enabled", "false")
|
||||
|
||||
doTest {
|
||||
onlyModules("project.*")
|
||||
executeRunConfiguration("CommonTest.test in commonTest - success")
|
||||
executeRunConfiguration("CommonTest.test in commonTest - failure")
|
||||
executeRunConfiguration("IosTest.test in iosTest - success")
|
||||
@@ -117,4 +113,48 @@ class KotlinMppRunConfigurationsTest : AbstractKotlinMppGradleImportingTest(), C
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@PluginTargetVersions(pluginVersion = "2.0.20-dev-0+")
|
||||
@Test
|
||||
fun testCommonTest() {
|
||||
doTest {
|
||||
onlyModules(".*commonTest")
|
||||
executeRunConfiguration("foo.bar.CommonTest")
|
||||
/**
|
||||
* Let's test the line-markers after the test executed
|
||||
*
|
||||
* ```kotlin
|
||||
* class CommonTest { // <- RED!
|
||||
* @Test
|
||||
* fun failure() // <- RED!
|
||||
*
|
||||
* @Test
|
||||
* fun success() // <- GREEN!
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
runAfterTestExecution {
|
||||
val nativeTestFile = projectRoot.findFile("src/commonTest/kotlin/CommonTest.kt") ?: error("Missing 'CommonTest.kt'")
|
||||
runInEdtAndWait {
|
||||
codeInsightTestFixture.openFileInEditor(nativeTestFile)
|
||||
codeInsightTestFixture.doHighlighting()
|
||||
val psi = PsiManager.getInstance(myProject).findFile(nativeTestFile) ?: error("Missing 'CommonTest.kt' PsiFile")
|
||||
val document = PsiDocumentManager.getInstance(myProject).getDocument(psi) ?: error("Missing 'CommonTest.kt' Document")
|
||||
val lineMarkers = DaemonCodeAnalyzerImpl.getLineMarkers(document, project)
|
||||
|
||||
fun assertStateAtText(text: String, icon: Icon) {
|
||||
val lineMarker = lineMarkers.find { marker -> marker.element?.text == text }
|
||||
?: error("Missing line marker for '$text'")
|
||||
|
||||
kotlin.test.assertEquals(icon, lineMarker.icon, "Wrong line-marker at '$text'")
|
||||
}
|
||||
|
||||
assertStateAtText("CommonTest", AllIcons.RunConfigurations.TestState.Red2)
|
||||
assertStateAtText("success", AllIcons.RunConfigurations.TestState.Green2)
|
||||
assertStateAtText("failure", AllIcons.RunConfigurations.TestState.Red2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
plugins {
|
||||
kotlin("multiplatform")
|
||||
}
|
||||
|
||||
repositories {
|
||||
{ { kts_kotlin_plugin_repositories } }
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvm()
|
||||
macosX64()
|
||||
macosArm64()
|
||||
linuxX64()
|
||||
linuxArm64()
|
||||
|
||||
sourceSets.commonTest.dependencies {
|
||||
implementation(kotlin("test"))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
MODULES
|
||||
project.commonTest
|
||||
fqName: foo.bar.CommonTest
|
||||
name: CommonTest
|
||||
type: Gradle
|
||||
tasks: [:cleanJvmTest, :jvmTest, --tests, "foo.bar.CommonTest"]
|
||||
scriptParameters:
|
||||
isDebugAllEnabled: false
|
||||
isRunAsTest: true
|
||||
|
||||
fqName: foo.bar.CommonTest.failure
|
||||
name: CommonTest.failure
|
||||
type: Gradle
|
||||
tasks: [:cleanJvmTest, :jvmTest, --tests, "foo.bar.CommonTest.failure"]
|
||||
scriptParameters:
|
||||
isDebugAllEnabled: false
|
||||
isRunAsTest: true
|
||||
|
||||
fqName: foo.bar.CommonTest.success
|
||||
name: CommonTest.success
|
||||
type: Gradle
|
||||
tasks: [:cleanJvmTest, :jvmTest, --tests, "foo.bar.CommonTest.success"]
|
||||
scriptParameters:
|
||||
isDebugAllEnabled: false
|
||||
isRunAsTest: true
|
||||
|
||||
|
||||
|
||||
Test configuration:
|
||||
- showing only modules matching .*commonTest
|
||||
- Showing runConfiguration detail: name
|
||||
- Showing runConfiguration detail: type
|
||||
- Showing runConfiguration detail: tasks
|
||||
- Showing runConfiguration detail: scriptParameters
|
||||
- Showing runConfiguration detail: isDebugAllEnabled
|
||||
- Showing runConfiguration detail: isRunAsTest
|
||||
@@ -0,0 +1,8 @@
|
||||
09:47:03: Executing ':cleanJvmTest :jvmTest --tests "foo.bar.CommonTest"'…
|
||||
09:47:06: Execution finished ':cleanJvmTest :jvmTest --tests "foo.bar.CommonTest"'.
|
||||
|
||||
|
||||
com.intellij.openapi.externalSystem.model.ExternalSystemException: There were failing tests. See the report at: file:///private/var/folders/1j/4f6kfm9d3fq98slcxvk2dr7c0000gn/T/unitTest_commonTest_2mbEIjqWRHVprTFR6f21p0INRfd/tmp/testDir1727336800275/project/build/reports/tests/jvmTest/index.html
|
||||
org.gradle.api.internal.exceptions.MarkedVerificationException: There were failing tests. See the report at: file:///private/var/folders/1j/4f6kfm9d3fq98slcxvk2dr7c0000gn/T/unitTest_commonTest_2mbEIjqWRHVprTFR6f21p0INRfd/tmp/testDir1727336800275/project/build/reports/tests/jvmTest/index.html
|
||||
|
||||
<exitCode: 1>
|
||||
@@ -0,0 +1,10 @@
|
||||
pluginManagement {
|
||||
repositories {
|
||||
{{kts_kotlin_plugin_repositories}}
|
||||
}
|
||||
|
||||
plugins {
|
||||
kotlin("multiplatform") version "{{kgp_version}}"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package foo.bar
|
||||
|
||||
class CommonTest {
|
||||
@kotlin.test.Test
|
||||
fun success() {
|
||||
|
||||
}
|
||||
|
||||
@kotlin.test.Test
|
||||
fun failure() {
|
||||
kotlin.test.assertEquals(1, 2)
|
||||
}
|
||||
}
|
||||
@@ -107,6 +107,7 @@ project.nativeTest
|
||||
|
||||
|
||||
Test configuration:
|
||||
- showing only modules matching project.*
|
||||
- Showing runConfiguration detail: name
|
||||
- Showing runConfiguration detail: type
|
||||
- Showing runConfiguration detail: tasks
|
||||
|
||||
Reference in New Issue
Block a user