diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/android/checker/KotlinAndroidSourceSetLayoutChecker.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/android/checker/KotlinAndroidSourceSetLayoutChecker.kt index 4530ed96bf9..487f5185ac0 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/android/checker/KotlinAndroidSourceSetLayoutChecker.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/android/checker/KotlinAndroidSourceSetLayoutChecker.kt @@ -14,7 +14,7 @@ import org.jetbrains.kotlin.gradle.plugin.sources.android.KotlinAndroidSourceSet import org.jetbrains.kotlin.gradle.utils.SingleWarningPerBuild internal interface KotlinAndroidSourceSetLayoutChecker { - class ProjectMisconfiguredException(message: String) : Exception(message) + open class ProjectMisconfiguredException(message: String) : Exception(message) interface DiagnosticReporter { fun error(diagnostic: Diagnostic): Nothing diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/assertions.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/assertions.kt index 180fcc63d03..7b116cc4e18 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/assertions.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/assertions.kt @@ -90,4 +90,9 @@ fun Project.assertNotContainsDependencies(configurationName: String, vararg depe foundUnexpectedDependencies.isEmpty(), "Unexpected dependencies '$foundUnexpectedDependencies' found in configuration '$configurationName'" ) +} + +inline fun assertIsInstance(value: Any?): T { + if (value is T) return value + fail("Expected $value to implement ${T::class.java}") } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/sources/android/MultiplatformAndroidSourceSetLayoutV2DiagnosticsTest.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/sources/android/MultiplatformAndroidSourceSetLayoutV2DiagnosticsTest.kt new file mode 100644 index 00000000000..9426dc55437 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/sources/android/MultiplatformAndroidSourceSetLayoutV2DiagnosticsTest.kt @@ -0,0 +1,69 @@ +/* + * Copyright 2010-2022 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. + */ + +@file:Suppress("FunctionName") + +package org.jetbrains.kotlin.gradle.sources.android + +import com.android.build.gradle.LibraryPlugin +import org.gradle.api.Project +import org.gradle.api.internal.project.ProjectInternal +import org.jetbrains.kotlin.gradle.* +import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension +import org.jetbrains.kotlin.gradle.plugin.sources.android.checker.MultiplatformLayoutV2AndroidStyleSourceDirUsageChecker.AndroidStyleSourceDirUsageDiagnostic +import org.jetbrains.kotlin.gradle.plugin.sources.android.findAndroidSourceSet +import org.jetbrains.kotlin.gradle.plugin.sources.android.multiplatformAndroidSourceSetLayoutV2 +import org.junit.Test +import kotlin.test.assertEquals + +class MultiplatformAndroidSourceSetLayoutV2DiagnosticsTest { + + private val diagnosticsReporter = TestDiagnosticsReporter() + + private fun buildMinimalAndroidMultiplatformProject(): ProjectInternal = buildProjectWithMPP { + setMultiplatformAndroidSourceSetLayoutVersion(2) + plugins.apply(LibraryPlugin::class.java) + androidLibrary { + compileSdk = 31 + } + kotlin { + android() + } + } + + private fun Project.checkCreatedSourceSets( + diagnosticsReporter: TestDiagnosticsReporter = this@MultiplatformAndroidSourceSetLayoutV2DiagnosticsTest.diagnosticsReporter + ) { + /* Invoke checkers on all source sets */ + project.multiplatformExtension.sourceSets.forEach { kotlinSourceSet -> + val androidSourceSet = project.findAndroidSourceSet(kotlinSourceSet) ?: return@forEach + multiplatformAndroidSourceSetLayoutV2.checker.checkCreatedSourceSet( + diagnosticReporter = diagnosticsReporter, + target = project.multiplatformExtension.android(), + layout = multiplatformAndroidSourceSetLayoutV2, + kotlinSourceSet = kotlinSourceSet, + androidSourceSet = androidSourceSet + ) + } + } + + @Test + fun `test - KT-53709 - androidTest_kotlin in use`() { + + val project = buildMinimalAndroidMultiplatformProject() + + /* Ensure that the problematic androidTest/kotlin source dir is 'in use' */ + val androidTestKotlinSourceDir = project.file("src/androidTest/kotlin") + androidTestKotlinSourceDir.mkdirs() + project.evaluate() + + /* Invoke checkers on all source sets */ + project.checkCreatedSourceSets() + + val diagnostic = assertIsInstance(diagnosticsReporter.assertSingleWarning()) + assertEquals(androidTestKotlinSourceDir, diagnostic.androidStyleSourceDirInUse) + assertEquals(project.file("src/androidInstrumentedTest/kotlin"), diagnostic.kotlinStyleSourceDirToUse) + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/sources/android/TestDiagnosticsReporter.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/sources/android/TestDiagnosticsReporter.kt new file mode 100644 index 00000000000..0d95526c486 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/sources/android/TestDiagnosticsReporter.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2010-2022 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.sources.android + +import org.jetbrains.kotlin.gradle.plugin.sources.android.checker.KotlinAndroidSourceSetLayoutChecker +import kotlin.test.fail + +internal class TestDiagnosticsReporter : KotlinAndroidSourceSetLayoutChecker.DiagnosticReporter { + + class ErrorDiagnosticException(val diagnostic: KotlinAndroidSourceSetLayoutChecker.Diagnostic) : + KotlinAndroidSourceSetLayoutChecker.ProjectMisconfiguredException(diagnostic.message) + + private val _errors = mutableListOf() + + private val _warnings = mutableListOf() + + val errors get() = _errors.toList() + + val warnings get() = _warnings.toList() + + override fun error(diagnostic: KotlinAndroidSourceSetLayoutChecker.Diagnostic): Nothing { + _errors.add(diagnostic) + throw ErrorDiagnosticException(diagnostic) + } + + override fun warning(diagnostic: KotlinAndroidSourceSetLayoutChecker.Diagnostic) { + _warnings.add(diagnostic) + } +} + +internal fun TestDiagnosticsReporter.assertSingleWarning(): KotlinAndroidSourceSetLayoutChecker.Diagnostic { + if (errors.isNotEmpty()) fail("Expected just a single warning, but found errors: $errors") + if (warnings.isEmpty()) fail("Expected a single warning, but found none!") + if (warnings.size > 1) fail("Expected a single warning, but found multiple: $warnings") + return warnings.first() +} \ No newline at end of file