diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/BuildKotlinToolingMetadataTest.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/BuildKotlinToolingMetadataTest.kt index 228a08d6020..6751ce04530 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/BuildKotlinToolingMetadataTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/BuildKotlinToolingMetadataTest.kt @@ -25,33 +25,21 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMetadataTarget import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTargetWithHostTests -import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.* import org.jetbrains.kotlin.gradle.targets.js.KotlinJsTarget import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget import org.jetbrains.kotlin.gradle.tooling.BuildKotlinToolingMetadataTask -import org.jetbrains.kotlin.gradle.tooling.buildKotlinToolingMetadataForMainKpmModuleTask import org.jetbrains.kotlin.gradle.tooling.buildKotlinToolingMetadataTask import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.library.KotlinAbiVersion import org.jetbrains.kotlin.tooling.KotlinToolingMetadata import org.jetbrains.kotlin.tooling.toJsonString -import org.junit.Assume -import org.junit.AssumptionViolatedException -import org.junit.Before -import org.junit.runner.RunWith -import org.junit.runners.Parameterized import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFalse import kotlin.test.assertTrue -@RunWith(Parameterized::class) class BuildKotlinToolingMetadataTest { - @Parameterized.Parameter(0) - @JvmField - val kpmModelMappingEnabled: Boolean = false - private val project = ProjectBuilder.builder().build().also{ addBuildEventsListenerRegistryMock(it) } as ProjectInternal private val multiplatformExtension get() = project.extensions.getByType(KotlinMultiplatformExtension::class.java) private val jsExtension get() = project.extensions.getByType(KotlinJsProjectExtension::class.java) @@ -60,11 +48,6 @@ class BuildKotlinToolingMetadataTest { project.extensions.getByType(ExtraPropertiesExtension::class.java).set("kotlin.mpp.enableKotlinToolingMetadataArtifact", "true") } - @Before - fun setup() { - project.enableKpmModelMapping(kpmModelMappingEnabled) - } - @Test fun `multiplatform empty setup`() { project.plugins.apply("kotlin-multiplatform") @@ -75,18 +58,12 @@ class BuildKotlinToolingMetadataTest { assertEquals(project.gradle.gradleVersion, metadata.buildSystemVersion) assertEquals(KotlinMultiplatformPluginWrapper::class.java.canonicalName, metadata.buildPlugin) assertEquals(project.getKotlinPluginVersion(), metadata.buildPluginVersion) - if (kpmModelMappingEnabled) { - assertEquals(0, metadata.projectTargets.size, "Expected no targets in KPM") - } else { - assertEquals(1, metadata.projectTargets.size, "Expected one target (metadata)") - val targetMetadata = metadata.projectTargets.single() - val targetClass = KotlinMetadataTarget::class - assertTrue( - targetClass.java.isAssignableFrom(Class.forName(targetMetadata.target)), - "Expect target to implement ${targetClass.simpleName}" - ) - assertEquals(common.name, targetMetadata.platformType) - } + assertEquals(1, metadata.projectTargets.size, "Expected one target (metadata)") + assertTrue( + KotlinMetadataTarget::class.java.isAssignableFrom(Class.forName(metadata.projectTargets.single().target)), + "Expect target to be implement ${KotlinMetadataTarget::class.simpleName}" + ) + assertEquals(common.name, metadata.projectTargets.single().platformType) assertTrue(metadata.toJsonString().isNotBlank(), "Expected non blank json representation") } @@ -112,28 +89,13 @@ class BuildKotlinToolingMetadataTest { val metadata = getKotlinToolingMetadata() assertEquals(KotlinMultiplatformPluginWrapper::class.java.canonicalName, metadata.buildPlugin) - if (kpmModelMappingEnabled) { - assertFalse("Kotlin Tooling Metadata generated from KPM should not contain target of 'common' platform") { - metadata.projectTargets.any { it.platformType == common.name } - } - } - - val expectedTargets = if (kpmModelMappingEnabled) { - mapOf( - androidJvm to LegacyMappedVariantWithRuntime::class, - jvm to KotlinJvmVariant::class, - js to LegacyMappedVariantWithRuntime::class, - native to KotlinLinuxX64Variant::class - ) - } else { - mapOf( - common to KotlinMetadataTarget::class, - androidJvm to KotlinAndroidTarget::class, - jvm to KotlinJvmTarget::class, - js to KotlinJsTarget::class, - native to KotlinNativeTargetWithHostTests::class - ) - } + val expectedTargets = mapOf( + common to KotlinMetadataTarget::class, + androidJvm to KotlinAndroidTarget::class, + jvm to KotlinJvmTarget::class, + js to KotlinJsTarget::class, + native to KotlinNativeTargetWithHostTests::class + ) assertEquals( expectedTargets.keys.map { it.name }.sorted(), @@ -148,7 +110,7 @@ class BuildKotlinToolingMetadataTest { ) } - assertEquals(kpmModelMappingEnabled, metadata.projectSettings.isKPMEnabled, "projectSettings.isKPMEnabled must be set") + assertFalse(metadata.projectSettings.isKPMEnabled, "projectSettings.isKPMEnabled must not be set") } @Test @@ -200,7 +162,6 @@ class BuildKotlinToolingMetadataTest { @Test fun js() { - Assume.assumeFalse("KPM model mapping is not yet supported in single-platform projects", kpmModelMappingEnabled) project.plugins.apply("org.jetbrains.kotlin.js") val kotlin = jsExtension kotlin.js { nodejs() } @@ -215,7 +176,6 @@ class BuildKotlinToolingMetadataTest { @Test fun jvm() { - Assume.assumeFalse("KPM model mapping is not yet supported in single-platform projects", kpmModelMappingEnabled) project.plugins.apply("org.jetbrains.kotlin.jvm") val metadata = getKotlinToolingMetadata() assertEquals(org.jetbrains.kotlin.gradle.plugin.KotlinPluginWrapper::class.java.canonicalName, metadata.buildPlugin) @@ -242,45 +202,12 @@ class BuildKotlinToolingMetadataTest { linuxX64.extras.native?.konanTarget ) - if (kpmModelMappingEnabled) { - assertEquals( - KotlinLinuxArm64Variant::class.java.canonicalName, - linuxArm64.target - ) - assertEquals( - KotlinLinuxX64Variant::class.java.canonicalName, - linuxX64.target - ) - } else { - assertEquals( - KotlinNativeTarget::class.java.canonicalName, - linuxArm64.target - ) - assertEquals( - KotlinNativeTargetWithHostTests::class.java.canonicalName, - linuxX64.target - ) - } + assertEquals(KotlinNativeTarget::class.java.canonicalName, linuxArm64.target) + assertEquals(KotlinNativeTargetWithHostTests::class.java.canonicalName, linuxX64.target) } private fun getKotlinToolingMetadata(): KotlinToolingMetadata { - if (!kpmModelMappingEnabled) { - val task = project.buildKotlinToolingMetadataTask?.get() ?: error("No ${BuildKotlinToolingMetadataTask.defaultTaskName} task") - return task.kotlinToolingMetadata - } else { - val task = project.buildKotlinToolingMetadataForMainKpmModuleTask - ?.get() - ?: error("No ${BuildKotlinToolingMetadataTask.defaultTaskName} for Main module task") - return task.kotlinToolingMetadata - } - } - - companion object { - @JvmStatic - @Parameterized.Parameters(name = "KPM-Model-Mapping:{0}") - fun parameters() = listOf( - arrayOf(false), - arrayOf(true), - ) + val task = project.buildKotlinToolingMetadataTask?.get() ?: error("No ${BuildKotlinToolingMetadataTask.defaultTaskName} task") + return task.kotlinToolingMetadata } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/kpm/BuildKotlinToolingMetadataTest.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/kpm/BuildKotlinToolingMetadataTest.kt new file mode 100644 index 00000000000..bbf13dbbdd8 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/kpm/BuildKotlinToolingMetadataTest.kt @@ -0,0 +1,217 @@ +/* + * Copyright 2010-2021 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. + */ + +package org.jetbrains.kotlin.gradle.kpm + +import com.android.build.gradle.BaseExtension +import org.gradle.api.JavaVersion +import org.gradle.api.Project +import org.gradle.api.internal.project.ProjectInternal +import org.gradle.testfixtures.ProjectBuilder +import org.jetbrains.kotlin.compilerRunner.konanVersion +import org.jetbrains.kotlin.gradle.addBuildEventsListenerRegistryMock +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension +import org.jetbrains.kotlin.gradle.enableKpmModelMapping +import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType.* +import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.* +import org.jetbrains.kotlin.gradle.tooling.buildKotlinToolingMetadataTask +import org.jetbrains.kotlin.konan.target.KonanTarget +import org.jetbrains.kotlin.library.KotlinAbiVersion +import org.jetbrains.kotlin.tooling.KotlinToolingMetadata +import org.jetbrains.kotlin.tooling.toJsonString +import org.gradle.kotlin.dsl.create +import org.jetbrains.kotlin.gradle.plugin.* +import kotlin.test.* + +private fun Project.kotlinToolingMetadataOfModule(moduleName: String = KotlinGradleModule.MAIN_MODULE_NAME): KotlinToolingMetadata { + val module = kpmModules.getByName(moduleName) + return module.buildKotlinToolingMetadataTask!!.get().kotlinToolingMetadata +} + +class BuildKotlinToolingMetadataTest : AbstractKpmExtensionTest() { + @Test + fun `multiple targets`() { + // Given + with(kotlin) { + mainAndTest { + jvm + val linux = fragments.create("linux") + fragments.create("linuxX64").apply { refines(linux) } + fragments.create("linuxArm64").apply { refines(linux) } + // No JS & Android variants available at the moment, only through [LegacyMappedVariant] which is tested below + } + } + + // When + val metadata = project.kotlinToolingMetadataOfModule() + + // Then + assertEquals("Gradle", metadata.buildSystem) + assertEquals(project.gradle.gradleVersion, metadata.buildSystemVersion) + assertEquals(KotlinPm20PluginWrapper::class.java.canonicalName, metadata.buildPlugin) + assertEquals(project.getKotlinPluginVersion(), metadata.buildPluginVersion) + assertEquals(3, metadata.projectTargets.size, "Expected 3 targets in KPM") + + val jvmTarget = metadata.projectTargets.single { it.platformType == jvm.name } + assertEquals(KotlinJvmVariant::class.java.canonicalName, jvmTarget.target) + + val nativeTargets = metadata.projectTargets.filter { it.platformType == native.name }.sortedBy { it.platformType } + assertEquals(KotlinLinuxArm64Variant::class.java.canonicalName, nativeTargets[0].target) + assertEquals(KotlinLinuxX64Variant::class.java.canonicalName, nativeTargets[1].target) + } +} + +class KotlinToolingMetadataWithModelMappingTest { + private val project = ProjectBuilder.builder().build().also { addBuildEventsListenerRegistryMock(it) } as ProjectInternal + private val multiplatformExtension get() = project.extensions.getByType(KotlinMultiplatformExtension::class.java) + private fun getKotlinToolingMetadata() = project.kotlinToolingMetadataOfModule() + + @BeforeTest + fun setup() { + project.enableKpmModelMapping() + } + + @Test + fun `multiplatform empty setup`() { + project.plugins.apply("kotlin-multiplatform") + + val metadata = getKotlinToolingMetadata() + + assertEquals("Gradle", metadata.buildSystem) + assertEquals(project.gradle.gradleVersion, metadata.buildSystemVersion) + assertEquals(KotlinMultiplatformPluginWrapper::class.java.canonicalName, metadata.buildPlugin) + assertEquals(project.getKotlinPluginVersion(), metadata.buildPluginVersion) + assertEquals(0, metadata.projectTargets.size, "Expected no targets in KPM") + assertTrue(metadata.toJsonString().isNotBlank(), "Expected non blank json representation") + } + + @Test + fun `multiplatform JS JVM Android linuxX64 setup`() { + project.plugins.apply("com.android.application") + project.plugins.apply("kotlin-multiplatform") + + val android = project.extensions.getByType(BaseExtension::class.java) + val kotlin = multiplatformExtension + + android.compileSdkVersion(28) + kotlin.android() + kotlin.jvm() + kotlin.js { + nodejs() + browser() + } + kotlin.linuxX64() + + project.evaluate() + + val metadata = getKotlinToolingMetadata() + assertEquals(KotlinMultiplatformPluginWrapper::class.java.canonicalName, metadata.buildPlugin) + + assertFalse("Kotlin Tooling Metadata generated from KPM should not contain target of 'common' platform") { + metadata.projectTargets.any { it.platformType == common.name } + } + + val expectedTargets = mapOf( + androidJvm to LegacyMappedVariantWithRuntime::class, + jvm to KotlinJvmVariant::class, + js to LegacyMappedVariantWithRuntime::class, + native to KotlinLinuxX64Variant::class + ) + + assertEquals( + expectedTargets.keys.map { it.name }.sorted(), + metadata.projectTargets.map { it.platformType }.sorted() + ) + + expectedTargets.forEach { (platformType, targetClass) -> + assertEquals( + targetClass.java.canonicalName, + metadata.projectTargets.single { it.platformType == platformType.name }.target, + "Platform '$platformType' has different target class" + ) + } + + assertTrue(metadata.projectSettings.isKPMEnabled, "projectSettings.isKPMEnabled must be set") + } + + @Test + fun `multiplatform Android target with different source and target compatibility`() { + project.plugins.apply("kotlin-multiplatform") + project.plugins.apply("com.android.application") + val android = project.extensions.getByType(BaseExtension::class.java) + val kotlin = multiplatformExtension + android.compileSdkVersion(28) + kotlin.android() + android.compileOptions.sourceCompatibility = JavaVersion.VERSION_1_6 + android.compileOptions.targetCompatibility = JavaVersion.VERSION_1_8 + project.evaluate() + + val androidTargetMetadata = getKotlinToolingMetadata() + .projectTargets.single { it.platformType == androidJvm.name } + + assertEquals("1.6", androidTargetMetadata.extras.android?.sourceCompatibility) + assertEquals("1.8", androidTargetMetadata.extras.android?.targetCompatibility) + } + + @Test + fun `multiplatform JVM with different targets`() { + project.plugins.apply("kotlin-multiplatform") + val kotlin = multiplatformExtension + val jvm = kotlin.jvm() + jvm.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME).kotlinOptions.jvmTarget = "12" + jvm.compilations.getByName(KotlinCompilation.TEST_COMPILATION_NAME).kotlinOptions.jvmTarget = "10" + + assertEquals( + "12", getKotlinToolingMetadata().projectTargets + .single { it.platformType == KotlinPlatformType.jvm.name }.extras.jvm?.jvmTarget, + "Expected jvmTarget of main compilation" + ) + } + + @Test + fun `multiplatform with native target`() { + project.plugins.apply("kotlin-multiplatform") + val kotlin = multiplatformExtension + kotlin.linuxX64() + + val metadata = getKotlinToolingMetadata() + val linuxTarget = metadata.projectTargets.single { it.platformType == native.name } + assertEquals(KonanTarget.LINUX_X64.name, linuxTarget.extras.native?.konanTarget) + assertEquals(project.konanVersion.toString(), linuxTarget.extras.native?.konanVersion) + assertEquals(KotlinAbiVersion.CURRENT.toString(), linuxTarget.extras.native?.konanAbiVersion) + } + + @Test + fun `multiple native targets`() { + project.plugins.apply("kotlin-multiplatform") + val kotlin = multiplatformExtension + kotlin.linuxX64() + kotlin.linuxArm64() + + val metadata = getKotlinToolingMetadata() + val nativeTargets = metadata.projectTargets.filter { it.platformType == native.name }.sortedBy { it.extras.native?.konanTarget } + assertEquals(2, nativeTargets.size, "Expected only two native targets") + val (linuxArm64, linuxX64) = nativeTargets + + assertEquals( + "linux_arm64", + linuxArm64.extras.native?.konanTarget + ) + assertEquals( + "linux_x64", + linuxX64.extras.native?.konanTarget + ) + + assertEquals( + KotlinLinuxArm64Variant::class.java.canonicalName, + linuxArm64.target + ) + assertEquals( + KotlinLinuxX64Variant::class.java.canonicalName, + linuxX64.target + ) + } + +} \ No newline at end of file