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