diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/mpp/MppEmptyTestSourceSetsIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/mpp/MppEmptyTestSourceSetsIT.kt new file mode 100644 index 0000000000000..90d079d4285ea --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/mpp/MppEmptyTestSourceSetsIT.kt @@ -0,0 +1,124 @@ +/* + * Copyright 2010-2026 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.mpp + +import org.gradle.util.GradleVersion +import org.jetbrains.kotlin.gradle.testbase.* +import org.junit.jupiter.api.DisplayName + +@MppGradlePluginTests +@DisplayName("Tests for empty MPP test source sets") +class MppEmptyTestSourceSetsIT : KGPBaseTest() { + + @DisplayName("No test sources in commonTest or jvmTest") + @GradleTest + fun testNoTestSources(gradleVersion: GradleVersion) { + project("base-kotlin-multiplatform-library", gradleVersion) { + buildScriptInjection { + kotlinMultiplatform.jvm() + } + kotlinSourcesDir("commonMain").source("CommonMain.kt") { + """ + package org.example.project + + fun commonFun(): String = "common" + """.trimIndent() + } + + build(":jvmTest") { + assertTasksNoSource(":compileTestKotlinJvm", ":jvmTest") + assertNoTestResultsProduced("jvmTest") + } + } + } + + // In Gradle 9.0+, executing a test task fails by default when test compilation outputs exist but 0 tests are discovered. + // Older Gradle versions succeeded silently. + @DisplayName("Sources in jvmTest without test cases fail on Gradle 9.0+") + @GradleTestVersions(minVersion = TestVersions.Gradle.G_9_0) + @GradleTest + fun testSourcesWithoutTests(gradleVersion: GradleVersion) { + project("base-kotlin-multiplatform-library", gradleVersion) { + buildScriptInjection { + kotlinMultiplatform.jvm() + } + kotlinSourcesDir("jvmTest").source("NotATest.kt") { + """ + package org.example.project + + class NotATest { + fun helper(): String = "helper" + } + """.trimIndent() + } + + buildAndFail(":jvmTest") { + assertTasksExecuted(":compileTestKotlinJvm") + assertTasksFailed(":jvmTest") + assertNoTestResultsProduced("jvmTest") + } + } + } + + @DisplayName("Common test discovery and inheritance in jvmTest") + @GradleTest + fun testCommonTestDiscoveryAndInheritance(gradleVersion: GradleVersion) { + project("base-kotlin-multiplatform-library", gradleVersion) { + buildScriptInjection { + kotlinMultiplatform.jvm() + kotlinMultiplatform.sourceSets.getByName("commonTest").dependencies { + implementation(kotlin("test")) + } + } + kotlinSourcesDir("commonTest").source("CommonSampleTest.kt") { + """ + package org.example.project + + import kotlin.test.Test + import kotlin.test.assertTrue + + open class CommonSampleTest { + @Test + fun testInCommon() { + assertTrue(true) + } + } + """.trimIndent() + } + + build(":jvmTest") { + assertTasksExecuted(":compileTestKotlinJvm", ":jvmTest") + assertExecutedTestCases("jvmTest", "org.example.project.CommonSampleTest#testInCommon") + } + + kotlinSourcesDir("jvmTest").source("JvmSampleTest.kt") { + """ + package org.example.project + + import kotlin.test.Test + import kotlin.test.assertTrue + + class JvmSampleTest : CommonSampleTest() { + @Test + fun testInJvm() { + assertTrue(true) + } + } + """.trimIndent() + } + + build(":jvmTest") { + assertTasksExecuted(":compileTestKotlinJvm", ":jvmTest") + assertExecutedTestCases( + "jvmTest", + "org.example.project.CommonSampleTest#testInCommon", + "org.example.project.JvmSampleTest#testInCommon", + "org.example.project.JvmSampleTest#testInJvm", + ) + } + } + } +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/testAssertions.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/testAssertions.kt index 5ff5ea54e0559..cc566af54ec77 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/testAssertions.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/testAssertions.kt @@ -20,6 +20,7 @@ import kotlin.io.path.absolutePathString import kotlin.io.path.name import kotlin.io.path.readText import kotlin.test.assertEquals +import kotlin.test.assertTrue /** * @param stripBrowserVersionInfoFromTestCaseNames Some test executor implementations include browser version info in test case names, @@ -63,6 +64,20 @@ fun GradleProject.assertTestResults( assertEquals(expectedTestResults, actualTestResults) } +fun GradleProject.assertNoTestResultsProduced( + taskName: String, + subprojectName: String? = null, +) { + val testResultsDir = testResultsAndReportsDirs(taskName, subprojectName).first + if (Files.exists(testResultsDir)) { + val xmlFiles = testResultsDir.allFilesWithExtension("xml") + assertTrue( + xmlFiles.isEmpty(), + "Expected no test result XML files in '$testResultsDir', but found: ${xmlFiles.joinToString()}" + ) + } +} + internal fun readValidateAndCleanupTestResults( testReportDirs: List, projectPath: Path,