diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/CommonizerIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/CommonizerIT.kt index c16c73b3299..efe4681eadf 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/CommonizerIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/CommonizerIT.kt @@ -1,71 +1,76 @@ /* - * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2023 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 -import groovy.json.StringEscapeUtils -import org.gradle.api.logging.LogLevel.INFO +import org.gradle.api.logging.LogLevel import org.gradle.internal.os.OperatingSystem +import org.gradle.testkit.runner.BuildResult +import org.gradle.util.GradleVersion import org.jetbrains.kotlin.commonizer.CommonizerTarget +import org.jetbrains.kotlin.gradle.testbase.* +import org.jetbrains.kotlin.gradle.util.replaceText import org.jetbrains.kotlin.gradle.util.reportSourceSetCommonizerDependencies import org.jetbrains.kotlin.incremental.testingUtils.assertEqualDirectories import org.jetbrains.kotlin.konan.target.HostManager import org.jetbrains.kotlin.konan.target.KonanTarget.* -import kotlin.test.Test -import kotlin.test.assertFalse +import org.junit.jupiter.api.DisplayName +import kotlin.io.path.* import kotlin.test.assertTrue import kotlin.test.fail -open class CommonizerIT : BaseGradleIT() { - override val defaultGradleVersion: GradleVersionRequired = GradleVersionRequired.FOR_MPP_SUPPORT + +@DisplayName("K/N tests for commonizer") +@NativeGradlePluginTests +open class CommonizerIT : KGPBaseTest() { companion object { private const val commonizerOutput = "Preparing commonized Kotlin/Native libraries" } - @Test - fun `test commonizeNativeDistributionWithIosLinuxWindows`() { - with(Project("commonizeNativeDistributionWithIosLinuxWindows")) { - build(":cleanNativeDistributionCommonization") { - assertSuccessful() - } + @DisplayName("Commonize native distribution with Ios Linux and Windows") + @GradleTest + fun testCommonizeNativeDistributionWithIosLinuxWindows(gradleVersion: GradleVersion) { + nativeProject("commonizeNativeDistributionWithIosLinuxWindows", gradleVersion) { + + build(":cleanNativeDistributionCommonization") build("commonize", "-Pkotlin.mpp.enableNativeDistributionCommonizationCache=false") { assertTasksExecuted(":commonizeNativeDistribution") - assertContains(commonizerOutput) - assertSuccessful() + assertOutputContains(commonizerOutput) } build("commonize", "-Pkotlin.mpp.enableNativeDistributionCommonizationCache=true") { assertTasksUpToDate(":commonizeNativeDistribution") assertNativeDistributionCommonizationCacheHit() - assertContains("Native Distribution Commonization: All available targets are commonized already") - assertContains("Native Distribution Commonization: Lock acquired") - assertContains("Native Distribution Commonization: Lock released") - assertNotContains(commonizerOutput) - assertSuccessful() + assertOutputContains("Native Distribution Commonization: All available targets are commonized already") + assertOutputContains("Native Distribution Commonization: Lock acquired") + assertOutputContains("Native Distribution Commonization: Lock released") + assertOutputDoesNotContain(commonizerOutput) } build("commonize", "-Pkotlin.mpp.enableNativeDistributionCommonizationCache=false") { assertTasksExecuted(":commonizeNativeDistribution") - assertContains("Native Distribution Commonization: Cache disabled") - assertContains(commonizerOutput) - assertSuccessful() + assertOutputContains("Native Distribution Commonization: Cache disabled") + assertOutputContains(commonizerOutput) } } } - @Test - fun `test commonizeCurlInterop UP-TO-DATE check`() { - with(preparedProject("commonizeCurlInterop")) { + @DisplayName("Commonize Curl Interop UP-TO-DATE check") + @GradleTest + fun testCommonizeCurlInteropUTDCheck(gradleVersion: GradleVersion) { + nativeProject("commonizeCurlInterop", gradleVersion) { + + configureCommonizerTargets() + build(":commonize") { assertTasksExecuted(":commonizeNativeDistribution") assertTasksExecuted(":cinteropCurlTargetA") assertTasksExecuted(":cinteropCurlTargetB") assertTasksExecuted(":commonizeCInterop") - assertSuccessful() } build(":commonize") { @@ -73,38 +78,37 @@ open class CommonizerIT : BaseGradleIT() { assertTasksUpToDate(":cinteropCurlTargetA") assertTasksUpToDate(":cinteropCurlTargetB") assertTasksUpToDate(":commonizeCInterop") - assertSuccessful() } - val buildGradleKts = projectFile("build.gradle.kts") - val originalBuildGradleKtsContent = buildGradleKts.readText() - - buildGradleKts.writeText(originalBuildGradleKtsContent.replace("curl", "curl2")) + buildGradleKts.replaceText("curl", "curl2") build(":commonize") { assertNativeDistributionCommonizationCacheHit() assertTasksExecuted(":cinteropCurl2TargetA") assertTasksExecuted(":cinteropCurl2TargetB") assertTasksExecuted(":commonizeCInterop") - assertSuccessful() } - buildGradleKts.writeText(originalBuildGradleKtsContent.lineSequence().filter { "curl" !in it }.joinToString("\n")) + buildGradleKts.modify { + it.lineSequence().filter { "curl" !in it }.joinToString("\n") + } build(":commonize") { assertNativeDistributionCommonizationCacheHit() assertTasksNotExecuted(":cinteropCurlTargetA") assertTasksNotExecuted(":cinteropCurlTargetB") - assertSuccessful() } } } - @Test - fun `test commonizeCurlInterop feature flag`() { - with(preparedProject("commonizeCurlInterop")) { - setupWorkingDir() + @DisplayName("Commonize Curl Interop feature flag") + @GradleTest + fun testCommonizeCurlInteropFeatureFlag(gradleVersion: GradleVersion) { + nativeProject("commonizeCurlInterop", gradleVersion) { + + configureCommonizerTargets() + // Remove feature flag from gradle.properties - projectFile("gradle.properties").apply { - writeText(readText().lineSequence().filter { "enableCInteropCommonization" !in it }.joinToString("\n")) + gradleProperties.modify { + it.lineSequence().filter { "enableCInteropCommonization" !in it }.joinToString("\n") } build(":commonize") { @@ -112,7 +116,6 @@ open class CommonizerIT : BaseGradleIT() { assertTasksNotExecuted(":cinteropCurl2TargetA") assertTasksNotExecuted(":cinteropCurl2TargetB") assertTasksNotExecuted(":commonizeCInterop") - assertSuccessful() } build(":commonize", "-Pkotlin.mpp.enableCInteropCommonization=true") { @@ -120,7 +123,6 @@ open class CommonizerIT : BaseGradleIT() { assertTasksExecuted(":cinteropCurlTargetA") assertTasksExecuted(":cinteropCurlTargetB") assertTasksExecuted(":commonizeCInterop") - assertSuccessful() } build(":commonize", "-Pkotlin.mpp.enableCInteropCommonization=false") { @@ -128,64 +130,67 @@ open class CommonizerIT : BaseGradleIT() { assertTasksNotExecuted(":cinteropCurlTargetA") assertTasksNotExecuted(":cinteropCurlTargetB") assertTasksNotExecuted(":commonizeCInterop") - assertSuccessful() } } } - @Test - fun `test commonizeCurlInterop copyCommonizeCInteropForIde`() { - with(preparedProject("commonizeCurlInterop")) { - setupWorkingDir() - val expectedOutputDirectoryForIde = projectDir.resolve(".gradle/kotlin/commonizer") - val expectedOutputDirectoryForBuild = projectDir.resolve("build/classes/kotlin/commonizer") + + @DisplayName("Commonize Curl Interop copy CommonizeCInterop for Ide") + @GradleTest + fun testCommonizeCurlInteropcopyCommonizeCInteropForIde(gradleVersion: GradleVersion) { + nativeProject("commonizeCurlInterop", gradleVersion) { + + configureCommonizerTargets() + + val expectedOutputDirectoryForIde = projectPath.resolve(".gradle/kotlin/commonizer") + val expectedOutputDirectoryForBuild = projectPath.resolve("build/classes/kotlin/commonizer") build(":copyCommonizeCInteropForIde") { - assertSuccessful() - assertTasksExecuted(":cinteropCurlTargetA") assertTasksExecuted(":cinteropCurlTargetB") assertTasksExecuted(":commonizeCInterop") - assertTrue(expectedOutputDirectoryForIde.isDirectory, "Missing output directory for IDE") - assertTrue(expectedOutputDirectoryForBuild.isDirectory, "Missing output directory for build") - assertEqualDirectories(expectedOutputDirectoryForBuild, expectedOutputDirectoryForIde, false) + assertDirectoryExists(expectedOutputDirectoryForIde, "Missing output directory for IDE") + assertDirectoryExists(expectedOutputDirectoryForBuild, "Missing output directory for build") + assertEqualDirectories(expectedOutputDirectoryForBuild.toFile(), expectedOutputDirectoryForIde.toFile(), false) } build(":clean") { - assertSuccessful() - assertTrue(expectedOutputDirectoryForIde.isDirectory, "Expected ide output directory to survive cleaning") - assertFalse(expectedOutputDirectoryForBuild.exists(), "Expected output directory for build to be cleaned") + assertDirectoryExists(expectedOutputDirectoryForIde, "Expected ide output directory to survive cleaning") + assertFileNotExists(expectedOutputDirectoryForBuild, "Expected output directory for build to be cleaned") } } } - @Test - fun `test commonizeCurlInterop compilation`() { - with(preparedProject("commonizeCurlInterop")) { + @DisplayName("Commonize Curl Interop compilation") + @GradleTest + fun testCommonizeCurlInteropCopyCompilation(gradleVersion: GradleVersion) { + nativeProject("commonizeCurlInterop", gradleVersion) { + + configureCommonizerTargets() + build(":compileNativeMainKotlinMetadata") { assertTasksExecuted(":commonizeNativeDistribution") assertTasksExecuted(":cinteropCurlTargetA") assertTasksExecuted(":cinteropCurlTargetB") assertTasksExecuted(":commonizeCInterop") - assertSuccessful() } // targetA will be macos - build(":compileTestKotlinTargetA") { - assertSuccessful() - } + build(":compileTestKotlinTargetA") + //targetB will be linuxArm64 - build(":compileTestKotlinTargetB") { - assertSuccessful() - } + build(":compileTestKotlinTargetB") } } - @Test - fun `test commonizeSQLiteInterop`() { - with(preparedProject("commonizeSQLiteInterop")) { + @DisplayName("Commonize SQL Lite Interop") + @GradleTest + fun testCommonizeSQLiteInterop(gradleVersion: GradleVersion) { + nativeProject("commonizeSQLiteInterop", gradleVersion) { + + configureCommonizerTargets() + build(":commonize") { - assertSuccessful() assertTasksExecuted(":cinteropSqliteTargetA") assertTasksExecuted(":cinteropSqliteTargetB") assertTasksExecuted(":commonizeCInterop") @@ -193,11 +198,14 @@ open class CommonizerIT : BaseGradleIT() { } } - @Test - fun `test commonizeSQLiteAndCurlInterop`() { - with(preparedProject("commonizeSQLiteAndCurlInterop")) { + @DisplayName("Commonize SQL Lite and Curl Interop") + @GradleTest + fun testCommonizeSQLiteAndCurlInterop(gradleVersion: GradleVersion) { + nativeProject("commonizeSQLiteAndCurlInterop", gradleVersion) { + + configureCommonizerTargets() + build(":commonize") { - assertSuccessful() assertTasksExecuted(":cinteropSqliteTargetA") assertTasksExecuted(":cinteropSqliteTargetB") assertTasksExecuted(":cinteropCurlTargetA") @@ -206,7 +214,6 @@ open class CommonizerIT : BaseGradleIT() { } build(":compileNativeMainKotlinMetadata") { - assertSuccessful() assertTasksUpToDate(":cinteropSqliteTargetA") assertTasksUpToDate(":cinteropSqliteTargetB") assertTasksUpToDate(":cinteropCurlTargetA") @@ -216,11 +223,14 @@ open class CommonizerIT : BaseGradleIT() { } } - @Test - fun `test commonizeInterop using posix APIs`() { - with(preparedProject("commonizeInteropUsingPosixApis")) { + @DisplayName("Commonize Interop using posix APIs") + @GradleTest + fun testCommonizeInteropUsingPosixAPIs(gradleVersion: GradleVersion) { + nativeProject("commonizeInteropUsingPosixApis", gradleVersion) { + + configureCommonizerTargets() + build(":commonizeCInterop") { - assertSuccessful() assertTasksExecuted(":cinteropWithPosixTargetA") assertTasksExecuted(":cinteropWithPosixTargetB") assertTasksExecuted(":commonizeNativeDistribution") @@ -228,7 +238,6 @@ open class CommonizerIT : BaseGradleIT() { } build(":compileNativeMainKotlinMetadata") { - assertSuccessful() assertTasksUpToDate(":cinteropWithPosixTargetA") assertTasksUpToDate(":cinteropWithPosixTargetB") assertNativeDistributionCommonizationCacheHit() @@ -237,184 +246,277 @@ open class CommonizerIT : BaseGradleIT() { } } - @Test - fun `test KT-46234 intermediate source set with only one native target`() { - `test single native platform`("commonize-kt-46234-singleNativeTarget") + @DisplayName("KT-46234 intermediate source set with only one native target") + @GradleTest + fun testIntermediateSourceSetWithOnlyOneNativeTarget(gradleVersion: GradleVersion) { + testSingleNativePlatform("commonize-kt-46234-singleNativeTarget", gradleVersion) } - @Test - fun `test KT-46142 standalone native source set`() { - `test single native platform`("commonize-kt-46142-singleNativeTarget") + @DisplayName("KT-46142 standalone native source set") + @GradleTest + fun testStandaloneNativeSourceSet(gradleVersion: GradleVersion) { + testSingleNativePlatform("commonize-kt-46142-singleNativeTarget", gradleVersion) } - private fun `test single native platform`(project: String) { - val posixInIntransitiveMetadataConfigurationRegex = Regex(""".*intransitiveMetadataConfiguration:.*([pP])osix""") - - fun CompiledProject.containsPosixInIntransitiveMetadataConfiguration(): Boolean = - output.lineSequence().any { line -> - line.matches(posixInIntransitiveMetadataConfigurationRegex) - } - - with(Project(project)) { - build(":p1:listNativePlatformMainDependencies", "-Pkotlin.mpp.enableIntransitiveMetadataConfiguration=false") { - assertSuccessful() - - assertFalse( - containsPosixInIntransitiveMetadataConfiguration(), - "Expected **no** dependency on posix in intransitiveMetadataConfiguration" - ) - } - - build(":p1:listNativePlatformMainDependencies", "-Pkotlin.mpp.enableIntransitiveMetadataConfiguration=true") { - assertSuccessful() - - assertTrue( - containsPosixInIntransitiveMetadataConfiguration(), - "Expected dependency on posix in intransitiveMetadataConfiguration" - ) - } - - build("assemble") { - assertSuccessful() - } - } - } - - @Test - fun `test KT-46248 single supported native target dependency propagation`() { - fun CompiledProject.containsPosixDependency(): Boolean = output.lineSequence().any { line -> - line.matches(Regex(""".*Dependency:.*[pP]osix""")) - } - - fun CompiledProject.containsDummyCInteropDependency(): Boolean = output.lineSequence().any { line -> - line.matches(Regex(""".*Dependency:.*cinterop-dummy.*""")) - } - - with(Project("commonize-kt-46248-singleNativeTargetPropagation")) { + @DisplayName("KT-46248 single supported native target dependency propagation") + @GradleTest + fun testSingleSupportedNativeTargetDependencyPropagation(gradleVersion: GradleVersion) { + val posixDependencyRegex = Regex(""".*Dependency:.*[pP]osix""") + val dummyCInteropDependencyRegex = Regex(""".*Dependency:.*cinterop-dummy.*""") + nativeProject("commonize-kt-46248-singleNativeTargetPropagation", gradleVersion) { build(":p1:listNativeMainDependencies") { - assertSuccessful() - assertTrue(containsPosixDependency(), "Expected dependency on posix in nativeMain") - assertTrue(containsDummyCInteropDependency(), "Expected dependency on dummy cinterop in nativeMain") + assertOutputContains(posixDependencyRegex) + assertOutputContains(dummyCInteropDependencyRegex) } build(":p1:listNativeMainParentDependencies") { - assertSuccessful() - assertTrue(containsPosixDependency(), "Expected dependency on posix in nativeMainParent") - assertTrue(containsDummyCInteropDependency(), "Expected dependency on dummy cinterop in nativeMain") + assertOutputContains(posixDependencyRegex) + assertOutputContains(dummyCInteropDependencyRegex) } build(":p1:listCommonMainDependencies") { - assertSuccessful() - assertFalse(containsPosixDependency(), "Expected **no** dependency on posix in commonMain (because of jvm target)") - assertFalse(containsDummyCInteropDependency(), "Expected **no** dependency on dummy cinterop in nativeMain") + assertOutputDoesNotContain(posixDependencyRegex) + assertOutputDoesNotContain(dummyCInteropDependencyRegex) } build("assemble") { - assertSuccessful() assertTasksExecuted(":p1:compileCommonMainKotlinMetadata") assertTasksExecuted(":p1:compileKotlinNativePlatform") } } } - @Test - fun `test KT-46248 single supported native target dependency propagation - cinterop`() { - fun CompiledProject.containsCinteropDependency(): Boolean { - val nativeMainContainsCInteropDependencyRegex = Regex(""".*Dependency:.*cinterop-dummy.*""") - return output.lineSequence().any { line -> - line.matches(nativeMainContainsCInteropDependencyRegex) - } - } - - with(Project("commonize-kt-47523-singleNativeTargetPropagation-cinterop")) { + @DisplayName("KT-46248 single supported native target dependency propagation - cinterop") + @GradleTest + fun testSingleSupportedNativeTargetDependencyPropagationCInterop(gradleVersion: GradleVersion) { + val nativeMainContainsCInteropDependencyRegex = Regex(""".*Dependency:.*cinterop-dummy.*""") + nativeProject("commonize-kt-47523-singleNativeTargetPropagation-cinterop", gradleVersion) { build("listNativePlatformMainDependencies") { - assertSuccessful() - assertFalse( - containsCinteropDependency(), - "Expected sourceSet 'nativeMain' to list cinterop dependency (not necessary, since included in compilation)" - ) + assertOutputDoesNotContain(nativeMainContainsCInteropDependencyRegex) } build("listNativeMainDependencies") { - assertSuccessful() - assertTrue(containsCinteropDependency(), "Expected sourceSet 'nativeMain' to list cinterop dependency") + assertOutputContains(nativeMainContainsCInteropDependencyRegex) } build("listCommonMainDependencies") { - assertSuccessful() - assertTrue(containsCinteropDependency(), "Expected sourceSet 'commonMain' to list cinterop dependency") + assertOutputContains(nativeMainContainsCInteropDependencyRegex) } - build("assemble") { - assertSuccessful() - } + build("assemble") } } - @Test - fun `test KT-48856 single native target dependency propagation - test source set - cinterop`() { - fun CompiledProject.containsCinteropDependency(): Boolean { - val nativeMainContainsCInteropDependencyRegex = Regex(""".*Dependency:.*cinterop-sampleInterop.*""") - return output.lineSequence().any { line -> - line.matches(nativeMainContainsCInteropDependencyRegex) - } - } - - with(Project("commonize-kt-48856-singleNativeTargetPropagation-testSourceSet")) { + @DisplayName("KT-48856 single native target dependency propagation - test source set - cinterop") + @GradleTest + fun testSingleSupportedNativeTargetDependencyPropagationTestSourceSetCInterop(gradleVersion: GradleVersion) { + val nativeMainContainsCInteropDependencyRegex = Regex(""".*Dependency:.*cinterop-sampleInterop.*""") + nativeProject("commonize-kt-48856-singleNativeTargetPropagation-testSourceSet", gradleVersion) { build("listNativeTestDependencies") { - assertSuccessful() - assertTrue(containsCinteropDependency(), "Expected sourceSet 'nativeTest' to list cinterop dependency") + assertOutputContains( + nativeMainContainsCInteropDependencyRegex, + "Expected sourceSet 'nativeTest' to list cinterop dependency" + ) } - build("assemble") { - assertSuccessful() - } + build("assemble") } } - @Test - fun `test KT-46856 filename too long - all native targets configured`() { - with(Project("commonize-kt-46856-all-targets")) { - build(":commonize", options = BuildOptions(forceOutputToStdout = true)) { - assertSuccessful() - } + @DisplayName("KT-46856 filename too long - all native targets configured") + @GradleTest + fun testFilenameTooLongAllNativeTargetsConfigured(gradleVersion: GradleVersion) { + nativeProject("commonize-kt-46856-all-targets", gradleVersion) { + build(":commonize") } } - @Test - fun `test multiple cinterops with test source sets and compilations - test source sets depending on main`() { - `test multiple cinterops with test source sets and compilations`(true) + @DisplayName("Multiple cinterops with test source sets and compilations - test source sets depending on main") + @GradleTest + fun testMultipleCinteropsWithTestSourceSetsAndCompilationsTestSourceSetsDependingOnMain(gradleVersion: GradleVersion) { + `test multiple cinterops with test source sets and compilations`(gradleVersion, true) } - @Test - fun `test multiple cinterops with test source sets and compilations`() { - `test multiple cinterops with test source sets and compilations`(false) + @DisplayName("Multiple cinterops with test source sets and compilations") + @GradleTest + fun testMultipleCinteropsWithTestSourceSetsAndCompilations(gradleVersion: GradleVersion) { + `test multiple cinterops with test source sets and compilations`(gradleVersion, false) } - @Test - fun `test KT-49735 two kotlin targets with same konanTarget`() { - with(Project("commonize-kt-49735-twoKotlinTargets-oneKonanTarget")) { + @DisplayName("KT-49735 two kotlin targets with same konanTarget") + @GradleTest + fun testTwoKotlinTargetsWithSameKonanTarget(gradleVersion: GradleVersion) { + nativeProject("commonize-kt-49735-twoKotlinTargets-oneKonanTarget", gradleVersion) { build(":assemble") { assertTasksExecuted(":compileCommonMainKotlinMetadata") - assertSuccessful() } } } - private fun `test multiple cinterops with test source sets and compilations`(testSourceSetsDependingOnMain: Boolean) { - with(Project("commonizeMultipleCInteropsWithTests", minLogLevel = INFO)) { + @DisplayName("KT-48118 c-interops available in commonMain") + @GradleTest + fun testCInteropsAvailableInCommonMain(gradleVersion: GradleVersion) { + nativeProject("commonize-kt-48118-c-interop-in-common-main", gradleVersion) { + reportSourceSetCommonizerDependencies { + val upperMain = getCommonizerDependencies("upperMain") + upperMain.withoutNativeDistributionDependencies().assertDependencyFilesMatches(".*cinterop-dummy") + upperMain.onlyNativeDistributionDependencies().assertNotEmpty() + + val commonMain = getCommonizerDependencies("commonMain") + commonMain.withoutNativeDistributionDependencies().assertDependencyFilesMatches(".*cinterop-dummy") + commonMain.onlyNativeDistributionDependencies().assertNotEmpty() + } + + build(":compileCommonMainKotlinMetadata") + + build(":compileUpperMainKotlinMetadata") + } + } + + @DisplayName("KT-47641 commonizing c-interops does not depend on any source compilation") + @GradleTest + fun testCInteropsDoesNotDependOnAnySourceCompilation(gradleVersion: GradleVersion) { + nativeProject( + "commonize-kt-47641-cinterops-compilation-dependency", + gradleVersion, + buildOptions = defaultBuildOptions.copy(logLevel = LogLevel.DEBUG) + ) { + build("commonizeCInterop") { + assertTasksExecuted(":p1:commonizeCInterop") + assertTasksExecuted(":p2:commonizeCInterop") + + assertAnyTaskHasBeenExecuted(findTasksByPattern(":p1:cinteropTestWithPosix.*".toRegex())) + assertAnyTaskHasBeenExecuted(findTasksByPattern(":p2:cinteropTestWithPosix.*".toRegex())) + assertAnyTaskHasBeenExecuted(findTasksByPattern(":p2:cinteropTestWithPosixP2.*".toRegex())) + + /* Make sure that we correctly reference any compile tasks in this test (test is useless otherwise) */ + assertOutputContains("Register task :p1.*compile.*".toRegex()) + assertOutputContains("Register task :p2.*compile.*".toRegex()) + + /* CInterops *shall not* require any compilation */ + assertOutputDoesNotContain("(Executing actions for task|Executing task) ':p0.*compile.*'".toRegex()) + assertOutputDoesNotContain("(Executing actions for task|Executing task) ':p1.*compile.*'".toRegex()) + assertOutputDoesNotContain("(Executing actions for task|Executing task) ':p2.*compile.*'".toRegex()) + } + } + } + + @DisplayName("KT-48138 commonizing c-interops when nativeTest and nativeMain have different targets") + @GradleTest + fun testCommonizingCInteropsWhenNativeTestAndNativeMainHaveDifferentTargets(gradleVersion: GradleVersion) { + nativeProject("commonize-kt-48138-nativeMain-nativeTest-different-targets", gradleVersion) { + reportSourceSetCommonizerDependencies { + val nativeMain = getCommonizerDependencies("nativeMain") + nativeMain.withoutNativeDistributionDependencies().assertDependencyFilesMatches(".*cinterop-dummy") + nativeMain.onlyNativeDistributionDependencies().assertNotEmpty() + nativeMain.assertTargetOnAllDependencies(CommonizerTarget(LINUX_X64, LINUX_ARM64, MINGW_X64)) + + val nativeTest = getCommonizerDependencies("nativeTest") + nativeTest.onlyNativeDistributionDependencies().assertNotEmpty() + nativeTest.withoutNativeDistributionDependencies().assertDependencyFilesMatches(".*cinterop-dummy") + nativeTest.assertTargetOnAllDependencies(CommonizerTarget(LINUX_X64, LINUX_ARM64)) + } + } + } + + @DisplayName("KT-50847 missing cinterop in supported target") + @GradleTest + fun testMissingCinteropInSupportedTarget(gradleVersion: GradleVersion) { + nativeProject("commonize-kt-50847-cinterop-missing-in-supported-target", gradleVersion) { + build(":compileCommonMainKotlinMetadata", "-PdisableTargetNumber=1") { + assertTasksSkipped(":cinteropSimpleTarget1") + assertTasksExecuted(":cinteropSimpleTarget2") + assertTasksExecuted(":commonizeCInterop") + } + + build(":compileCommonMainKotlinMetadata", "-PdisableTargetNumber=2") { + assertTasksSkipped(":cinteropSimpleTarget2") + assertTasksExecuted(":cinteropSimpleTarget1") + assertTasksExecuted(":commonizeCInterop") + } + } + } + + @DisplayName("KT-52243 cinterop caching") + @GradleTest + fun testCInteropCaching(gradleVersion: GradleVersion) { + nativeProject("commonizeCurlInterop", gradleVersion) { + + configureCommonizerTargets() + + val localBuildCacheDir = projectPath.resolve("local-build-cache-dir").also { assertTrue(it.toFile().mkdirs()) } + enableLocalBuildCache(localBuildCacheDir) + + build(":commonize", buildOptions = defaultBuildOptions.copy(buildCacheEnabled = true)) { + assertTasksExecuted(":cinteropCurlTargetA", ":cinteropCurlTargetB") + } + build(":clean") {} + build(":commonize", buildOptions = defaultBuildOptions.copy(buildCacheEnabled = true)) { + assertTasksFromCache(":cinteropCurlTargetA", ":cinteropCurlTargetB") + } + } + } + + @DisplayName("KT-51517 commonization with transitive cinterop") + @GradleTest + fun testCommonizationWithTransitiveCinterop(gradleVersion: GradleVersion) { + nativeProject("commonize-kt-51517-transitive-cinterop", gradleVersion) { + build(":app:assemble") { + assertTasksExecuted(":lib:transformCommonMainCInteropDependenciesMetadata") + assertTasksExecuted(":lib:commonizeCInterop") + assertTasksExecuted(":lib:compileCommonMainKotlinMetadata") + assertTasksExecuted(":app:commonizeCInterop") + assertTasksExecuted(":app:compileNativeMainKotlinMetadata") + } + } + } + + @DisplayName("KT-57796 commonization with two cinterop commonizer groups`") + @GradleTest + fun testCommonizationWithTwoCInteropCommonizerGroups(gradleVersion: GradleVersion) { + nativeProject("commonize-kt-57796-twoCInteropCommonizerGroups", gradleVersion) { + build(":app:commonizeCIntero") { + assertTasksExecuted(":lib:transformCommonMainCInteropDependenciesMetadata") + assertTasksExecuted(":lib:commonizeCInterop") + assertTasksExecuted(":app:transformCommonMainCInteropDependenciesMetadata") + assertTasksExecuted(":app:commonizeCInterop") + } + } + } + + @DisplayName("KT-57796 commonization with two cinterop commonizer groups`") + @GradleTest + fun testCommonizationWithLibraryContainingTwoRoots(gradleVersion: GradleVersion) { + project("commonize-kt-56729-consume-library-with-two-roots", gradleVersion) { + build("publish") + + build(":consumer:assemble") { + assertTasksExecuted(":consumer:compileCommonMainKotlinMetadata") + assertOutputDoesNotContain("Duplicated libraries:") + assertOutputDoesNotContain("w: duplicate library name") + } + } + } + + + private fun `test multiple cinterops with test source sets and compilations`( + gradleVersion: GradleVersion, + testSourceSetsDependingOnMain: Boolean, + ) { + nativeProject("commonizeMultipleCInteropsWithTests", gradleVersion) { val isMac = HostManager.hostIsMac - fun CompiledProject.assertTestSourceSetsDependingOnMainParameter() { + fun BuildResult.assertTestSourceSetsDependingOnMainParameter() { val message = "testSourceSetsDependingOnMain is set" - if (testSourceSetsDependingOnMain) assertContains(message) else assertNotContains(message) + if (testSourceSetsDependingOnMain) assertOutputContains(message) else assertOutputDoesNotContain(message) } - val testSourceSetsDependingOnMainParameterOption = defaultBuildOptions() - .withFreeCommandLineArgument("-PtestSourceSetsDependingOnMain=$testSourceSetsDependingOnMain") + val testSourceSetsDependingOnMainParameterOption = defaultBuildOptions.copy( + freeArgs = listOf("-PtestSourceSetsDependingOnMain=$testSourceSetsDependingOnMain") + ) - reportSourceSetCommonizerDependencies(this, options = testSourceSetsDependingOnMainParameterOption) { + reportSourceSetCommonizerDependencies(options = testSourceSetsDependingOnMainParameterOption) { it.assertTestSourceSetsDependingOnMainParameter() /* this source sets are also shared with a jvm target */ @@ -495,208 +597,62 @@ open class CommonizerIT : BaseGradleIT() { getCommonizerDependencies("windowsX64Test").assertEmpty() } - build(":assemble", options = testSourceSetsDependingOnMainParameterOption) { + build(":assemble", buildOptions = testSourceSetsDependingOnMainParameterOption) { assertTestSourceSetsDependingOnMainParameter() - assertSuccessful() assertTasksUpToDate(":commonizeNativeDistribution") - assertContains("Native Distribution Commonization: Cache hit") + assertOutputContains("Native Distribution Commonization: Cache hit") assertTasksUpToDate(":commonizeCInterop") } - build(":compileNativeMainKotlinMetadata", options = testSourceSetsDependingOnMainParameterOption) { + build(":compileNativeMainKotlinMetadata", buildOptions = testSourceSetsDependingOnMainParameterOption) { assertTestSourceSetsDependingOnMainParameter() - assertSuccessful() } - build(":compileUnixMainKotlinMetadata", options = testSourceSetsDependingOnMainParameterOption) { + build(":compileUnixMainKotlinMetadata", buildOptions = testSourceSetsDependingOnMainParameterOption) { assertTestSourceSetsDependingOnMainParameter() - assertSuccessful() } - build(":compileLinuxMainKotlinMetadata", options = testSourceSetsDependingOnMainParameterOption) { + build(":compileLinuxMainKotlinMetadata", buildOptions = testSourceSetsDependingOnMainParameterOption) { assertTestSourceSetsDependingOnMainParameter() - assertSuccessful() } if (isMac) { - build(":compileAppleMainKotlinMetadata", options = testSourceSetsDependingOnMainParameterOption) { + build(":compileAppleMainKotlinMetadata", buildOptions = testSourceSetsDependingOnMainParameterOption) { assertTestSourceSetsDependingOnMainParameter() - assertSuccessful() } - build(":compileIosMainKotlinMetadata", options = testSourceSetsDependingOnMainParameterOption) { + build(":compileIosMainKotlinMetadata", buildOptions = testSourceSetsDependingOnMainParameterOption) { assertTestSourceSetsDependingOnMainParameter() - assertSuccessful() } } } } - @Test - fun `test KT-48118 c-interops available in commonMain`() { - with(Project("commonize-kt-48118-c-interop-in-common-main")) { - reportSourceSetCommonizerDependencies(this) { - val upperMain = getCommonizerDependencies("upperMain") - upperMain.withoutNativeDistributionDependencies().assertDependencyFilesMatches(".*cinterop-dummy") - upperMain.onlyNativeDistributionDependencies().assertNotEmpty() + private fun testSingleNativePlatform(projectName: String, gradleVersion: GradleVersion) { - val commonMain = getCommonizerDependencies("commonMain") - commonMain.withoutNativeDistributionDependencies().assertDependencyFilesMatches(".*cinterop-dummy") - commonMain.onlyNativeDistributionDependencies().assertNotEmpty() + val posixInIntransitiveMetadataConfigurationRegex = Regex(""".*intransitiveMetadataConfiguration:.*([pP])osix""") + + nativeProject(projectName, gradleVersion) { + build(":p1:listNativePlatformMainDependencies", "-Pkotlin.mpp.enableIntransitiveMetadataConfiguration=false") { + assertOutputDoesNotContain(posixInIntransitiveMetadataConfigurationRegex) } - build(":compileCommonMainKotlinMetadata") { - assertSuccessful() + build(":p1:listNativePlatformMainDependencies", "-Pkotlin.mpp.enableIntransitiveMetadataConfiguration=true") { + assertOutputContains(posixInIntransitiveMetadataConfigurationRegex) } - build(":compileUpperMainKotlinMetadata") { - assertSuccessful() - } + build("assemble") } + } - @Test - fun `test KT-47641 commonizing c-interops does not depend on any source compilation`() { - with(Project("commonize-kt-47641-cinterops-compilation-dependency")) { - build("commonizeCInterop", options = BuildOptions(forceOutputToStdout = true)) { - assertTasksExecuted(":p1:commonizeCInterop") - assertTasksExecuted(":p2:commonizeCInterop") - - assertTasksExecuted(":p1:cinteropTestWithPosix.*") - assertTasksExecuted(":p2:cinteropTestWithPosix.*") - assertTasksExecuted(":p2:cinteropTestWithPosixP2.*") - - /* Make sure that we correctly reference any compile tasks in this test (test is useless otherwise) */ - assertTasksRegisteredRegex(":p1.*compile.*") - assertTasksRegisteredRegex(":p2.*compile.*") - - /* CInterops *shall not* require any compilation */ - assertTasksNotExecuted(":p0.*compile.*") - assertTasksNotExecuted(":p1.*compile.*") - assertTasksNotExecuted(":p2.*compile.*") - } - } + private fun TestProject.configureCommonizerTargets() { + buildGradleKts.replaceText("", CommonizableTargets.targetA.value) + buildGradleKts.replaceText("", CommonizableTargets.targetB.value) } - @Test - fun `test KT-48138 commonizing c-interops when nativeTest and nativeMain have different targets`() { - with(Project("commonize-kt-48138-nativeMain-nativeTest-different-targets")) { - reportSourceSetCommonizerDependencies(this) { - val nativeMain = getCommonizerDependencies("nativeMain") - nativeMain.withoutNativeDistributionDependencies().assertDependencyFilesMatches(".*cinterop-dummy") - nativeMain.onlyNativeDistributionDependencies().assertNotEmpty() - nativeMain.assertTargetOnAllDependencies(CommonizerTarget(LINUX_X64, LINUX_ARM64, MINGW_X64)) - - val nativeTest = getCommonizerDependencies("nativeTest") - nativeTest.onlyNativeDistributionDependencies().assertNotEmpty() - nativeTest.withoutNativeDistributionDependencies().assertDependencyFilesMatches(".*cinterop-dummy") - nativeTest.assertTargetOnAllDependencies(CommonizerTarget(LINUX_X64, LINUX_ARM64)) - } - } - } - - @Test - fun `test KT-50847 missing cinterop in supported target`() { - with(Project("commonize-kt-50847-cinterop-missing-in-supported-target")) { - build(":compileCommonMainKotlinMetadata", "-PdisableTargetNumber=1") { - assertSuccessful() - assertTasksSkipped(":cinteropSimpleTarget1") - assertTasksExecuted(":cinteropSimpleTarget2") - assertTasksExecuted(":commonizeCInterop") - } - - build(":compileCommonMainKotlinMetadata", "-PdisableTargetNumber=2") { - assertSuccessful() - assertTasksSkipped(":cinteropSimpleTarget2") - assertTasksExecuted(":cinteropSimpleTarget1") - assertTasksExecuted(":commonizeCInterop") - } - } - } - - @Test - fun `test KT-52243 cinterop caching`() { - with(preparedProject("commonizeCurlInterop")) { - val localBuildCacheDir = projectDir.resolve("local-build-cache-dir").also { assertTrue(it.mkdirs()) } - gradleSettingsScript().appendText( - """ - - buildCache { - local { - directory = "${StringEscapeUtils.escapeJava(localBuildCacheDir.absolutePath)}" - } - } - """.trimIndent() - ) - build(":commonize", options = defaultBuildOptions().copy(withBuildCache = true)) { - assertTasksExecuted(":cinteropCurlTargetA", ":cinteropCurlTargetB") - } - build(":clean") {} - build(":commonize", options = defaultBuildOptions().copy(withBuildCache = true)) { - assertTasksRetrievedFromCache(":cinteropCurlTargetA", ":cinteropCurlTargetB") - } - } - } - - @Test - fun `test KT-51517 commonization with transitive cinterop`() { - with(Project("commonize-kt-51517-transitive-cinterop")) { - build(":app:assemble") { - assertSuccessful() - assertTasksExecuted(":lib:transformCommonMainCInteropDependenciesMetadata") - assertTasksExecuted(":lib:commonizeCInterop") - assertTasksExecuted(":lib:compileCommonMainKotlinMetadata") - assertTasksExecuted(":app:commonizeCInterop") - assertTasksExecuted(":app:compileNativeMainKotlinMetadata") - } - } - } - - @Test - fun `test KT-57796 commonization with two cinterop commonizer groups`() { - with(Project("commonize-kt-57796-twoCInteropCommonizerGroups")) { - build(":app:commonizeCIntero") { - assertSuccessful() - assertTasksExecuted(":lib:transformCommonMainCInteropDependenciesMetadata") - assertTasksExecuted(":lib:commonizeCInterop") - assertTasksExecuted(":app:transformCommonMainCInteropDependenciesMetadata") - assertTasksExecuted(":app:commonizeCInterop") - } - } - } - - - @Test - fun `test KT-56729 commonization with library containing two roots`() { - with(Project("commonize-kt-56729-consume-library-with-two-roots")) { - build("publish") { - assertSuccessful() - } - - build(":consumer:assemble") { - assertSuccessful() - assertTasksExecuted(":consumer:compileCommonMainKotlinMetadata") - assertNotContains("Duplicated libraries:") - assertNotContains("w: duplicate library name") - } - } - } - - private fun preparedProject(name: String): Project { - return Project(name).apply { - setupWorkingDir() - projectDir.walkTopDown().filter { it.name.startsWith("build.gradle") }.forEach { buildFile -> - val originalText = buildFile.readText() - val preparedText = originalText - .replace("", CommonizableTargets.targetA.value) - .replace("", CommonizableTargets.targetB.value) - buildFile.writeText(preparedText) - } - } - } - - private fun CompiledProject.assertNativeDistributionCommonizationCacheHit() { - assertContains("Native Distribution Commonization: Cache hit") + private fun BuildResult.assertNativeDistributionCommonizationCacheHit() { + assertOutputContains("Native Distribution Commonization: Cache hit") } } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/K2Tests.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/K2Tests.kt index bb12e413224..3dd4a9e78e6 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/K2Tests.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/K2Tests.kt @@ -28,9 +28,9 @@ class K2NewMultiplatformIT : NewMultiplatformIT() { override fun defaultBuildOptions(): BuildOptions = super.defaultBuildOptions().copy(languageVersion = "2.0") } -@Ignore +@Disabled("Used for local testing only") class K2CommonizerIT : CommonizerIT() { - override fun defaultBuildOptions(): BuildOptions = super.defaultBuildOptions().copy(languageVersion = "2.0") + override val defaultBuildOptions: BuildOptions get() = super.defaultBuildOptions.copy(languageVersion = "2.0") } @Ignore @@ -89,7 +89,13 @@ class CustomK2Tests : KGPBaseTest() { @GradleTest @DisplayName("Compiling shared native source with FirFakeOverrideGenerator referencing a common entity. KT-58145") fun kt581450MppNativeSharedCrash(gradleVersion: GradleVersion) { - with(project("kt-581450-mpp-native-shared-crash", gradleVersion, buildOptions = defaultBuildOptions.copy(languageVersion = "2.0"))) { + with( + project( + "kt-581450-mpp-native-shared-crash", + gradleVersion, + buildOptions = defaultBuildOptions.copy(languageVersion = "2.0") + ) + ) { val taskToExecute = ":compileNativeMainKotlinMetadata" build(taskToExecute) { assertTasksExecuted(taskToExecute) diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/fileAssertions.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/fileAssertions.kt index d9f8c90b0ee..6b480e7c30a 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/fileAssertions.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/fileAssertions.kt @@ -21,7 +21,7 @@ import kotlin.test.asserter * Asserts file under [file] path exists and is a regular file. */ fun assertFileExists( - file: Path + file: Path, ) { assert(Files.exists(file)) { "File '${file}' does not exist!" @@ -36,14 +36,14 @@ fun assertFileExists( * Asserts file under [pathToFile] relative to the test project exists and is a regular file. */ fun GradleProject.assertFileInProjectExists( - pathToFile: String + pathToFile: String, ) { assertFileExists(projectPath.resolve(pathToFile)) } fun assertFileExistsInTree( pathToTreeRoot: Path, - fileName: String + fileName: String, ) { val foundFile = pathToTreeRoot .toFile() @@ -61,22 +61,23 @@ fun assertFileExistsInTree( * Asserts file under [pathToFile] relative to the test project does not exist. */ fun GradleProject.assertFileInProjectNotExists( - pathToFile: String + pathToFile: String, ) { assertFileNotExists(projectPath.resolve(pathToFile)) } fun assertFileNotExists( - pathToFile: Path + pathToFile: Path, + message: String = "File '${pathToFile}' exists!" ) { assert(!Files.exists(pathToFile)) { - "File '${pathToFile}' exists!" + message } } fun assertFileNotExistsInTree( pathToTreeRoot: Path, - fileName: String + fileName: String, ) { val foundFile = pathToTreeRoot .toFile() @@ -92,7 +93,7 @@ fun assertFileNotExistsInTree( fun GradleProject.assertFileNotExistsInTree( pathToTreeRoot: String, - fileName: String + fileName: String, ) { assertFileNotExistsInTree(projectPath.resolve(pathToTreeRoot), fileName) } @@ -101,7 +102,7 @@ fun GradleProject.assertFileNotExistsInTree( * Asserts symlink under [path] exists and is a symlink */ fun assertSymlinkExists( - path: Path + path: Path, ) { assert(Files.exists(path)) { "Symlink '${path}' does not exist!" @@ -116,7 +117,7 @@ fun assertSymlinkExists( * Asserts symlink under [pathToFile] relative to the test project exists and is a symlink. */ fun TestProject.assertSymlinkInProjectExists( - pathToFile: String + pathToFile: String, ) { assertSymlinkExists(projectPath.resolve(pathToFile)) } @@ -125,24 +126,26 @@ fun TestProject.assertSymlinkInProjectExists( * Asserts directory under [pathToDir] relative to the test project exists and is a directory. */ fun GradleProject.assertDirectoryInProjectExists( - pathToDir: String + pathToDir: String, ) = assertDirectoryExists(projectPath.resolve(pathToDir)) /** * Asserts directory under [dirPath] exists and is a directory. */ fun assertDirectoryExists( - dirPath: Path -) = assertDirectoriesExist(dirPath) + dirPath: Path, + message: String? = null, +) = assertDirectoriesExist(dirPath, message = message) fun assertDirectoriesExist( - vararg dirPaths: Path + vararg dirPaths: Path, + message: String? = null, ) { val (exist, notExist) = dirPaths.partition { it.exists() } val notDirectories = exist.filterNot { it.isDirectory() } assert(notExist.isEmpty() && notDirectories.isEmpty()) { - buildString { + message ?: buildString { if (notExist.isNotEmpty()) { appendLine("Following directories does not exist:") appendLine(notExist.joinToString(separator = "\n")) @@ -160,7 +163,7 @@ fun assertDirectoriesExist( */ fun GradleProject.assertFileInProjectContains( pathToFile: String, - vararg expectedText: String + vararg expectedText: String, ) { assertFileContains(projectPath.resolve(pathToFile), *expectedText) } @@ -170,7 +173,7 @@ fun GradleProject.assertFileInProjectContains( */ fun GradleProject.assertFileInProjectDoesNotContain( pathToFile: String, - vararg unexpectedText: String + vararg unexpectedText: String, ) { assertFileDoesNotContain(projectPath.resolve(pathToFile), *unexpectedText) } @@ -180,7 +183,7 @@ fun GradleProject.assertFileInProjectDoesNotContain( */ fun assertFileContains( file: Path, - vararg expectedText: String + vararg expectedText: String, ) { assertFileExists(file) val text = file.readText() @@ -202,7 +205,7 @@ fun assertFileContains( */ fun assertFileDoesNotContain( file: Path, - vararg unexpectedText: String + vararg unexpectedText: String, ) { assertFileExists(file) val text = file.readText() @@ -258,7 +261,7 @@ fun assertFilesContentEquals(expected: Path, actual: Path) { } class GradleVariantAssertions( - val variantJson: JsonObject + val variantJson: JsonObject, ) { fun assertAttributesEquals(expected: Map) { val attributesJson = variantJson.getAsJsonObject("attributes") diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/outputAssertions.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/outputAssertions.kt index 30cb14a1518..19199faed69 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/outputAssertions.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/outputAssertions.kt @@ -22,7 +22,7 @@ fun BuildResult.assertOutputContains( } /** - * Asserts Gradle output contains any of [expectedSubString] strings. + * Asserts Gradle output contains any of [expectedSubStrings] strings. */ fun BuildResult.assertOutputContainsAny( vararg expectedSubStrings: String, @@ -103,11 +103,12 @@ fun BuildResult.assertOutputDoesNotContain( */ fun BuildResult.assertOutputContains( expected: Regex, + message: String = "Build output does not contain any line matching '$expected' regex.", ) { assert(output.contains(expected)) { printBuildOutput() - "Build output does not contain any line matching '$expected' regex." + message } } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/tasksAssertions.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/tasksAssertions.kt index fc52b0484d6..6fb5c3310f7 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/tasksAssertions.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/tasksAssertions.kt @@ -41,6 +41,20 @@ fun BuildResult.assertTasksExecuted(vararg tasks: String) { } } +/** + * Asserts any of [tasks] has 'SUCCESS' execution state. + */ +fun BuildResult.assertAnyTaskHasBeenExecuted(tasks: Set) { + assert( + tasks.any { task -> + task(task)?.outcome == TaskOutcome.SUCCESS + } + ) { + printBuildOutput() + "There are no 'SUCCESS' tasks in the $tasks" + } +} + /** * Asserts given [tasks] have not been executed. */ @@ -148,7 +162,7 @@ fun BuildResult.assertTasksPackedToCache(vararg tasks: String) { fun BuildResult.assertNativeTasksClasspath( vararg tasksPaths: String, toolName: NativeToolKind = NativeToolKind.KONANC, - assertions: (List) -> Unit + assertions: (List) -> Unit, ) = tasksPaths.forEach { taskPath -> assertions(extractNativeCompilerClasspath(getOutputForTask(taskPath), toolName)) } /** @@ -189,7 +203,7 @@ fun TestProject.buildAndAssertAllTasks( */ fun BuildResult.assertTasksInBuildOutput( expectedPresentTasks: List = emptyList(), - expectedAbsentTasks: List = emptyList() + expectedAbsentTasks: List = emptyList(), ) { val registeredTasks = getAllTasksFromTheOutput() expectedPresentTasks.forEach { diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/testDsl.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/testDsl.kt index a69cfd283b6..9dbfee1b761 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/testDsl.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/testDsl.kt @@ -240,12 +240,14 @@ internal inline fun TestProject.getModels( fun TestProject.enableLocalBuildCache( buildCacheLocation: Path, ) { - // language=Groovy - settingsGradle.append( + + val settingsFile = if (Files.exists(settingsGradle)) settingsGradle else settingsGradleKts + + settingsFile.append( """ buildCache { local { - directory = '${buildCacheLocation.toUri()}' + directory = "${buildCacheLocation.toUri()}" } } """.trimIndent() diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/util/reportSourceSetCommonizerDependencies.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/util/reportSourceSetCommonizerDependencies.kt index 2ceba3aa545..94112b304da 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/util/reportSourceSetCommonizerDependencies.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/util/reportSourceSetCommonizerDependencies.kt @@ -5,30 +5,34 @@ package org.jetbrains.kotlin.gradle.util +import org.gradle.testkit.runner.BuildResult import org.intellij.lang.annotations.Language import org.intellij.lang.annotations.RegExp import org.jetbrains.kotlin.commonizer.CommonizerTarget import org.jetbrains.kotlin.commonizer.SharedCommonizerTarget import org.jetbrains.kotlin.commonizer.parseCommonizerTarget import org.jetbrains.kotlin.gradle.BaseGradleIT -import org.jetbrains.kotlin.gradle.BaseGradleIT.CompiledProject +import org.jetbrains.kotlin.gradle.testbase.BuildOptions +import org.jetbrains.kotlin.gradle.testbase.TestProject +import org.jetbrains.kotlin.gradle.testbase.build import org.jetbrains.kotlin.library.ToolingSingleFileKlibResolveStrategy import org.jetbrains.kotlin.library.commonizerTarget import org.jetbrains.kotlin.library.resolveSingleFileKlib import org.jetbrains.kotlin.tooling.core.linearClosure import java.io.File import javax.annotation.RegEx +import kotlin.io.path.appendText import kotlin.test.fail data class SourceSetCommonizerDependency( val sourceSetName: String, val target: CommonizerTarget, - val file: File + val file: File, ) data class SourceSetCommonizerDependencies( val sourceSetName: String, - val dependencies: Set + val dependencies: Set, ) { fun withoutNativeDistributionDependencies(): SourceSetCommonizerDependencies { @@ -77,10 +81,6 @@ data class SourceSetCommonizerDependencies( assertDependencyFilesMatches(fileMatchers.filterNotNull().map(::Regex).toSet()) } - fun assertDependencyFilesMatches(vararg fileMatchers: Regex?) = apply { - assertDependencyFilesMatches(fileMatchers.filterNotNull().toSet()) - } - fun assertDependencyFilesMatches(fileMatchers: Set) = apply { val unmatchedDependencies = dependencies.filter { dependency -> fileMatchers.none { matcher -> dependency.file.absolutePath.matches(matcher) } @@ -120,7 +120,7 @@ fun BaseGradleIT.reportSourceSetCommonizerDependencies( project: BaseGradleIT.Project, subproject: String? = null, options: BaseGradleIT.BuildOptions = defaultBuildOptions(), - test: WithSourceSetCommonizerDependencies.(compiledProject: CompiledProject) -> Unit + test: WithSourceSetCommonizerDependencies.(compiledProject: BaseGradleIT.CompiledProject) -> Unit ) = with(project) { if (!projectDir.exists()) { @@ -160,6 +160,40 @@ fun BaseGradleIT.reportSourceSetCommonizerDependencies( } } +fun TestProject.reportSourceSetCommonizerDependencies( + subproject: String? = null, + options: BuildOptions = this.buildOptions, + test: WithSourceSetCommonizerDependencies.(compiledProject: BuildResult) -> Unit, +) { + + buildGradleKts.appendText("\n\n$taskSourceCode\n\n") + + val taskName = buildString { + if (subproject != null) append(":$subproject") + append(":reportCommonizerSourceSetDependencies") + } + + build(taskName, buildOptions = options) { + + val dependencyReports = output.lineSequence().filter { line -> line.contains("SourceSetCommonizerDependencyReport") }.toList() + + val withSourceSetCommonizerDependencies = WithSourceSetCommonizerDependencies { sourceSetName -> + val reportMarker = "Report[$sourceSetName]" + + val reportForSourceSet = dependencyReports.firstOrNull { line -> line.contains(reportMarker) } + ?: fail("Missing dependency report for $sourceSetName") + + val files = reportForSourceSet.split(reportMarker, limit = 2).last().split("|#+#|") + .map(String::trim).filter(String::isNotEmpty).map(::File) + + val dependencies = files.mapNotNull { file -> createSourceSetCommonizerDependencyOrNull(sourceSetName, file) }.toSet() + SourceSetCommonizerDependencies(sourceSetName, dependencies) + } + + withSourceSetCommonizerDependencies.test(this) + } +} + private fun createSourceSetCommonizerDependencyOrNull(sourceSetName: String, libraryFile: File): SourceSetCommonizerDependency? { return SourceSetCommonizerDependency( sourceSetName,