Migration HierarchicalMppIT tests to new DSL
^KT-50912
This commit is contained in:
committed by
Space
parent
c56f06f942
commit
86d8ef7e45
+231
-163
@@ -5,62 +5,91 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle
|
||||
|
||||
import org.gradle.api.logging.LogLevel
|
||||
import org.gradle.api.logging.configuration.WarningMode
|
||||
import org.gradle.testkit.runner.BuildResult
|
||||
import org.gradle.util.GradleVersion
|
||||
import org.jetbrains.kotlin.gradle.internals.MULTIPLATFORM_PROJECT_METADATA_JSON_FILE_NAME
|
||||
import org.jetbrains.kotlin.gradle.internals.parseKotlinSourceSetMetadataFromJson
|
||||
import org.jetbrains.kotlin.gradle.native.transformNativeTestProjectWithPluginDsl
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinJsCompilerType
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinProjectStructureMetadata
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.ModuleDependencyIdentifier
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.SourceSetMetadataLayout
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultKotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.testbase.*
|
||||
import org.jetbrains.kotlin.gradle.util.checkedReplace
|
||||
import org.jetbrains.kotlin.gradle.util.modify
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.io.TempDir
|
||||
import java.io.File
|
||||
import java.nio.file.Path
|
||||
import java.util.zip.ZipFile
|
||||
import kotlin.test.Test
|
||||
import kotlin.io.path.absolutePathString
|
||||
import kotlin.io.path.appendText
|
||||
import kotlin.io.path.writeText
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class HierarchicalMppIT : BaseGradleIT() {
|
||||
override val defaultGradleVersion: GradleVersionRequired
|
||||
get() = gradleVersion
|
||||
@MppGradlePluginTests
|
||||
@DisplayName("Hierarchical multiplatform")
|
||||
class HierarchicalMppIT : KGPBaseTest() {
|
||||
|
||||
companion object {
|
||||
private val gradleVersion = GradleVersionRequired.FOR_MPP_SUPPORT
|
||||
}
|
||||
private val String.withPrefix get() = "hierarchical-mpp-published-modules/$this"
|
||||
|
||||
@Test
|
||||
fun testPublishedModules() {
|
||||
publishThirdPartyLib(withGranularMetadata = false)
|
||||
@GradleTest
|
||||
@DisplayName("Check build with published third-party library")
|
||||
fun testPublishedModules(gradleVersion: GradleVersion, @TempDir tempDir: Path) {
|
||||
val buildOptions = defaultBuildOptions.copy(logLevel = LogLevel.DEBUG)
|
||||
|
||||
transformNativeTestProjectWithPluginDsl("my-lib-foo", gradleVersion, "hierarchical-mpp-published-modules").run {
|
||||
publishThirdPartyLib(withGranularMetadata = false, gradleVersion = gradleVersion, localRepoDir = tempDir)
|
||||
|
||||
nativeProject(
|
||||
"my-lib-foo".withPrefix,
|
||||
gradleVersion,
|
||||
localRepoDir = tempDir,
|
||||
buildOptions = buildOptions
|
||||
).run {
|
||||
build("publish") {
|
||||
checkMyLibFoo(this, subprojectPrefix = null)
|
||||
checkMyLibFoo(localRepoDir = tempDir)
|
||||
}
|
||||
}
|
||||
|
||||
transformNativeTestProjectWithPluginDsl("my-lib-bar", gradleVersion, "hierarchical-mpp-published-modules").run {
|
||||
nativeProject(
|
||||
"my-lib-bar".withPrefix,
|
||||
gradleVersion,
|
||||
localRepoDir = tempDir,
|
||||
buildOptions = buildOptions
|
||||
).run {
|
||||
build("publish") {
|
||||
checkMyLibBar(this, subprojectPrefix = null)
|
||||
checkMyLibBar(localRepoDir = tempDir)
|
||||
}
|
||||
}
|
||||
|
||||
transformNativeTestProjectWithPluginDsl("my-app", gradleVersion, "hierarchical-mpp-published-modules").run {
|
||||
nativeProject(
|
||||
"my-app".withPrefix,
|
||||
gradleVersion,
|
||||
localRepoDir = tempDir,
|
||||
buildOptions = buildOptions
|
||||
).run {
|
||||
build("assemble") {
|
||||
checkMyApp(this, subprojectPrefix = null)
|
||||
checkMyApp()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNoSourceSetsVisibleIfNoVariantMatched() {
|
||||
publishThirdPartyLib(withGranularMetadata = true)
|
||||
@GradleTest
|
||||
@DisplayName("Check no sourceSets visible if no variant matched")
|
||||
fun testNoSourceSetsVisibleIfNoVariantMatched(gradleVersion: GradleVersion, @TempDir tempDir: Path) {
|
||||
publishThirdPartyLib(withGranularMetadata = true, gradleVersion = gradleVersion, localRepoDir = tempDir)
|
||||
|
||||
transformNativeTestProjectWithPluginDsl("my-lib-foo", gradleVersion, "hierarchical-mpp-published-modules").run {
|
||||
nativeProject(
|
||||
projectName = "my-lib-foo".withPrefix,
|
||||
gradleVersion = gradleVersion,
|
||||
localRepoDir = tempDir
|
||||
).run {
|
||||
// --- Move the dependency from jvmAndJsMain to commonMain, where there's a linuxX64 target missing in the lib
|
||||
gradleBuildScript().modify {
|
||||
buildGradleKts.modify {
|
||||
it.checkedReplace("api(\"com.example.thirdparty:third-party-lib:1.0\")", "//") + "\n" + """
|
||||
dependencies {
|
||||
"commonMainApi"("com.example.thirdparty:third-party-lib:1.0")
|
||||
@@ -81,14 +110,19 @@ class HierarchicalMppIT : BaseGradleIT() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDependenciesInTests() {
|
||||
publishThirdPartyLib(withGranularMetadata = true) {
|
||||
projectDir.resolve("src/jvmMain").copyRecursively(projectDir.resolve("src/linuxX64Main"))
|
||||
gradleBuildScript().appendText("\nkotlin.linuxX64()")
|
||||
@GradleTest
|
||||
@DisplayName("Dependencies in tests should be correct with third-party library")
|
||||
fun testDependenciesInTests(gradleVersion: GradleVersion, @TempDir tempDir: Path) {
|
||||
publishThirdPartyLib(withGranularMetadata = true, gradleVersion = gradleVersion, localRepoDir = tempDir) {
|
||||
kotlinSourcesDir("jvmMain").copyRecursively(kotlinSourcesDir("linuxX64Main"))
|
||||
buildGradleKts.appendText("kotlin.linuxX64()")
|
||||
}
|
||||
|
||||
transformNativeTestProjectWithPluginDsl("my-lib-foo", gradleVersion, "hierarchical-mpp-published-modules").run {
|
||||
nativeProject(
|
||||
projectName = "my-lib-foo".withPrefix,
|
||||
gradleVersion = gradleVersion,
|
||||
localRepoDir = tempDir
|
||||
).run {
|
||||
testDependencyTransformations { reports ->
|
||||
val testApiTransformationReports =
|
||||
reports.filter { report ->
|
||||
@@ -110,13 +144,12 @@ class HierarchicalMppIT : BaseGradleIT() {
|
||||
val existingFilesFromReports = reports.flatMap { it.useFiles }.filter { it.isFile }
|
||||
assertTrue { existingFilesFromReports.isNotEmpty() }
|
||||
build("clean") {
|
||||
assertSuccessful()
|
||||
existingFilesFromReports.forEach { assertTrue("Expected that $it exists after clean build.") { it.isFile } }
|
||||
}
|
||||
}
|
||||
|
||||
// --- Move the dependency from jvmAndJsMain to commonMain, expect that it is now propagated to commonTest:
|
||||
gradleBuildScript().modify {
|
||||
buildGradleKts.modify {
|
||||
it.checkedReplace("api(\"com.example.thirdparty:third-party-lib:1.0\")", "//") + "\n" + """
|
||||
dependencies {
|
||||
"commonMainApi"("com.example.thirdparty:third-party-lib:1.0")
|
||||
@@ -140,7 +173,7 @@ class HierarchicalMppIT : BaseGradleIT() {
|
||||
|
||||
// --- Remove the dependency from commonMain, add it to commonTest to check that it is correctly picked from a non-published
|
||||
// source set:
|
||||
gradleBuildScript().modify {
|
||||
buildGradleKts.modify {
|
||||
it.checkedReplace("\"commonMainApi\"(\"com.example.thirdparty:third-party-lib:1.0\")", "//") + "\n" + """
|
||||
dependencies {
|
||||
"commonTestApi"("com.example.thirdparty:third-party-lib:1.0")
|
||||
@@ -166,93 +199,108 @@ class HierarchicalMppIT : BaseGradleIT() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testProjectDependencies() {
|
||||
publishThirdPartyLib(withGranularMetadata = false)
|
||||
@GradleTest
|
||||
@DisplayName("Dependencies in project should be correct with third-party library")
|
||||
fun testProjectDependencies(gradleVersion: GradleVersion, @TempDir tempDir: Path) {
|
||||
publishThirdPartyLib(withGranularMetadata = false, gradleVersion = gradleVersion, localRepoDir = tempDir)
|
||||
|
||||
with(transformNativeTestProjectWithPluginDsl("hierarchical-mpp-project-dependency", gradleVersion)) {
|
||||
build("publish", "assemble") {
|
||||
checkMyLibFoo(this, subprojectPrefix = "my-lib-foo")
|
||||
checkMyLibBar(this, subprojectPrefix = "my-lib-bar")
|
||||
checkMyApp(this, subprojectPrefix = "my-app")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testHmppWithPublishedJsBothDependency() {
|
||||
val directoryPrefix = "hierarchical-mpp-with-js-published-modules"
|
||||
publishThirdPartyLib(
|
||||
projectName = "third-party-lib",
|
||||
directoryPrefix = directoryPrefix,
|
||||
withGranularMetadata = true,
|
||||
jsCompilerType = KotlinJsCompilerType.BOTH
|
||||
)
|
||||
|
||||
with(transformNativeTestProjectWithPluginDsl("my-lib-foo", gradleVersion, directoryPrefix)) {
|
||||
build(
|
||||
"publish",
|
||||
"assemble",
|
||||
options = defaultBuildOptions().copy(jsCompilerType = KotlinJsCompilerType.IR)
|
||||
) {
|
||||
assertSuccessful()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testHmppWithProjectJsIrDependency() {
|
||||
with(transformNativeTestProjectWithPluginDsl("hierarchical-mpp-with-js-project-dependency", gradleVersion)) {
|
||||
build(
|
||||
"assemble",
|
||||
options = defaultBuildOptions().copy(jsCompilerType = KotlinJsCompilerType.IR)
|
||||
) {
|
||||
assertSuccessful()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMultiModulesHmppKt48370() = with(Project("hierarchical-mpp-multi-modules", GradleVersionRequired.FOR_MPP_SUPPORT)) {
|
||||
build(
|
||||
"assemble", options = defaultBuildOptions().copy(
|
||||
parallelTasksInProject = true,
|
||||
warningMode = WarningMode.Summary
|
||||
with(
|
||||
nativeProject(
|
||||
"hierarchical-mpp-project-dependency",
|
||||
gradleVersion,
|
||||
localRepoDir = tempDir,
|
||||
buildOptions = defaultBuildOptions.copy(logLevel = LogLevel.DEBUG)
|
||||
)
|
||||
) {
|
||||
assertSuccessful()
|
||||
build("publish", "assemble") {
|
||||
checkMyLibFoo(subprojectPrefix = "my-lib-foo", tempDir)
|
||||
checkMyLibBar(subprojectPrefix = "my-lib-bar", tempDir)
|
||||
checkMyApp(subprojectPrefix = "my-app")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@GradleTest
|
||||
@DisplayName("Works with published JS library")
|
||||
fun testHmppWithPublishedJsBothDependency(gradleVersion: GradleVersion, @TempDir tempDir: Path) {
|
||||
publishThirdPartyLib(
|
||||
projectName = "hierarchical-mpp-with-js-published-modules/third-party-lib",
|
||||
withGranularMetadata = true,
|
||||
jsCompilerType = KotlinJsCompilerType.BOTH,
|
||||
gradleVersion = gradleVersion,
|
||||
localRepoDir = tempDir
|
||||
)
|
||||
|
||||
with(
|
||||
nativeProject(
|
||||
"hierarchical-mpp-with-js-published-modules/my-lib-foo",
|
||||
gradleVersion,
|
||||
localRepoDir = tempDir,
|
||||
buildOptions = defaultBuildOptions.copy(jsOptions = BuildOptions.JsOptions(jsCompilerType = KotlinJsCompilerType.IR))
|
||||
)
|
||||
) {
|
||||
build("publish", "assemble")
|
||||
}
|
||||
}
|
||||
|
||||
@GradleTest
|
||||
@DisplayName("Works with project dependency on JS library")
|
||||
fun testHmppWithProjectJsIrDependency(gradleVersion: GradleVersion) {
|
||||
with(
|
||||
nativeProject(
|
||||
projectName = "hierarchical-mpp-with-js-project-dependency",
|
||||
gradleVersion = gradleVersion,
|
||||
buildOptions = defaultBuildOptions.copy(jsOptions = BuildOptions.JsOptions(jsCompilerType = KotlinJsCompilerType.IR))
|
||||
)
|
||||
) {
|
||||
build("assemble")
|
||||
}
|
||||
}
|
||||
|
||||
@GradleTest
|
||||
@DisplayName("KT-48370: Multiplatform Gradle build fails for Native targets with \"we cannot choose between the following variants of project\"")
|
||||
fun testMultiModulesHmppKt48370(gradleVersion: GradleVersion) = with(
|
||||
project(
|
||||
projectName = "hierarchical-mpp-multi-modules",
|
||||
gradleVersion = gradleVersion,
|
||||
buildOptions = defaultBuildOptions.copy(
|
||||
warningMode = WarningMode.Summary
|
||||
)
|
||||
)
|
||||
) {
|
||||
build(
|
||||
"assemble",
|
||||
)
|
||||
}
|
||||
|
||||
private fun publishThirdPartyLib(
|
||||
projectName: String = "third-party-lib",
|
||||
directoryPrefix: String = "hierarchical-mpp-published-modules",
|
||||
projectName: String = "third-party-lib".withPrefix,
|
||||
withGranularMetadata: Boolean,
|
||||
jsCompilerType: KotlinJsCompilerType = KotlinJsCompilerType.LEGACY,
|
||||
beforePublishing: Project.() -> Unit = { }
|
||||
): Project =
|
||||
transformNativeTestProjectWithPluginDsl(projectName, gradleVersion, directoryPrefix).apply {
|
||||
gradleVersion: GradleVersion,
|
||||
localRepoDir: Path,
|
||||
beforePublishing: TestProject.() -> Unit = { }
|
||||
): TestProject =
|
||||
nativeProject(
|
||||
projectName = projectName,
|
||||
gradleVersion = gradleVersion,
|
||||
localRepoDir = localRepoDir,
|
||||
buildOptions = defaultBuildOptions.copy(jsOptions = BuildOptions.JsOptions(jsCompilerType = jsCompilerType))
|
||||
).apply {
|
||||
beforePublishing()
|
||||
|
||||
if (!withGranularMetadata) {
|
||||
projectDir.resolve("gradle.properties").appendText("kotlin.internal.mpp.hierarchicalStructureByDefault=false")
|
||||
}
|
||||
|
||||
build(
|
||||
"publish",
|
||||
options = defaultBuildOptions().copy(jsCompilerType = jsCompilerType)
|
||||
) {
|
||||
assertSuccessful()
|
||||
projectPath.toFile().resolve("gradle.properties").appendText("kotlin.internal.mpp.hierarchicalStructureByDefault=false")
|
||||
}
|
||||
build("publish")
|
||||
}
|
||||
|
||||
private fun checkMyLibFoo(compiledProject: CompiledProject, subprojectPrefix: String? = null) = with(compiledProject) {
|
||||
assertSuccessful()
|
||||
private fun BuildResult.checkMyLibFoo(subprojectPrefix: String? = null, localRepoDir: Path) {
|
||||
assertTasksExecuted(expectedTasks(subprojectPrefix))
|
||||
|
||||
ZipFile(
|
||||
project.projectDir.parentFile.resolve(
|
||||
"repo/com/example/foo/my-lib-foo/1.0/my-lib-foo-1.0-all.jar"
|
||||
localRepoDir.toFile().resolve(
|
||||
"com/example/foo/my-lib-foo/1.0/my-lib-foo-1.0-all.jar"
|
||||
)
|
||||
).use { publishedMetadataJar ->
|
||||
publishedMetadataJar.checkAllEntryNamesArePresent(
|
||||
@@ -282,8 +330,8 @@ class HierarchicalMppIT : BaseGradleIT() {
|
||||
}
|
||||
|
||||
ZipFile(
|
||||
project.projectDir.parentFile.resolve(
|
||||
"repo/com/example/foo/my-lib-foo/1.0/my-lib-foo-1.0-sources.jar"
|
||||
localRepoDir.toFile().resolve(
|
||||
"com/example/foo/my-lib-foo/1.0/my-lib-foo-1.0-sources.jar"
|
||||
)
|
||||
).use { publishedSourcesJar ->
|
||||
publishedSourcesJar.checkAllEntryNamesArePresent(
|
||||
@@ -295,15 +343,14 @@ class HierarchicalMppIT : BaseGradleIT() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkMyLibBar(compiledProject: CompiledProject, subprojectPrefix: String?) = with(compiledProject) {
|
||||
private fun BuildResult.checkMyLibBar(subprojectPrefix: String? = null, localRepoDir: Path) {
|
||||
val taskPrefix = subprojectPrefix?.let { ":$it" }.orEmpty()
|
||||
|
||||
assertSuccessful()
|
||||
assertTasksExecuted(expectedTasks(subprojectPrefix))
|
||||
|
||||
ZipFile(
|
||||
project.projectDir.parentFile.resolve(
|
||||
"repo/com/example/bar/my-lib-bar/1.0/my-lib-bar-1.0-all.jar"
|
||||
localRepoDir.toFile().resolve(
|
||||
"com/example/bar/my-lib-bar/1.0/my-lib-bar-1.0-all.jar"
|
||||
)
|
||||
).use { publishedMetadataJar ->
|
||||
publishedMetadataJar.checkAllEntryNamesArePresent(
|
||||
@@ -333,8 +380,8 @@ class HierarchicalMppIT : BaseGradleIT() {
|
||||
}
|
||||
|
||||
ZipFile(
|
||||
project.projectDir.parentFile.resolve(
|
||||
"repo/com/example/bar/my-lib-bar/1.0/my-lib-bar-1.0-sources.jar"
|
||||
localRepoDir.toFile().resolve(
|
||||
"com/example/bar/my-lib-bar/1.0/my-lib-bar-1.0-sources.jar"
|
||||
)
|
||||
).use { publishedSourcesJar ->
|
||||
publishedSourcesJar.checkAllEntryNamesArePresent(
|
||||
@@ -382,10 +429,8 @@ class HierarchicalMppIT : BaseGradleIT() {
|
||||
)
|
||||
}
|
||||
|
||||
private fun checkMyApp(compiledProject: CompiledProject, subprojectPrefix: String?) = with(compiledProject) {
|
||||
private fun BuildResult.checkMyApp(subprojectPrefix: String? = null) {
|
||||
val taskPrefix = subprojectPrefix?.let { ":$it" }.orEmpty()
|
||||
|
||||
assertSuccessful()
|
||||
assertTasksExecuted(expectedTasks(subprojectPrefix))
|
||||
|
||||
checkNamesOnCompileClasspath(
|
||||
@@ -436,7 +481,7 @@ class HierarchicalMppIT : BaseGradleIT() {
|
||||
checkNamesOnCompileClasspath("$taskPrefix:compileLinuxAndJsMainKotlinMetadata")
|
||||
}
|
||||
|
||||
private fun CompiledProject.checkNamesOnCompileClasspath(
|
||||
private fun BuildResult.checkNamesOnCompileClasspath(
|
||||
taskPath: String,
|
||||
shouldInclude: Iterable<Pair<String, String>> = emptyList(),
|
||||
shouldNotInclude: Iterable<Pair<String, String>> = emptyList()
|
||||
@@ -519,13 +564,15 @@ class HierarchicalMppIT : BaseGradleIT() {
|
||||
return checkNotNull(parseKotlinSourceSetMetadataFromJson(json))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCompileOnlyDependencyProcessingForMetadataCompilations() =
|
||||
with(transformNativeTestProjectWithPluginDsl("hierarchical-mpp-project-dependency")) {
|
||||
publishThirdPartyLib(withGranularMetadata = true)
|
||||
@GradleTest
|
||||
@DisplayName("Compile only dependency processing for metadata compilations")
|
||||
fun testCompileOnlyDependencyProcessingForMetadataCompilations(gradleVersion: GradleVersion, @TempDir tempDir: Path) =
|
||||
with(nativeProject("hierarchical-mpp-project-dependency", gradleVersion, localRepoDir = tempDir)) {
|
||||
publishThirdPartyLib(withGranularMetadata = true, gradleVersion = gradleVersion, localRepoDir = tempDir)
|
||||
|
||||
gradleBuildScript("my-lib-foo").appendText("\ndependencies { \"jvmAndJsMainCompileOnly\"(kotlin(\"test-annotations-common\")) }")
|
||||
projectDir.resolve("my-lib-foo/src/jvmAndJsMain/kotlin/UseCompileOnlyDependency.kt").writeText(
|
||||
subProject("my-lib-foo").buildGradleKts
|
||||
.appendText("\ndependencies { \"jvmAndJsMainCompileOnly\"(kotlin(\"test-annotations-common\")) }")
|
||||
projectPath.resolve("my-lib-foo/src/jvmAndJsMain/kotlin/UseCompileOnlyDependency.kt").writeText(
|
||||
"""
|
||||
import kotlin.test.Test
|
||||
|
||||
@@ -536,33 +583,39 @@ class HierarchicalMppIT : BaseGradleIT() {
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
build(":my-lib-foo:compileJvmAndJsMainKotlinMetadata") {
|
||||
assertSuccessful()
|
||||
}
|
||||
build(":my-lib-foo:compileJvmAndJsMainKotlinMetadata")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testHmppDependenciesInJsTests() {
|
||||
val thirdPartyRepo = publishThirdPartyLib(withGranularMetadata = true).projectDir.parentFile.resolve("repo")
|
||||
with(Project("hierarchical-mpp-js-test")) {
|
||||
@GradleTest
|
||||
@DisplayName("HMPP dependencies in js tests")
|
||||
fun testHmppDependenciesInJsTests(gradleVersion: GradleVersion, @TempDir tempDir: Path) {
|
||||
publishThirdPartyLib(
|
||||
withGranularMetadata = true,
|
||||
gradleVersion = gradleVersion,
|
||||
localRepoDir = tempDir
|
||||
)
|
||||
with(project("hierarchical-mpp-js-test", gradleVersion)) {
|
||||
val taskToExecute = ":jsNodeTest"
|
||||
build(taskToExecute, "-PthirdPartyRepo=$thirdPartyRepo") {
|
||||
assertSuccessful()
|
||||
build(taskToExecute, "-PthirdPartyRepo=${tempDir.absolutePathString()}") {
|
||||
assertTasksExecuted(taskToExecute)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testProcessingDependencyDeclaredInNonRootSourceSet() {
|
||||
publishThirdPartyLib(withGranularMetadata = true)
|
||||
@GradleTest
|
||||
@DisplayName("Processing dependency declared in non root sourceSet")
|
||||
fun testProcessingDependencyDeclaredInNonRootSourceSet(gradleVersion: GradleVersion, @TempDir tempDir: Path) {
|
||||
publishThirdPartyLib(withGranularMetadata = true, gradleVersion = gradleVersion, localRepoDir = tempDir)
|
||||
|
||||
transformNativeTestProjectWithPluginDsl("my-lib-foo", gradleVersion, "hierarchical-mpp-published-modules").run {
|
||||
nativeProject(
|
||||
"my-lib-foo".withPrefix,
|
||||
gradleVersion = gradleVersion,
|
||||
localRepoDir = tempDir,
|
||||
buildOptions = defaultBuildOptions.copy(logLevel = LogLevel.DEBUG)
|
||||
).run {
|
||||
val intermediateMetadataCompileTask = ":compileJvmAndJsMainKotlinMetadata"
|
||||
|
||||
build(intermediateMetadataCompileTask) {
|
||||
assertSuccessful()
|
||||
|
||||
checkNamesOnCompileClasspath(
|
||||
intermediateMetadataCompileTask,
|
||||
shouldInclude = listOf(
|
||||
@@ -573,11 +626,16 @@ class HierarchicalMppIT : BaseGradleIT() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDependenciesInNonPublishedSourceSets() {
|
||||
publishThirdPartyLib(withGranularMetadata = true)
|
||||
@GradleTest
|
||||
@DisplayName("Check dependencies in non published sourceSets")
|
||||
fun testDependenciesInNonPublishedSourceSets(gradleVersion: GradleVersion, @TempDir tempDir: Path) {
|
||||
publishThirdPartyLib(withGranularMetadata = true, gradleVersion = gradleVersion, localRepoDir = tempDir)
|
||||
|
||||
transformNativeTestProjectWithPluginDsl("my-lib-foo", gradleVersion, "hierarchical-mpp-published-modules").run {
|
||||
nativeProject(
|
||||
"my-lib-foo".withPrefix,
|
||||
gradleVersion = gradleVersion,
|
||||
localRepoDir = tempDir
|
||||
).run {
|
||||
testDependencyTransformations { reports ->
|
||||
reports.single {
|
||||
it.sourceSetName == "jvmAndJsMain" && it.scope == "api" && it.groupAndModule.startsWith("com.example")
|
||||
@@ -589,23 +647,30 @@ class HierarchicalMppIT : BaseGradleIT() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testTransitiveDependencyOnSelf() = with(Project("transitive-dep-on-self-hmpp")) {
|
||||
testDependencyTransformations(subproject = "lib") { reports ->
|
||||
reports.single {
|
||||
it.sourceSetName == "commonTest" && it.scope == "implementation" && "libtests" in it.groupAndModule
|
||||
}.let {
|
||||
assertEquals(setOf("commonMain", "jvmAndJsMain"), it.allVisibleSourceSets)
|
||||
@GradleTest
|
||||
@DisplayName("Check transitive dependency on self")
|
||||
fun testTransitiveDependencyOnSelf(gradleVersion: GradleVersion) =
|
||||
with(project("transitive-dep-on-self-hmpp", gradleVersion = gradleVersion)) {
|
||||
testDependencyTransformations(subproject = "lib") { reports ->
|
||||
reports.single {
|
||||
it.sourceSetName == "commonTest" && it.scope == "implementation" && "libtests" in it.groupAndModule
|
||||
}.let {
|
||||
assertEquals(setOf("commonMain", "jvmAndJsMain"), it.allVisibleSourceSets)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMixedScopesFilesExistKt44845() {
|
||||
publishThirdPartyLib(withGranularMetadata = true)
|
||||
@GradleTest
|
||||
@DisplayName("KT-44845: all external dependencies is unresolved in IDE with kotlin.mpp.enableGranularSourceSetsMetadata=true")
|
||||
fun testMixedScopesFilesExistKt44845(gradleVersion: GradleVersion, @TempDir tempDir: Path) {
|
||||
publishThirdPartyLib(withGranularMetadata = true, gradleVersion = gradleVersion, localRepoDir = tempDir)
|
||||
|
||||
transformNativeTestProjectWithPluginDsl("my-lib-foo", gradleVersion, "hierarchical-mpp-published-modules").run {
|
||||
gradleBuildScript().appendText(
|
||||
nativeProject(
|
||||
"my-lib-foo".withPrefix,
|
||||
gradleVersion,
|
||||
localRepoDir = tempDir
|
||||
).run {
|
||||
buildGradleKts.appendText(
|
||||
"""
|
||||
${"\n"}
|
||||
dependencies {
|
||||
@@ -617,15 +682,19 @@ class HierarchicalMppIT : BaseGradleIT() {
|
||||
|
||||
testDependencyTransformations { reports ->
|
||||
val reportsForJvmAndJsMain = reports.filter { it.sourceSetName == "jvmAndJsMain" }
|
||||
val thirdPartyLib = reportsForJvmAndJsMain.single {
|
||||
val thirdPartyLib = reportsForJvmAndJsMain.singleOrNull {
|
||||
it.scope == "api" && it.groupAndModule.startsWith("com.example")
|
||||
}
|
||||
val coroutinesCore = reportsForJvmAndJsMain.single {
|
||||
val coroutinesCore = reportsForJvmAndJsMain.singleOrNull {
|
||||
it.scope == "implementation" && it.groupAndModule.contains("kotlinx-coroutines-core")
|
||||
}
|
||||
val serialization = reportsForJvmAndJsMain.single {
|
||||
val serialization = reportsForJvmAndJsMain.singleOrNull {
|
||||
it.scope == "compileOnly" && it.groupAndModule.contains("kotlinx-serialization-json")
|
||||
}
|
||||
assertNotNull(thirdPartyLib, "Expected report for third-party-lib")
|
||||
assertNotNull(coroutinesCore, "Expected report for kotlinx-coroutines-core")
|
||||
assertNotNull(serialization, "Expected report for kotlinx-serialization-json")
|
||||
|
||||
listOf(thirdPartyLib, coroutinesCore, serialization).forEach { report ->
|
||||
assertTrue(report.newVisibleSourceSets.isNotEmpty(), "Expected visible source sets for $report")
|
||||
assertTrue(report.useFiles.isNotEmpty(), "Expected non-empty useFiles for $report")
|
||||
@@ -635,9 +704,10 @@ class HierarchicalMppIT : BaseGradleIT() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNativeLeafTestSourceSetsKt46417() {
|
||||
with(Project("kt-46417-ios-test-source-sets")) {
|
||||
@GradleTest
|
||||
@DisplayName("KT-46417: [UNRESOLVED_REFERENCE] For project to project dependencies of native platform test source sets")
|
||||
fun testNativeLeafTestSourceSetsKt46417(gradleVersion: GradleVersion) {
|
||||
with(project("kt-46417-ios-test-source-sets", gradleVersion = gradleVersion)) {
|
||||
testDependencyTransformations("p2") { reports ->
|
||||
val report = reports.singleOrNull { it.sourceSetName == "iosArm64Test" && it.scope == "implementation" }
|
||||
assertNotNull(report, "No single report for 'iosArm64' and implementation scope")
|
||||
@@ -647,12 +717,12 @@ class HierarchicalMppIT : BaseGradleIT() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun Project.testDependencyTransformations(
|
||||
private fun TestProject.testDependencyTransformations(
|
||||
subproject: String? = null,
|
||||
check: CompiledProject.(reports: Iterable<DependencyTransformationReport>) -> Unit
|
||||
check: BuildResult.(reports: Iterable<DependencyTransformationReport>) -> Unit
|
||||
) {
|
||||
setupWorkingDir()
|
||||
val buildGradleKts = gradleBuildScript(subproject)
|
||||
val buildGradleKts = (subproject?.let { subProject(subproject).buildGradleKts } ?: buildGradleKts).toFile()
|
||||
assert(buildGradleKts.exists()) { "Kotlin scripts are not found." }
|
||||
assert(buildGradleKts.extension == "kts") { "Only Kotlin scripts are supported." }
|
||||
|
||||
val testTaskName = "reportDependencyTransformationsForTest"
|
||||
@@ -695,8 +765,6 @@ class HierarchicalMppIT : BaseGradleIT() {
|
||||
}
|
||||
|
||||
build(":${subproject?.plus(":").orEmpty()}$testTaskName") {
|
||||
assertSuccessful()
|
||||
|
||||
val reports = output.lines()
|
||||
.filter { DependencyTransformationReport.TEST_OUTPUT_MARKER in it }
|
||||
.map { DependencyTransformationReport.parseTestOutputLine(it) }
|
||||
@@ -705,7 +773,7 @@ class HierarchicalMppIT : BaseGradleIT() {
|
||||
}
|
||||
}
|
||||
|
||||
private data class DependencyTransformationReport(
|
||||
internal data class DependencyTransformationReport(
|
||||
val sourceSetName: String,
|
||||
val scope: String,
|
||||
val groupAndModule: String,
|
||||
|
||||
+2
-1
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.gradle.util.modify
|
||||
import java.io.File
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
import kotlin.io.path.createFile
|
||||
import kotlin.io.path.exists
|
||||
|
||||
internal fun Path.applyAndroidTestFixes() {
|
||||
@@ -17,7 +18,7 @@ internal fun Path.applyAndroidTestFixes() {
|
||||
assert(keystoreFile.exists()) {
|
||||
"Common 'debug.keystore' file does not exists in ${keystoreFile.toAbsolutePath()} location!"
|
||||
}
|
||||
resolve("gradle.properties").append(
|
||||
resolve("gradle.properties").also { if (!it.exists()) it.createFile() }.append(
|
||||
"""
|
||||
|test.fixes.android.debugKeystore=${keystoreFile.toAbsolutePath().toString().normalizePath()}
|
||||
|
|
||||
|
||||
+7
@@ -20,6 +20,13 @@ fun BuildResult.assertTasksExecuted(vararg tasks: String) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts given [tasks] have 'SUCCESS' execution state.
|
||||
*/
|
||||
fun BuildResult.assertTasksExecuted(tasks: Collection<String>) {
|
||||
assertTasksExecuted(*tasks.toTypedArray())
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts given [tasks] have 'FAILED' execution state.
|
||||
*/
|
||||
|
||||
+71
-6
@@ -12,7 +12,11 @@ import org.gradle.util.GradleVersion
|
||||
import org.jetbrains.kotlin.gradle.BaseGradleIT.Companion.acceptAndroidSdkLicenses
|
||||
import org.jetbrains.kotlin.gradle.model.ModelContainer
|
||||
import org.jetbrains.kotlin.gradle.model.ModelFetcherBuildAction
|
||||
import org.jetbrains.kotlin.gradle.native.disableKotlinNativeCaches
|
||||
import org.jetbrains.kotlin.gradle.util.modify
|
||||
import org.jetbrains.kotlin.gradle.report.BuildReportType
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
import org.jetbrains.kotlin.konan.target.presetName
|
||||
import org.jetbrains.kotlin.test.util.KtTestUtil
|
||||
import java.io.File
|
||||
import java.nio.file.*
|
||||
@@ -36,17 +40,19 @@ fun KGPBaseTest.project(
|
||||
enableGradleDebug: Boolean = false,
|
||||
projectPathAdditionalSuffix: String = "",
|
||||
buildJdk: File? = null,
|
||||
test: TestProject.() -> Unit
|
||||
localRepoDir: Path? = null,
|
||||
test: TestProject.() -> Unit = {}
|
||||
): TestProject {
|
||||
val projectPath = setupProjectFromTestResources(
|
||||
projectName,
|
||||
gradleVersion,
|
||||
workingDir,
|
||||
projectPathAdditionalSuffix
|
||||
projectPathAdditionalSuffix,
|
||||
)
|
||||
projectPath.addDefaultBuildFiles()
|
||||
projectPath.enableCacheRedirector()
|
||||
projectPath.enableAndroidSdk()
|
||||
|
||||
if (addHeapDumpOptions) projectPath.addHeapDumpOptions()
|
||||
|
||||
val gradleRunner = GradleRunner
|
||||
@@ -65,13 +71,51 @@ fun KGPBaseTest.project(
|
||||
forceOutput,
|
||||
enableBuildScan
|
||||
)
|
||||
|
||||
localRepoDir?.let { testProject.configureLocalRepository(localRepoDir) }
|
||||
if (buildJdk != null) testProject.setupNonDefaultJdk(buildJdk)
|
||||
|
||||
testProject.test()
|
||||
return testProject
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new test project with configuring single native target.
|
||||
*
|
||||
* @param [projectName] test project name in 'src/test/resources/testProject` directory.
|
||||
* @param [buildOptions] common Gradle build options
|
||||
* @param [buildJdk] path to JDK build should run with. *Note* Only append to 'gradle.properties'!
|
||||
*/
|
||||
fun KGPBaseTest.nativeProject(
|
||||
projectName: String,
|
||||
gradleVersion: GradleVersion,
|
||||
buildOptions: BuildOptions = defaultBuildOptions,
|
||||
forceOutput: Boolean = false,
|
||||
enableBuildScan: Boolean = false,
|
||||
addHeapDumpOptions: Boolean = true,
|
||||
enableGradleDebug: Boolean = false,
|
||||
projectPathAdditionalSuffix: String = "",
|
||||
buildJdk: File? = null,
|
||||
localRepoDir: Path? = null,
|
||||
test: TestProject.() -> Unit = {}
|
||||
): TestProject {
|
||||
val project = project(
|
||||
projectName = projectName,
|
||||
gradleVersion = gradleVersion,
|
||||
buildOptions = buildOptions,
|
||||
forceOutput = forceOutput,
|
||||
enableBuildScan = enableBuildScan,
|
||||
addHeapDumpOptions = addHeapDumpOptions,
|
||||
enableGradleDebug = enableGradleDebug,
|
||||
projectPathAdditionalSuffix = projectPathAdditionalSuffix,
|
||||
buildJdk = buildJdk,
|
||||
localRepoDir = localRepoDir,
|
||||
)
|
||||
project.configureSingleNativeTarget()
|
||||
project.disableKotlinNativeCaches()
|
||||
project.test()
|
||||
return project
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger test project build with given [buildArguments] and assert build is successful.
|
||||
*/
|
||||
@@ -204,6 +248,7 @@ open class GradleProject(
|
||||
val settingsGradle: Path get() = projectPath.resolve("settings.gradle")
|
||||
val settingsGradleKts: Path get() = projectPath.resolve("settings.gradle.kts")
|
||||
val gradleProperties: Path get() = projectPath.resolve("gradle.properties")
|
||||
val buildFileNames: Set<String> get() = setOf("build.gradle", "build.gradle.kts", "settings.gradle", "settings.gradle.kts")
|
||||
|
||||
fun classesDir(
|
||||
sourceSet: String = "main",
|
||||
@@ -324,11 +369,11 @@ private fun setupProjectFromTestResources(
|
||||
projectName: String,
|
||||
gradleVersion: GradleVersion,
|
||||
tempDir: Path,
|
||||
optionalSubDir: String
|
||||
optionalSubDir: String,
|
||||
): Path {
|
||||
val testProjectPath = projectName.testProjectPath
|
||||
assertTrue("Test project exists") { Files.exists(testProjectPath) }
|
||||
assertTrue("Test project path is a directory") { Files.isDirectory(testProjectPath) }
|
||||
assertTrue("Test project doesn't exists") { Files.exists(testProjectPath) }
|
||||
assertTrue("Test project path isn't a directory") { Files.isDirectory(testProjectPath) }
|
||||
|
||||
return tempDir
|
||||
.resolve(gradleVersion.version)
|
||||
@@ -535,3 +580,23 @@ private fun Path.addHeapDumpOptions() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private const val SINGLE_NATIVE_TARGET_PLACEHOLDER = "<SingleNativeTarget>"
|
||||
private const val LOCAL_REPOSITORY_PLACEHOLDER = "<localRepo>"
|
||||
|
||||
private fun TestProject.configureSingleNativeTarget(preset: String = HostManager.host.presetName) {
|
||||
val buildScript = if (buildGradle.exists()) buildGradle else buildGradleKts
|
||||
buildScript.modify {
|
||||
it.replace(SINGLE_NATIVE_TARGET_PLACEHOLDER, preset)
|
||||
}
|
||||
}
|
||||
|
||||
private fun TestProject.configureLocalRepository(localRepoDir: Path) {
|
||||
projectPath.toFile().walkTopDown()
|
||||
.filter { it.isFile && it.name in buildFileNames }
|
||||
.forEach { file ->
|
||||
file.modify { it.replace(LOCAL_REPOSITORY_PLACEHOLDER, localRepoDir.absolutePathString().replace("\\", "\\\\")) }
|
||||
}
|
||||
}
|
||||
|
||||
internal fun TestProject.disableKotlinNativeCaches() = gradleProperties.toFile().disableKotlinNativeCaches()
|
||||
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
plugins {
|
||||
kotlin("multiplatform").version("<pluginMarkerVersion>").apply(false)
|
||||
kotlin("multiplatform").apply(false)
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
maven("$rootDir/../repo")
|
||||
maven("<localRepo>")
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -90,6 +90,6 @@ kotlin {
|
||||
|
||||
publishing {
|
||||
repositories {
|
||||
maven("$rootDir/../repo")
|
||||
maven("<localRepo>")
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -95,6 +95,6 @@ kotlin {
|
||||
|
||||
publishing {
|
||||
repositories {
|
||||
maven("$rootDir/../repo")
|
||||
maven("<localRepo>")
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
plugins {
|
||||
kotlin("multiplatform").version("<pluginMarkerVersion>")
|
||||
kotlin("multiplatform")
|
||||
`maven-publish`
|
||||
}
|
||||
|
||||
@@ -52,6 +52,6 @@ kotlin {
|
||||
|
||||
publishing {
|
||||
repositories {
|
||||
maven("../repo")
|
||||
maven("<localRepo>")
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
plugins {
|
||||
kotlin("multiplatform").version("<pluginMarkerVersion>")
|
||||
kotlin("multiplatform")
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
maven("../repo")
|
||||
maven("<localRepo>")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -1,11 +1,11 @@
|
||||
plugins {
|
||||
kotlin("multiplatform").version("<pluginMarkerVersion>")
|
||||
kotlin("multiplatform")
|
||||
`maven-publish`
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
maven("../repo")
|
||||
maven("<localRepo>")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
@@ -91,6 +91,6 @@ kotlin {
|
||||
|
||||
publishing {
|
||||
repositories {
|
||||
maven("../repo")
|
||||
maven("<localRepo>")
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -1,11 +1,11 @@
|
||||
plugins {
|
||||
kotlin("multiplatform").version("<pluginMarkerVersion>")
|
||||
kotlin("multiplatform")
|
||||
`maven-publish`
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
maven("../repo")
|
||||
maven("<localRepo>")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
@@ -103,6 +103,6 @@ kotlin {
|
||||
|
||||
publishing {
|
||||
repositories {
|
||||
maven("../repo")
|
||||
maven("<localRepo>")
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
plugins {
|
||||
kotlin("multiplatform").version("<pluginMarkerVersion>")
|
||||
kotlin("multiplatform")
|
||||
`maven-publish`
|
||||
}
|
||||
|
||||
@@ -52,6 +52,6 @@ kotlin {
|
||||
|
||||
publishing {
|
||||
repositories {
|
||||
maven("../repo")
|
||||
maven("<localRepo>")
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
plugins {
|
||||
kotlin("multiplatform").version("<pluginMarkerVersion>").apply(false)
|
||||
kotlin("multiplatform").apply(false)
|
||||
}
|
||||
|
||||
allprojects {
|
||||
|
||||
+3
-3
@@ -1,11 +1,11 @@
|
||||
plugins {
|
||||
kotlin("multiplatform").version("<pluginMarkerVersion>")
|
||||
kotlin("multiplatform")
|
||||
`maven-publish`
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
maven("../repo")
|
||||
maven("<localRepo>")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
@@ -33,6 +33,6 @@ kotlin {
|
||||
|
||||
publishing {
|
||||
repositories {
|
||||
maven("../repo")
|
||||
maven("<localRepo>")
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
plugins {
|
||||
kotlin("js").version("<pluginMarkerVersion>")
|
||||
kotlin("js")
|
||||
`maven-publish`
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ kotlin {
|
||||
|
||||
publishing {
|
||||
repositories {
|
||||
maven("../repo")
|
||||
maven("<localRepo>")
|
||||
}
|
||||
publications {
|
||||
create<MavenPublication>("maven") {
|
||||
|
||||
Reference in New Issue
Block a user