diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/dependencyResolutionTests/MaveRepositoryMock.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/dependencyResolutionTests/MaveRepositoryMock.kt new file mode 100644 index 00000000000..f8f16dcb04f --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/dependencyResolutionTests/MaveRepositoryMock.kt @@ -0,0 +1,69 @@ +/* + * Copyright 2010-2024 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.dependencyResolutionTests + +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension +import org.jetbrains.kotlin.gradle.plugin.KotlinTarget +import java.io.File + +fun KotlinMultiplatformExtension.publishAsMockedLibrary(repoDir: File, name: String, version: String) { + val moduleRootDir = repoDir.resolve("test/$name/$version") + moduleRootDir.mkdirs() + val moduleFile = moduleRootDir.resolve("$name-$version.module") + moduleFile.writeText(publishedMockedGradleMetadata(name, version)) + val pomFile = moduleFile.parentFile.resolve("$name-$version.pom") + pomFile.writeText( + """ + + + 4.0.0 + test + $name + $version + + """.trimIndent() + ) +} + +private fun KotlinMultiplatformExtension.publishedMockedGradleMetadata(name: String, version: String): String { + val variants = targets.joinToString(",") { it.variantJson() + "\n" } + return """ + { + "formatVersion": "1.1", + "component": { + "group": "test", + "module": "$name", + "version": "$version", + "attributes": { + "org.gradle.status": "release" + } + }, + "variants": [ + $variants + ] + } + """.trimIndent() +} + +private fun KotlinTarget.variantJson(): String { + val apiElements = project.configurations.getByName(apiElementsConfigurationName) + val attributesString = apiElements + .attributes + .keySet() + .map { it to apiElements.attributes.getAttribute(it) } + .joinToString(",\n") { "\"${it.first.name}\": \"${it.second}\"" } + + return """ + { + "name": "$name", + "attributes": { + $attributesString + } + } + """.trimIndent() +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/dependencyResolutionTests/SourceSetDependenciesResolution.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/dependencyResolutionTests/SourceSetDependenciesResolution.kt new file mode 100644 index 00000000000..091b50f805d --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/dependencyResolutionTests/SourceSetDependenciesResolution.kt @@ -0,0 +1,87 @@ +/* + * Copyright 2010-2024 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.dependencyResolutionTests + +import org.gradle.api.Project +import org.gradle.kotlin.dsl.maven +import org.jetbrains.kotlin.gradle.dsl.kotlinExtension +import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension +import org.jetbrains.kotlin.gradle.dsl.platformTargets +import org.jetbrains.kotlin.gradle.plugin.mpp.resolvableMetadataConfiguration +import org.jetbrains.kotlin.gradle.plugin.sources.internal +import org.jetbrains.kotlin.gradle.util.* +import org.jetbrains.kotlin.test.KotlinTestUtils +import org.junit.Rule +import org.junit.rules.TemporaryFolder + +abstract class SourceSetDependenciesResolution { + @get:Rule + val tempFolder = TemporaryFolder() + + class SourceSetDependenciesDsl( + private val project: Project + ) { + val declaredDependencies = mutableSetOf>() // list of name + versions + + /** + * Declares an API dependency to test:[name]:[version] for [sourceSetName] source set + */ + fun api(sourceSetName: String, name: String, version: String) { + declaredDependencies.add(name to version) + project.kotlinExtension.sourceSets.getByName(sourceSetName).dependencies { api("test:$name:$version") } + } + } + + fun assertSourceSetDependenciesResolution(expectedFilePath: String, configure: SourceSetDependenciesDsl.(Project) -> Unit) { + val repoRoot = tempFolder.newFolder() + val project = buildProject { + enableDefaultStdlibDependency(false) + enableDependencyVerification(false) + applyMultiplatformPlugin() + + repositories.maven(repoRoot) + } + + val dsl = SourceSetDependenciesDsl(project) + dsl.configure(project) + + dsl.declaredDependencies.forEach { project.multiplatformExtension.publishAsMockedLibrary(repoRoot, it.first, it.second) } + + project.evaluate() + + val actualResult = project.resolveAllSourceSetDependencies() + val expectedFile = resourcesRoot.resolve("dependenciesResolution").resolve(expectedFilePath) + KotlinTestUtils.assertEqualsToFile(expectedFile, actualResult) + } + + private fun Project.resolveAllSourceSetDependencies(): String { + val allSourceSets = multiplatformExtension.sourceSets.toSet() + + val platformSpecificSourceSets = multiplatformExtension + .targets + .platformTargets + .flatMap { it.compilations } + .associate { it.defaultSourceSet to configurations.getByName(it.compileDependencyConfigurationName) } + + val commonSourceSetsWithoutMetadataCompilation = allSourceSets + .minus(platformSpecificSourceSets.keys) + .associateWith { it.internal.resolvableMetadataConfiguration } + + val actual = (platformSpecificSourceSets + commonSourceSetsWithoutMetadataCompilation).mapValues { (_, configuration) -> + val resolutionResult = configuration.incoming.resolutionResult + val rootComponent = resolutionResult.root + val dependencies = resolutionResult.allComponents + .minus(rootComponent) + .map { it.id.displayName } + .sorted() + dependencies.joinToString("\n") { " $it" } + }.entries.sortedBy { (sourceSet, _) -> sourceSet.name }.joinToString("\n") { + it.key.name + "\n" + it.value + } + + return actual + } +} \ No newline at end of file