[Gradle] Migrate KlibBasedMppIT to new test DSL
^KT-65528 In Progress
This commit is contained in:
committed by
Space Team
parent
74c02a77fe
commit
55bbaec3f9
+3
-2
@@ -19,9 +19,10 @@ class K2HierarchicalMppIT : HierarchicalMppIT() {
|
||||
override val defaultBuildOptions: BuildOptions get() = super.defaultBuildOptions.copy(languageVersion = "2.0")
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@MppGradlePluginTests
|
||||
@DisplayName("KLibs in K2")
|
||||
class K2KlibBasedMppIT : KlibBasedMppIT() {
|
||||
override fun defaultBuildOptions(): BuildOptions = super.defaultBuildOptions().copy(languageVersion = "2.0")
|
||||
override val defaultBuildOptions: BuildOptions = super.defaultBuildOptions.copyEnsuringK2()
|
||||
}
|
||||
|
||||
@Ignore
|
||||
|
||||
+416
-287
@@ -5,240 +5,401 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle
|
||||
|
||||
import org.jetbrains.kotlin.gradle.util.modify
|
||||
import org.gradle.testkit.runner.BuildResult
|
||||
import org.gradle.util.GradleVersion
|
||||
import org.jetbrains.kotlin.gradle.testbase.*
|
||||
import org.jetbrains.kotlin.gradle.util.replaceText
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
import org.junit.Assume
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.condition.OS
|
||||
import org.junit.jupiter.api.io.TempDir
|
||||
import java.io.File
|
||||
import java.nio.file.Path
|
||||
import java.util.*
|
||||
import java.util.zip.ZipFile
|
||||
import kotlin.test.Test
|
||||
import kotlin.io.path.appendText
|
||||
import kotlin.io.path.deleteRecursively
|
||||
import kotlin.io.path.isDirectory
|
||||
import kotlin.io.path.writeText
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
open class KlibBasedMppIT : BaseGradleIT() {
|
||||
override val defaultGradleVersion: GradleVersionRequired = GradleVersionRequired.FOR_MPP_SUPPORT
|
||||
|
||||
companion object {
|
||||
private const val MODULE_GROUP = "com.example"
|
||||
}
|
||||
@DisplayName("KLibs in K1")
|
||||
@MppGradlePluginTests
|
||||
open class KlibBasedMppIT : KGPBaseTest() {
|
||||
|
||||
@Test
|
||||
fun testBuildWithProjectDependency() = testBuildWithDependency {
|
||||
gradleBuildScript().appendText(
|
||||
"\n" + """
|
||||
dependencies {
|
||||
commonMainImplementation(project("$dependencyModuleName"))
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
override val defaultBuildOptions: BuildOptions = super.defaultBuildOptions.copyEnsuringK1()
|
||||
|
||||
@Test
|
||||
fun testPublishingAndConsumptionWithEmptySourceSet() = testBuildWithDependency {
|
||||
// KT-36674
|
||||
projectDir.resolve("$dependencyModuleName/src/windowsMain").run {
|
||||
assertTrue { isDirectory }
|
||||
deleteRecursively()
|
||||
}
|
||||
publishProjectDepAndAddDependency(validateHostSpecificPublication = false)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCommonSourceSetsInTransitiveDependencies() = with(Project("common-klib-lib-and-app")) {
|
||||
// On macOS KT-41083 is also validated by publishing a lib with host specific source sets depending on another lib with host-specific source sets
|
||||
setupWorkingDir()
|
||||
val projectDepName = "dependency"
|
||||
val publishedGroup = "published"
|
||||
val producerProjectName = "producer"
|
||||
embedProject(this, renameTo = projectDepName)
|
||||
projectDir.resolve("$projectDepName/src").walkTopDown().filter { it.extension == "kt" }.forEach { ktFile ->
|
||||
// Avoid FQN duplicates between producer & consumer
|
||||
ktFile.modify { it.replace("package com.h0tk3y.hmpp.klib.demo", "package com.h0tk3y.hmpp.klib.lib") }
|
||||
}
|
||||
|
||||
gradleBuildScript(projectDepName).appendText(
|
||||
"""
|
||||
${"\n"}
|
||||
group = "$publishedGroup"
|
||||
""".trimIndent()
|
||||
)
|
||||
gradleBuildScript().modify {
|
||||
transformBuildScriptWithPluginsDsl(it) +
|
||||
"""
|
||||
${"\n"}
|
||||
dependencies { "commonMainImplementation"(project(":$projectDepName")) }
|
||||
group = "$publishedGroup"
|
||||
""".trimIndent()
|
||||
}
|
||||
gradleSettingsScript().appendText("\nrootProject.name = \"$producerProjectName\"")
|
||||
|
||||
build("publish") {
|
||||
assertSuccessful()
|
||||
}
|
||||
|
||||
// Then consume the published project. To do that, rename the modules so that Gradle chooses the published ones given the original
|
||||
// Maven coordinates and doesn't resolve them as project dependencies.
|
||||
|
||||
val localGroup = "local"
|
||||
gradleBuildScript(projectDepName).appendText("""${"\n"}group = "$localGroup"""")
|
||||
gradleBuildScript().appendText(
|
||||
"""
|
||||
${"\n"}
|
||||
repositories { maven("${'$'}rootDir/repo") }
|
||||
dependencies { "commonMainImplementation"("$publishedGroup:$producerProjectName:1.0") }
|
||||
group = "$localGroup"
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
val commonModules = listOf(
|
||||
"published-producer-1.0-commonMain-[\\w-]+.klib",
|
||||
"published-dependency-1.0-commonMain-[\\w-]+.klib",
|
||||
).map(::Regex)
|
||||
|
||||
val hostSpecificModules = listOf(
|
||||
"published-producer-1.0-iosMain-[\\w-]+.klib",
|
||||
"published-dependency-1.0-iosMain-[\\w-]+.klib",
|
||||
).map(::Regex)
|
||||
|
||||
val windowsAndLinuxModules = listOf(
|
||||
"published-producer-1.0-windowsAndLinuxMain-[\\w-]+.klib",
|
||||
"published-dependency-1.0-windowsAndLinuxMain-[\\w-]+.klib",
|
||||
).map(::Regex)
|
||||
|
||||
checkTaskCompileClasspath(
|
||||
"compileWindowsAndLinuxMainKotlinMetadata",
|
||||
checkModulesInClasspath = commonModules + windowsAndLinuxModules,
|
||||
checkModulesNotInClasspath = hostSpecificModules
|
||||
)
|
||||
|
||||
// The consumer should correctly receive the klibs of the host-specific source sets
|
||||
|
||||
if (HostManager.hostIsMac) {
|
||||
checkTaskCompileClasspath(
|
||||
"compileIosMainKotlinMetadata",
|
||||
checkModulesInClasspath = commonModules + hostSpecificModules,
|
||||
checkModulesNotInClasspath = windowsAndLinuxModules
|
||||
@DisplayName("Could be compiled with project dependency")
|
||||
@GradleTest
|
||||
fun testBuildWithProjectDependency(
|
||||
gradleVersion: GradleVersion,
|
||||
@TempDir localRepo: Path,
|
||||
) {
|
||||
testBuildWithDependency(gradleVersion, localRepo) {
|
||||
buildGradleKts.appendText(
|
||||
"""
|
||||
|
|
||||
|dependencies {
|
||||
| commonMainImplementation(project("$dependencyModuleName"))
|
||||
|}
|
||||
""".trimMargin()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testHostSpecificBuildWithPublishedDependency() = testBuildWithDependency {
|
||||
// Host-specific dependencies are only possible on macOS
|
||||
Assume.assumeTrue(HostManager.hostIsMac)
|
||||
publishProjectDepAndAddDependency(validateHostSpecificPublication = true)
|
||||
@DisplayName("KT-36674: Could be compiled with empty source set")
|
||||
@GradleTest
|
||||
fun testPublishingAndConsumptionWithEmptySourceSet(
|
||||
gradleVersion: GradleVersion,
|
||||
@TempDir localRepo: Path,
|
||||
) {
|
||||
testBuildWithDependency(gradleVersion, localRepo) {
|
||||
subProject(dependencyModuleName)
|
||||
.kotlinSourcesDir("windowsMain")
|
||||
.parent
|
||||
.run {
|
||||
assertTrue(isDirectory())
|
||||
deleteRecursively()
|
||||
}
|
||||
publishProjectDepAndAddDependency(validateHostSpecificPublication = false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Project.publishProjectDepAndAddDependency(validateHostSpecificPublication: Boolean) {
|
||||
@DisplayName("Compiles with common sources in transitive dependencies")
|
||||
@GradleTest
|
||||
fun testCommonSourceSetsInTransitiveDependencies(
|
||||
gradleVersion: GradleVersion,
|
||||
@TempDir localRepo: Path,
|
||||
) {
|
||||
project(
|
||||
"common-klib-lib-and-app",
|
||||
gradleVersion,
|
||||
localRepoDir = localRepo
|
||||
) {
|
||||
// On macOS KT-41083 is also validated by publishing a lib with host specific source sets depending on another lib with host-specific source sets
|
||||
val projectDepName = "dependency"
|
||||
val publishedGroup = "published"
|
||||
val producerProjectName = "producer"
|
||||
includeOtherProjectAsSubmodule(
|
||||
otherProjectName = "common-klib-lib-and-app",
|
||||
newSubmoduleName = projectDepName,
|
||||
isKts = true,
|
||||
localRepoDir = localRepo
|
||||
)
|
||||
|
||||
subProject(projectDepName)
|
||||
.projectPath
|
||||
.allKotlinFiles
|
||||
.forEach { ktFile ->
|
||||
// Avoid FQN duplicates between producer & consumer
|
||||
ktFile.replaceText("package com.h0tk3y.hmpp.klib.demo", "package com.h0tk3y.hmpp.klib.lib")
|
||||
}
|
||||
|
||||
subProject(projectDepName).buildGradleKts.appendText(
|
||||
"""
|
||||
|
|
||||
|group = "$publishedGroup"
|
||||
""".trimMargin()
|
||||
)
|
||||
|
||||
buildGradleKts.appendText(
|
||||
"""
|
||||
|
|
||||
|dependencies { "commonMainImplementation"(project(":$projectDepName")) }
|
||||
|group = "$publishedGroup"
|
||||
""".trimMargin()
|
||||
)
|
||||
settingsGradleKts.appendText(
|
||||
"""
|
||||
|
|
||||
|rootProject.name = "$producerProjectName"
|
||||
|
|
||||
""".trimMargin()
|
||||
)
|
||||
|
||||
build("publish")
|
||||
|
||||
// Then consume the published project. To do that, rename the modules so that Gradle chooses the published ones given the original
|
||||
// Maven coordinates and doesn't resolve them as project dependencies.
|
||||
val localGroup = "local"
|
||||
subProject(projectDepName).buildGradleKts.appendText(
|
||||
"""
|
||||
|
|
||||
|group = "$localGroup"
|
||||
""".trimMargin()
|
||||
)
|
||||
buildGradleKts.appendText(
|
||||
"""
|
||||
|
|
||||
|repositories { maven("${'$'}rootDir/repo") }
|
||||
|dependencies { "commonMainImplementation"("$publishedGroup:$producerProjectName:1.0") }
|
||||
|group = "$localGroup"
|
||||
""".trimMargin()
|
||||
)
|
||||
|
||||
val commonModules = listOf(
|
||||
"published-producer-1.0-commonMain-[\\w-]+.klib",
|
||||
"published-dependency-1.0-commonMain-[\\w-]+.klib",
|
||||
).map(::Regex)
|
||||
|
||||
val hostSpecificModules = listOf(
|
||||
"published-producer-1.0-iosMain-[\\w-]+.klib",
|
||||
"published-dependency-1.0-iosMain-[\\w-]+.klib",
|
||||
).map(::Regex)
|
||||
|
||||
val windowsAndLinuxModules = listOf(
|
||||
"published-producer-1.0-windowsAndLinuxMain-[\\w-]+.klib",
|
||||
"published-dependency-1.0-windowsAndLinuxMain-[\\w-]+.klib",
|
||||
).map(::Regex)
|
||||
|
||||
checkTaskCompileClasspath(
|
||||
"compileWindowsAndLinuxMainKotlinMetadata",
|
||||
checkModulesInClasspath = commonModules + windowsAndLinuxModules,
|
||||
checkModulesNotInClasspath = hostSpecificModules
|
||||
)
|
||||
|
||||
// The consumer should correctly receive the klibs of the host-specific source sets
|
||||
if (HostManager.hostIsMac) {
|
||||
checkTaskCompileClasspath(
|
||||
"compileIosMainKotlinMetadata",
|
||||
checkModulesInClasspath = commonModules + hostSpecificModules,
|
||||
checkModulesNotInClasspath = windowsAndLinuxModules
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Host-specific dependencies are only possible on macOS
|
||||
@OsCondition(
|
||||
supportedOn = [OS.MAC],
|
||||
enabledOnCI = [OS.MAC],
|
||||
)
|
||||
@DisplayName("Works with host specific dependencies")
|
||||
@GradleTest
|
||||
fun testHostSpecificBuildWithPublishedDependency(
|
||||
gradleVersion: GradleVersion,
|
||||
@TempDir localRepo: Path
|
||||
) {
|
||||
testBuildWithDependency(gradleVersion, localRepo) {
|
||||
publishProjectDepAndAddDependency(validateHostSpecificPublication = true)
|
||||
}
|
||||
}
|
||||
|
||||
@DisplayName("Works with Kotlin native transitive dependencies")
|
||||
@GradleTest
|
||||
fun testKotlinNativeImplPublishedDeps(
|
||||
gradleVersion: GradleVersion,
|
||||
@TempDir localRepo: Path
|
||||
) {
|
||||
testKotlinNativeImplementationDependencies(gradleVersion, localRepo) {
|
||||
build(":$transitiveDepModuleName:publish", ":$dependencyModuleName:publish")
|
||||
|
||||
buildGradleKts.appendText(
|
||||
"""
|
||||
|
|
||||
|repositories {
|
||||
| maven("${'$'}rootDir/repo")
|
||||
|}
|
||||
|
|
||||
|dependencies {
|
||||
| commonMainImplementation("$MODULE_GROUP:$dependencyModuleName:1.0")
|
||||
|}
|
||||
""".trimMargin()
|
||||
)
|
||||
|
||||
listOf(transitiveDepModuleName, dependencyModuleName).forEach {
|
||||
// prevent Gradle from linking the above dependency to the project:
|
||||
subProject(it).buildGradleKts.appendText(
|
||||
"""
|
||||
|
|
||||
|group = "com.some.other.group"
|
||||
""".trimMargin()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@DisplayName("Works with project dependencies containing Kotlin Native target")
|
||||
@GradleTest
|
||||
fun testKotlinNativeImplProjectDeps(
|
||||
gradleVersion: GradleVersion,
|
||||
@TempDir localRepo: Path,
|
||||
) {
|
||||
testKotlinNativeImplementationDependencies(gradleVersion, localRepo) {
|
||||
buildGradleKts.appendText(
|
||||
"""
|
||||
|
|
||||
|dependencies {
|
||||
| "commonMainImplementation"(project(":$dependencyModuleName"))
|
||||
|}
|
||||
""".trimMargin()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@DisplayName("KT-38746: Should not disable compilation of shared source set")
|
||||
@GradleTest
|
||||
fun testAvoidSkippingSharedNativeSourceSetKt38746(gradleVersion: GradleVersion) {
|
||||
project("hierarchical-all-native", gradleVersion) {
|
||||
val targetNames = listOf(
|
||||
// Try different alphabetical ordering of the targets to ensure that the behavior doesn't depend on it,
|
||||
// as with 'first target'
|
||||
listOf("a1", "a2", "a3"),
|
||||
listOf("a3", "a1", "a2"),
|
||||
listOf("a2", "a3", "a1"),
|
||||
)
|
||||
val targetParamNames = listOf("mingwTargetName", "linuxTargetName", "macosTargetName", "currentHostTargetName")
|
||||
for (names in targetNames) {
|
||||
val currentHostTargetName = when {
|
||||
HostManager.hostIsMingw -> names[0]
|
||||
HostManager.hostIsLinux -> names[1]
|
||||
HostManager.hostIsMac -> names[2]
|
||||
else -> error("unexpected host")
|
||||
}
|
||||
val params = targetParamNames.zip(names + currentHostTargetName) { k, v -> "-P$k=$v" }
|
||||
build(":clean", ":compileCurrentHostAndLinuxKotlinMetadata", *params.toTypedArray()) {
|
||||
assertTasksExecuted(":compileCurrentHostAndLinuxKotlinMetadata", ":compileAllNativeKotlinMetadata")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun TestProject.publishProjectDepAndAddDependency(validateHostSpecificPublication: Boolean) {
|
||||
build(":$dependencyModuleName:publish") {
|
||||
assertSuccessful()
|
||||
if (validateHostSpecificPublication)
|
||||
checkPublishedHostSpecificMetadata(this@build)
|
||||
if (validateHostSpecificPublication) checkPublishedHostSpecificMetadata(this@publishProjectDepAndAddDependency)
|
||||
}
|
||||
|
||||
gradleBuildScript().appendText(
|
||||
"\n" + """
|
||||
repositories {
|
||||
maven("${'$'}rootDir/repo")
|
||||
}
|
||||
dependencies {
|
||||
commonMainImplementation("$MODULE_GROUP:$dependencyModuleName:1.0")
|
||||
}
|
||||
""".trimIndent()
|
||||
buildGradleKts.appendText(
|
||||
"""
|
||||
|
|
||||
|repositories {
|
||||
| maven("${'$'}rootDir/repo")
|
||||
|}
|
||||
|
|
||||
|dependencies {
|
||||
| commonMainImplementation("$MODULE_GROUP:$dependencyModuleName:1.0")
|
||||
|}
|
||||
""".trimMargin()
|
||||
)
|
||||
|
||||
// prevent Gradle from linking the above dependency to the project:
|
||||
gradleBuildScript(dependencyModuleName).appendText("\ngroup = \"some.other.group\"")
|
||||
subProject(dependencyModuleName)
|
||||
.buildGradleKts
|
||||
.appendText(
|
||||
"""
|
||||
|
|
||||
|group = "some.other.group"
|
||||
""".trimMargin()
|
||||
)
|
||||
}
|
||||
|
||||
private val dependencyModuleName = "project-dep"
|
||||
private val transitiveDepModuleName = "transitive-dep"
|
||||
|
||||
private fun testBuildWithDependency(configureDependency: Project.() -> Unit) = with(Project("common-klib-lib-and-app")) {
|
||||
embedProject(Project("common-klib-lib-and-app"), renameTo = dependencyModuleName)
|
||||
private fun testBuildWithDependency(
|
||||
gradleVersion: GradleVersion,
|
||||
localRepo: Path,
|
||||
configureDependency: TestProject.() -> Unit
|
||||
) {
|
||||
project("common-klib-lib-and-app", gradleVersion, localRepoDir = localRepo) {
|
||||
includeOtherProjectAsSubmodule(
|
||||
otherProjectName = "common-klib-lib-and-app",
|
||||
newSubmoduleName = dependencyModuleName,
|
||||
isKts = true,
|
||||
localRepoDir = localRepo,
|
||||
)
|
||||
|
||||
projectDir.resolve("$dependencyModuleName/src/commonMain/kotlin/TestKt37832.kt").writeText(
|
||||
"package com.example.test.kt37832" + "\n" + "class MyException : RuntimeException()"
|
||||
)
|
||||
subProject(dependencyModuleName)
|
||||
.kotlinSourcesDir("commonMain")
|
||||
.resolve("TestKt37832.kt")
|
||||
.writeText(
|
||||
"""
|
||||
|package com.example.test.kt37832
|
||||
|
|
||||
|class MyException : RuntimeException()
|
||||
""".trimMargin()
|
||||
)
|
||||
|
||||
gradleBuildScript().modify(::transformBuildScriptWithPluginsDsl)
|
||||
|
||||
projectDir.resolve(dependencyModuleName + "/src").walkTopDown().filter { it.extension == "kt" }.forEach { file ->
|
||||
file.modify { it.replace("package com.h0tk3y.hmpp.klib.demo", "package com.projectdep") }
|
||||
}
|
||||
|
||||
configureDependency()
|
||||
|
||||
projectDir.resolve("src/commonMain/kotlin/LibUsage.kt").appendText(
|
||||
"\n" + """
|
||||
package com.h0tk3y.hmpp.klib.demo.test
|
||||
|
||||
import com.projectdep.LibCommonMainExpect as ProjectDepExpect
|
||||
|
||||
private fun useProjectDep() {
|
||||
ProjectDepExpect()
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
projectDir.resolve("src/linuxMain/kotlin/LibLinuxMainUsage.kt").appendText(
|
||||
"\n" + """
|
||||
package com.h0tk3y.hmpp.klib.demo.test
|
||||
|
||||
import com.projectdep.libLinuxMainFun as libFun
|
||||
|
||||
private fun useProjectDep() {
|
||||
libFun()
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
val tasksToExecute = listOf(
|
||||
":compileJvmAndJsMainKotlinMetadata",
|
||||
":compileLinuxMainKotlinMetadata",
|
||||
) + (if (HostManager.hostIsMac) listOf(":compileIosMainKotlinMetadata") else emptyList())
|
||||
|
||||
build("assemble") {
|
||||
assertSuccessful()
|
||||
|
||||
assertTasksExecuted(*tasksToExecute.toTypedArray())
|
||||
|
||||
assertFileExists("build/classes/kotlin/metadata/commonMain/default/manifest")
|
||||
assertFileExists("build/classes/kotlin/metadata/jvmAndJsMain/default/manifest")
|
||||
assertFileExists("build/classes/kotlin/metadata/linuxMain/klib/${projectName}_linuxMain")
|
||||
|
||||
// Check that the common and JVM+JS source sets don't receive the Kotlin/Native stdlib in the classpath:
|
||||
run {
|
||||
fun getClasspath(taskPath: String): Iterable<String> {
|
||||
val argsPrefix = " $taskPath Kotlin compiler args:"
|
||||
return output.lines().single { argsPrefix in it }
|
||||
.substringAfter("-classpath ").substringBefore(" -").split(File.pathSeparator)
|
||||
subProject(dependencyModuleName)
|
||||
.projectPath
|
||||
.allKotlinFiles
|
||||
.forEach { file ->
|
||||
file.replaceText("package com.h0tk3y.hmpp.klib.demo", "package com.projectdep")
|
||||
}
|
||||
|
||||
fun classpathHasKNStdlib(classpath: Iterable<String>) = classpath.any { "klib/common/stdlib" in it.replace("\\", "/") }
|
||||
configureDependency()
|
||||
|
||||
kotlinSourcesDir("commonMain").resolve("LibUsage.kt").writeText(
|
||||
"""
|
||||
|
|
||||
|package com.h0tk3y.hmpp.klib.demo.test
|
||||
|
|
||||
|import com.projectdep.LibCommonMainExpect as ProjectDepExpect
|
||||
|
|
||||
|private fun useProjectDep() {
|
||||
| ProjectDepExpect()
|
||||
|}
|
||||
""".trimMargin()
|
||||
)
|
||||
|
||||
kotlinSourcesDir("linuxMain").resolve("LibLinuxMainUsage.kt").writeText(
|
||||
"""
|
||||
|
|
||||
|package com.h0tk3y.hmpp.klib.demo.test
|
||||
|
|
||||
|import com.projectdep.libLinuxMainFun as libFun
|
||||
|
|
||||
|private fun useProjectDep() {
|
||||
| libFun()
|
||||
|}
|
||||
""".trimMargin()
|
||||
)
|
||||
|
||||
val tasksToExecute = listOfNotNull(
|
||||
":compileJvmAndJsMainKotlinMetadata",
|
||||
":compileLinuxMainKotlinMetadata",
|
||||
if (HostManager.hostIsMac) ":compileIosMainKotlinMetadata" else null
|
||||
)
|
||||
|
||||
build("assemble") {
|
||||
assertTasksExecuted(tasksToExecute)
|
||||
|
||||
assertFileInProjectExists("build/classes/kotlin/metadata/commonMain/default/manifest")
|
||||
assertFileInProjectExists("build/classes/kotlin/metadata/jvmAndJsMain/default/manifest")
|
||||
assertDirectoryInProjectExists("build/classes/kotlin/metadata/linuxMain/klib/${projectName}_linuxMain")
|
||||
|
||||
// Check that the common and JVM+JS source sets don't receive the Kotlin/Native stdlib in the classpath:
|
||||
assertFalse(classpathHasKNStdlib(getClasspath(":compileCommonMainKotlinMetadata")))
|
||||
assertFalse(classpathHasKNStdlib(getClasspath(":compileJvmAndJsMainKotlinMetadata")))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkPublishedHostSpecificMetadata(compiledProject: CompiledProject) = with(compiledProject) {
|
||||
val groupDir = project.projectDir.resolve("repo/com/example")
|
||||
private fun classpathHasKNStdlib(classpath: Iterable<String>) = classpath.any { "klib/common/stdlib" in it.replace("\\", "/") }
|
||||
|
||||
assertTasksExecuted(
|
||||
":$dependencyModuleName:compileIosMainKotlinMetadata")
|
||||
private fun BuildResult.getClasspath(taskPath: String): Iterable<String> {
|
||||
val argsPrefix = " $taskPath Kotlin compiler args:"
|
||||
return output.lines().single { argsPrefix in it }
|
||||
.substringAfter("-classpath ").substringBefore(" -").split(File.pathSeparator)
|
||||
}
|
||||
|
||||
private fun BuildResult.checkPublishedHostSpecificMetadata(project: TestProject) {
|
||||
val groupDir = project.projectPath.resolve("repo/com/example")
|
||||
|
||||
assertTasksExecuted(":$dependencyModuleName:compileIosMainKotlinMetadata")
|
||||
|
||||
// Check that the metadata JAR doesn't contain the host-specific source set entries, but contains the shared-Native source set
|
||||
// that can be built on every host:
|
||||
|
||||
ZipFile(groupDir.resolve("$dependencyModuleName/1.0/$dependencyModuleName-1.0-all.jar")).use { metadataJar ->
|
||||
assertTrue { metadataJar.entries().asSequence().none { it.name.startsWith("iosMain") } }
|
||||
assertTrue { metadataJar.entries().asSequence().any { it.name.startsWith("linuxMain") } }
|
||||
}
|
||||
ZipFile(groupDir.resolve("$dependencyModuleName/1.0/$dependencyModuleName-1.0-all.jar").toFile())
|
||||
.use { metadataJar ->
|
||||
assertTrue(metadataJar.entries().asSequence().none { it.name.startsWith("iosMain") })
|
||||
assertTrue(metadataJar.entries().asSequence().any { it.name.startsWith("linuxMain") })
|
||||
}
|
||||
|
||||
// Then check that in the host-specific modules, there's a metadata artifact that contains the host-specific source set but not the
|
||||
// common source sets:
|
||||
|
||||
val hostSpecificTargets = when {
|
||||
HostManager.hostIsMac -> listOf("iosArm64", "iosX64")
|
||||
else -> error("Host doesn't support host-specific metadata")
|
||||
@@ -246,99 +407,64 @@ open class KlibBasedMppIT : BaseGradleIT() {
|
||||
|
||||
hostSpecificTargets.forEach { targetName ->
|
||||
val moduleName = "$dependencyModuleName-${targetName.lowercase(Locale.getDefault())}"
|
||||
ZipFile(groupDir.resolve("$moduleName/1.0/$moduleName-1.0-metadata.jar")).use { metadataJar ->
|
||||
assertTrue { metadataJar.entries().asSequence().any { it.name.startsWith("iosMain") } }
|
||||
assertTrue { metadataJar.entries().asSequence().none { it.name.startsWith("commonMain") } }
|
||||
}
|
||||
ZipFile(groupDir.resolve("$moduleName/1.0/$moduleName-1.0-metadata.jar").toFile())
|
||||
.use { metadataJar ->
|
||||
assertTrue(metadataJar.entries().asSequence().any { it.name.startsWith("iosMain") })
|
||||
assertTrue(metadataJar.entries().asSequence().none { it.name.startsWith("commonMain") })
|
||||
}
|
||||
}
|
||||
|
||||
// Also check that the targets that don't include any host-specific sources don't even have the metadata artifact:
|
||||
|
||||
groupDir.resolve("$dependencyModuleName-linuxx64/1.0/$dependencyModuleName-linuxx64-1.0-metadata.jar").let { metadataJar ->
|
||||
assertTrue { !metadataJar.exists() }
|
||||
}
|
||||
assertFileNotExists(
|
||||
groupDir.resolve("$dependencyModuleName-linuxx64/1.0/$dependencyModuleName-linuxx64-1.0-metadata.jar")
|
||||
)
|
||||
}
|
||||
|
||||
private val transitiveDepModuleName = "transitive-dep"
|
||||
|
||||
@Test
|
||||
fun testKotlinNativeImplPublishedDeps() =
|
||||
testKotlinNativeImplementationDependencies {
|
||||
build(":$transitiveDepModuleName:publish", ":$dependencyModuleName:publish") {
|
||||
assertSuccessful()
|
||||
}
|
||||
|
||||
gradleBuildScript().appendText(
|
||||
"\n" + """
|
||||
repositories {
|
||||
maven("${'$'}rootDir/repo")
|
||||
}
|
||||
dependencies {
|
||||
commonMainImplementation("$MODULE_GROUP:$dependencyModuleName:1.0")
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
listOf(transitiveDepModuleName, dependencyModuleName).forEach {
|
||||
// prevent Gradle from linking the above dependency to the project:
|
||||
gradleBuildScript(it).appendText("\ngroup = \"com.some.other.group\"")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testKotlinNativeImplProjectDeps() =
|
||||
testKotlinNativeImplementationDependencies {
|
||||
gradleBuildScript().appendText("\ndependencies { \"commonMainImplementation\"(project(\":$dependencyModuleName\")) }")
|
||||
}
|
||||
|
||||
private fun testKotlinNativeImplementationDependencies(
|
||||
setupDependencies: Project.() -> Unit,
|
||||
) = with(Project("common-klib-lib-and-app")) {
|
||||
embedProject(Project("common-klib-lib-and-app"), renameTo = transitiveDepModuleName)
|
||||
embedProject(Project("common-klib-lib-and-app"), renameTo = dependencyModuleName).apply {
|
||||
projectDir.resolve(dependencyModuleName).walkTopDown().filter { it.extension == "kt" }.forEach { file ->
|
||||
// Avoid duplicate FQNs as in the compatibility mode, the K2Metadata compiler reports duplicate symbols on them:
|
||||
file.modify { it.replace("package com.h0tk3y.hmpp.klib.demo", "package com.h0tk3y.hmpp.klib.demo1") }
|
||||
}
|
||||
}
|
||||
gradleBuildScript().modify(::transformBuildScriptWithPluginsDsl)
|
||||
gradleBuildScript(dependencyModuleName).appendText("\ndependencies { \"commonMainImplementation\"(project(\":$transitiveDepModuleName\")) }")
|
||||
gradleVersion: GradleVersion,
|
||||
localRepo: Path,
|
||||
setupProject: TestProject.() -> Unit,
|
||||
) {
|
||||
project("common-klib-lib-and-app", gradleVersion, localRepoDir = localRepo) {
|
||||
includeOtherProjectAsSubmodule(
|
||||
otherProjectName = "common-klib-lib-and-app",
|
||||
newSubmoduleName = transitiveDepModuleName,
|
||||
isKts = true,
|
||||
localRepoDir = localRepo,
|
||||
)
|
||||
includeOtherProjectAsSubmodule(
|
||||
otherProjectName = "common-klib-lib-and-app",
|
||||
newSubmoduleName = dependencyModuleName,
|
||||
isKts = true,
|
||||
localRepoDir = localRepo
|
||||
)
|
||||
|
||||
setupDependencies(this@with)
|
||||
subProject(dependencyModuleName)
|
||||
.projectPath
|
||||
.allKotlinFiles
|
||||
.forEach { file ->
|
||||
// Avoid duplicate FQNs as in the compatibility mode, the K2Metadata compiler reports duplicate symbols on them:
|
||||
file.replaceText("package com.h0tk3y.hmpp.klib.demo", "package com.h0tk3y.hmpp.klib.demo1")
|
||||
}
|
||||
|
||||
val compileNativeMetadataTaskName = "compileLinuxMainKotlinMetadata"
|
||||
build(":$compileNativeMetadataTaskName") {
|
||||
assertSuccessful()
|
||||
subProject(dependencyModuleName)
|
||||
.buildGradleKts
|
||||
.appendText(
|
||||
"""
|
||||
|
|
||||
|dependencies {
|
||||
| "commonMainImplementation"(project(":$transitiveDepModuleName"))
|
||||
|}
|
||||
""".trimMargin()
|
||||
)
|
||||
|
||||
setupProject(this)
|
||||
|
||||
build(":compileLinuxMainKotlinMetadata")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAvoidSkippingSharedNativeSourceSetKt38746() = with(Project("hierarchical-all-native")) {
|
||||
val targetNames = listOf(
|
||||
// Try different alphabetical ordering of the targets to ensure that the behavior doesn't depend on it, as with 'first target'
|
||||
listOf("a1", "a2", "a3"),
|
||||
listOf("a3", "a1", "a2"),
|
||||
listOf("a2", "a3", "a1"),
|
||||
)
|
||||
val targetParamNames = listOf("mingwTargetName", "linuxTargetName", "macosTargetName", "currentHostTargetName")
|
||||
for (names in targetNames) {
|
||||
val currentHostTargetName = when {
|
||||
HostManager.hostIsMingw -> names[0]
|
||||
HostManager.hostIsLinux -> names[1]
|
||||
HostManager.hostIsMac -> names[2]
|
||||
else -> error("unexpected host")
|
||||
}
|
||||
val params = targetParamNames.zip(names + currentHostTargetName) { k, v -> "-P$k=$v" }
|
||||
build(":clean", ":compileCurrentHostAndLinuxKotlinMetadata", *params.toTypedArray()) {
|
||||
assertSuccessful()
|
||||
assertTasksExecuted(":compileCurrentHostAndLinuxKotlinMetadata", ":compileAllNativeKotlinMetadata")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var testBuildRunId = 0
|
||||
|
||||
private fun BaseGradleIT.Project.checkTaskCompileClasspath(
|
||||
private fun TestProject.checkTaskCompileClasspath(
|
||||
taskPath: String,
|
||||
checkModulesInClasspath: List<Regex> = emptyList(),
|
||||
checkModulesNotInClasspath: List<Regex> = emptyList(),
|
||||
@@ -350,28 +476,27 @@ open class KlibBasedMppIT : BaseGradleIT() {
|
||||
checkPrintedItems(subproject, expression, checkModulesInClasspath, checkModulesNotInClasspath)
|
||||
}
|
||||
|
||||
private fun BaseGradleIT.Project.checkPrintedItems(
|
||||
private fun TestProject.checkPrintedItems(
|
||||
subproject: String?,
|
||||
itemsExpression: String,
|
||||
checkAnyItemsContains: List<Regex>,
|
||||
checkNoItemContains: List<Regex>,
|
||||
) = with(testCase) {
|
||||
setupWorkingDir()
|
||||
|
||||
val printingTaskName = "printItems${testBuildRunId++}"
|
||||
gradleBuildScript(subproject).appendText(
|
||||
) {
|
||||
val printingTaskName = "printItems"
|
||||
val testProject = if (subproject != null) subProject(subproject) else this
|
||||
testProject.buildGradleKts.appendText(
|
||||
"""
|
||||
${'\n'}
|
||||
tasks.register("$printingTaskName") {
|
||||
dependsOn("transformDependenciesMetadata")
|
||||
doLast {
|
||||
println("###$printingTaskName" + $itemsExpression)
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
|
||||
|tasks.register("$printingTaskName") {
|
||||
| dependsOn("transformDependenciesMetadata")
|
||||
| doLast {
|
||||
| println("###$printingTaskName" + $itemsExpression)
|
||||
| }
|
||||
|}
|
||||
""".trimMargin()
|
||||
)
|
||||
|
||||
build("${subproject?.prependIndent(":").orEmpty()}:$printingTaskName") {
|
||||
assertSuccessful()
|
||||
val itemsLine = output.lines().single { "###$printingTaskName" in it }.substringAfter(printingTaskName)
|
||||
// NOTE: This does not work for commonized libraries, they may contain the ',' naturally
|
||||
val items = itemsLine.removeSurrounding("[", "]").split(", ").toSet()
|
||||
@@ -383,4 +508,8 @@ open class KlibBasedMppIT : BaseGradleIT() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val MODULE_GROUP = "com.example"
|
||||
}
|
||||
}
|
||||
+10
-3
@@ -397,11 +397,16 @@ class TestProject(
|
||||
*/
|
||||
fun includeOtherProjectAsSubmodule(
|
||||
otherProjectName: String,
|
||||
pathPrefix: String,
|
||||
pathPrefix: String = "",
|
||||
newSubmoduleName: String = otherProjectName,
|
||||
isKts: Boolean = false,
|
||||
localRepoDir: Path? = null,
|
||||
) {
|
||||
val otherProjectPath = "$pathPrefix/$otherProjectName".testProjectPath
|
||||
val otherProjectPath = if (pathPrefix.isEmpty()) {
|
||||
otherProjectName.testProjectPath
|
||||
} else {
|
||||
"$pathPrefix/$otherProjectName".testProjectPath
|
||||
}
|
||||
otherProjectPath.copyRecursively(projectPath.resolve(newSubmoduleName))
|
||||
|
||||
val gradleSettingToUpdate = if (isKts) settingsGradleKts else settingsGradle
|
||||
@@ -412,6 +417,8 @@ class TestProject(
|
||||
include(":$newSubmoduleName")
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
localRepoDir?.let { subProject(newSubmoduleName).configureLocalRepository(localRepoDir) }
|
||||
}
|
||||
|
||||
fun includeOtherProjectAsIncludedBuild(
|
||||
@@ -814,7 +821,7 @@ private fun TestProject.configureSingleNativeTargetInSubFolders(preset: String =
|
||||
}
|
||||
}
|
||||
|
||||
private fun TestProject.configureLocalRepository(localRepoDir: Path) {
|
||||
private fun GradleProject.configureLocalRepository(localRepoDir: Path) {
|
||||
projectPath.toFile().walkTopDown()
|
||||
.filter { it.isFile && it.name in buildFileNames }
|
||||
.forEach { file ->
|
||||
|
||||
+2
-7
@@ -1,16 +1,11 @@
|
||||
plugins {
|
||||
kotlin("multiplatform").version("<pluginMarkerVersion>")
|
||||
kotlin("multiplatform")
|
||||
id("maven-publish")
|
||||
}
|
||||
|
||||
group = "com.example"
|
||||
version = "1.0"
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvm()
|
||||
js()
|
||||
@@ -65,7 +60,7 @@ kotlin {
|
||||
|
||||
publishing {
|
||||
repositories {
|
||||
maven("$rootDir/repo")
|
||||
maven("<localRepo>")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user