diff --git a/kover-gradle-plugin/src/functionalTest/kotlin/kotlinx/kover/gradle/plugin/test/functional/cases/NoDependencyTests.kt b/kover-gradle-plugin/src/functionalTest/kotlin/kotlinx/kover/gradle/plugin/test/functional/cases/NoDependencyTests.kt
new file mode 100644
index 00000000..d7729524
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/kotlin/kotlinx/kover/gradle/plugin/test/functional/cases/NoDependencyTests.kt
@@ -0,0 +1,44 @@
+package kotlinx.kover.gradle.plugin.test.functional.cases
+
+import kotlinx.kover.gradle.plugin.test.functional.framework.checker.checkNoAndroidSdk
+import kotlinx.kover.gradle.plugin.test.functional.framework.runner.buildFromTemplate
+import kotlinx.kover.gradle.plugin.test.functional.framework.runner.runWithParams
+import org.junit.jupiter.api.Test
+import kotlin.test.assertContains
+import kotlin.test.assertFalse
+
+/**
+ * Tests on dependency check https://github.com/Kotlin/kotlinx-kover/issues/478.
+ */
+class NoDependencyTests {
+ @Test
+ fun testJvmNotApplied() {
+ val buildSource = buildFromTemplate("no-dependency-jvm")
+ val build = buildSource.generate()
+ val buildResult = build.runWithParams("koverHtmlReport")
+ assertFalse(buildResult.isSuccessful)
+ assertContains(buildResult.output, "Kover plugin is not applied")
+ }
+
+ @Test
+ fun testAndroidNotApplied() {
+ val buildSource = buildFromTemplate("no-dependency-android")
+ val build = buildSource.generate()
+ val buildResult = build.runWithParams(":app:koverHtmlReportDebug")
+ buildResult.checkNoAndroidSdk()
+
+ assertFalse(buildResult.isSuccessful)
+ assertContains(buildResult.output, "Kover plugin is not applied")
+ }
+
+ @Test
+ fun testAndroidNoVariant() {
+ val buildSource = buildFromTemplate("no-dependency-variant-android")
+ val build = buildSource.generate()
+ val buildResult = build.runWithParams(":app-extra:koverHtmlReportExtra")
+ buildResult.checkNoAndroidSdk()
+
+ assertFalse(buildResult.isSuccessful)
+ assertContains(buildResult.output, "Kover android variant 'extra' was not matched with any variant from dependency")
+ }
+}
\ No newline at end of file
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/app/build.gradle.kts b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/app/build.gradle.kts
new file mode 100644
index 00000000..fc439e6b
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/app/build.gradle.kts
@@ -0,0 +1,47 @@
+plugins {
+ id ("org.jetbrains.kotlinx.kover")
+ id ("com.android.application")
+ id ("org.jetbrains.kotlin.android")
+}
+
+android {
+ namespace = "kotlinx.kover.test.android"
+ compileSdk = 32
+
+ defaultConfig {
+ applicationId = "kotlinx.kover.test.android"
+ minSdk = 21
+ targetSdk = 31
+ versionCode = 1
+ versionName = "1.0"
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = true
+ }
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+ }
+ kotlinOptions {
+ jvmTarget = "1.8"
+ }
+ buildFeatures {
+ viewBinding = true
+ }
+}
+
+dependencies {
+ // error dependency
+ kover(project(":subproject"))
+
+ implementation("androidx.core:core-ktx:1.8.0")
+ implementation("androidx.appcompat:appcompat:1.5.0")
+ implementation("com.google.android.material:material:1.6.1")
+ implementation("androidx.constraintlayout:constraintlayout:2.1.4")
+ testImplementation("junit:junit:4.13.2")
+}
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/app/src/main/AndroidManifest.xml b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/app/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..358fac25
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/app/src/main/java/kotlinx/kover/test/android/DebugUtil.kt b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/app/src/main/java/kotlinx/kover/test/android/DebugUtil.kt
new file mode 100644
index 00000000..efe82040
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/app/src/main/java/kotlinx/kover/test/android/DebugUtil.kt
@@ -0,0 +1,7 @@
+package kotlinx.kover.test.android
+
+object DebugUtil {
+ fun log(message: String) {
+ println("DEBUG: $message")
+ }
+}
\ No newline at end of file
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/app/src/main/java/kotlinx/kover/test/android/MainActivity.kt b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/app/src/main/java/kotlinx/kover/test/android/MainActivity.kt
new file mode 100644
index 00000000..1caaf5b6
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/app/src/main/java/kotlinx/kover/test/android/MainActivity.kt
@@ -0,0 +1,13 @@
+package kotlinx.kover.test.android
+
+import android.os.Bundle
+import android.app.Activity
+
+class MainActivity : Activity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_main)
+ }
+
+}
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/app/src/main/java/kotlinx/kover/test/android/Maths.kt b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/app/src/main/java/kotlinx/kover/test/android/Maths.kt
new file mode 100644
index 00000000..03edc099
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/app/src/main/java/kotlinx/kover/test/android/Maths.kt
@@ -0,0 +1,13 @@
+package kotlinx.kover.test.android
+
+object Maths {
+ fun sum(a: Int, b: Int): Int {
+ DebugUtil.log("invoked sum")
+ return a + b
+ }
+
+ fun sub(a: Int, b: Int): Int {
+ DebugUtil.log("invoked sub")
+ return a - b
+ }
+}
\ No newline at end of file
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/app/src/main/res/layout/activity_main.xml b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 00000000..ee57d166
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/app/src/main/res/values/colors.xml b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/app/src/main/res/values/colors.xml
new file mode 100644
index 00000000..f8c6127d
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/app/src/main/res/values/colors.xml
@@ -0,0 +1,10 @@
+
+
+ #FFBB86FC
+ #FF6200EE
+ #FF3700B3
+ #FF03DAC5
+ #FF018786
+ #FF000000
+ #FFFFFFFF
+
\ No newline at end of file
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/app/src/main/res/values/strings.xml b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/app/src/main/res/values/strings.xml
new file mode 100644
index 00000000..fa43411e
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ Android Test
+
\ No newline at end of file
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/app/src/main/res/values/themes.xml b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/app/src/main/res/values/themes.xml
new file mode 100644
index 00000000..0b4cfc4c
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/app/src/main/res/values/themes.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/app/src/test/java/kotlinx/kover/test/android/LocalTests.kt b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/app/src/test/java/kotlinx/kover/test/android/LocalTests.kt
new file mode 100644
index 00000000..c6453c26
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/app/src/test/java/kotlinx/kover/test/android/LocalTests.kt
@@ -0,0 +1,13 @@
+package kotlinx.kover.test.android
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+
+class LocalTests {
+ @Test
+ fun testDebugUtils() {
+ assertEquals(3, Maths.sum(1, 2))
+ }
+}
\ No newline at end of file
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/build.gradle.kts b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/build.gradle.kts
new file mode 100644
index 00000000..c3ef99cd
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/build.gradle.kts
@@ -0,0 +1,6 @@
+plugins {
+ id("com.android.application") version "7.4.0" apply false
+ id("com.android.library") version "7.4.0" apply false
+ id("org.jetbrains.kotlin.android") version "1.8.20" apply false
+ id("org.jetbrains.kotlinx.kover") version "0.7.1" apply false
+}
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/gradle.properties b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/gradle.properties
new file mode 100644
index 00000000..3c5031eb
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/gradle.properties
@@ -0,0 +1,23 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app's APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Kotlin code style for this project: "official" or "obsolete":
+kotlin.code.style=official
+# Enables namespacing of each library's R class so that its R class includes only the
+# resources declared in the library itself and none from the library's dependencies,
+# thereby reducing the size of the R class for that library
+android.nonTransitiveRClass=true
\ No newline at end of file
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/settings.gradle.kts b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/settings.gradle.kts
new file mode 100644
index 00000000..5bbee848
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/settings.gradle.kts
@@ -0,0 +1,19 @@
+pluginManagement {
+ repositories {
+ google()
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+
+dependencyResolutionManagement {
+ repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+ repositories {
+ google()
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+
+rootProject.name = "android_kts"
+include(":app", ":subproject")
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/subproject/build.gradle.kts b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/subproject/build.gradle.kts
new file mode 100644
index 00000000..444baaa3
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-android/subproject/build.gradle.kts
@@ -0,0 +1,3 @@
+plugins {
+ kotlin("jvm")
+}
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-jvm/build.gradle.kts b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-jvm/build.gradle.kts
new file mode 100644
index 00000000..77d07a19
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-jvm/build.gradle.kts
@@ -0,0 +1,12 @@
+plugins {
+ kotlin("jvm") version "1.8.20"
+ id("org.jetbrains.kotlinx.kover")
+}
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ kover(project(":subproject"))
+}
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-jvm/settings.gradle.kts b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-jvm/settings.gradle.kts
new file mode 100644
index 00000000..129183fd
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-jvm/settings.gradle.kts
@@ -0,0 +1,10 @@
+pluginManagement {
+ repositories {
+ gradlePluginPortal()
+ mavenCentral()
+ }
+}
+
+rootProject.name = "no-dependency-jvm"
+
+include(":subproject")
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-jvm/subproject/build.gradle.kts b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-jvm/subproject/build.gradle.kts
new file mode 100644
index 00000000..fb0d35ad
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-jvm/subproject/build.gradle.kts
@@ -0,0 +1,7 @@
+plugins {
+ kotlin("jvm")
+}
+
+repositories {
+ mavenCentral()
+}
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app-extra/build.gradle.kts b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app-extra/build.gradle.kts
new file mode 100644
index 00000000..414b5aee
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app-extra/build.gradle.kts
@@ -0,0 +1,45 @@
+plugins {
+ id ("org.jetbrains.kotlinx.kover")
+ id ("com.android.application")
+ id ("org.jetbrains.kotlin.android")
+}
+
+android {
+ namespace = "kotlinx.kover.test.android.extra"
+ compileSdk = 32
+
+ defaultConfig {
+ applicationId = "kotlinx.kover.test.android.extra"
+ minSdk = 21
+ targetSdk = 31
+ versionCode = 1
+ versionName = "1.0"
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ create("extra")
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+ }
+ kotlinOptions {
+ jvmTarget = "1.8"
+ }
+ buildFeatures {
+ viewBinding = true
+ }
+}
+
+dependencies {
+ // error dependency
+ kover(project(":app"))
+
+ implementation("androidx.core:core-ktx:1.8.0")
+ implementation("androidx.appcompat:appcompat:1.5.0")
+ implementation("com.google.android.material:material:1.6.1")
+ implementation("androidx.constraintlayout:constraintlayout:2.1.4")
+ testImplementation("junit:junit:4.13.2")
+}
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app-extra/src/main/AndroidManifest.xml b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app-extra/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..358fac25
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app-extra/src/main/AndroidManifest.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app-extra/src/main/java/kotlinx/kover/test/android/ExtraUtil.kt b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app-extra/src/main/java/kotlinx/kover/test/android/ExtraUtil.kt
new file mode 100644
index 00000000..de12a6bc
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app-extra/src/main/java/kotlinx/kover/test/android/ExtraUtil.kt
@@ -0,0 +1,7 @@
+package kotlinx.kover.test.android
+
+object ExtraUtil {
+ fun log(message: String) {
+ println("Extra: $message")
+ }
+}
\ No newline at end of file
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app-extra/src/main/res/layout/activity_main.xml b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app-extra/src/main/res/layout/activity_main.xml
new file mode 100644
index 00000000..ee57d166
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app-extra/src/main/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app-extra/src/main/res/values/colors.xml b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app-extra/src/main/res/values/colors.xml
new file mode 100644
index 00000000..f8c6127d
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app-extra/src/main/res/values/colors.xml
@@ -0,0 +1,10 @@
+
+
+ #FFBB86FC
+ #FF6200EE
+ #FF3700B3
+ #FF03DAC5
+ #FF018786
+ #FF000000
+ #FFFFFFFF
+
\ No newline at end of file
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app-extra/src/main/res/values/strings.xml b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app-extra/src/main/res/values/strings.xml
new file mode 100644
index 00000000..fa43411e
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app-extra/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ Android Test
+
\ No newline at end of file
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app-extra/src/main/res/values/themes.xml b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app-extra/src/main/res/values/themes.xml
new file mode 100644
index 00000000..0b4cfc4c
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app-extra/src/main/res/values/themes.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app-extra/src/test/java/kotlinx/kover/test/android/LocalTests.kt b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app-extra/src/test/java/kotlinx/kover/test/android/LocalTests.kt
new file mode 100644
index 00000000..eadabade
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app-extra/src/test/java/kotlinx/kover/test/android/LocalTests.kt
@@ -0,0 +1,13 @@
+package kotlinx.kover.test.android
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+
+class LocalTests {
+ @Test
+ fun testDebugUtils() {
+ assertEquals(3, 3)
+ }
+}
\ No newline at end of file
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app/build.gradle.kts b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app/build.gradle.kts
new file mode 100644
index 00000000..43833f8d
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app/build.gradle.kts
@@ -0,0 +1,44 @@
+plugins {
+ id ("org.jetbrains.kotlinx.kover")
+ id ("com.android.application")
+ id ("org.jetbrains.kotlin.android")
+}
+
+android {
+ namespace = "kotlinx.kover.test.android"
+ compileSdk = 32
+
+ defaultConfig {
+ applicationId = "kotlinx.kover.test.android"
+ minSdk = 21
+ targetSdk = 31
+ versionCode = 1
+ versionName = "1.0"
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = true
+ }
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+ }
+ kotlinOptions {
+ jvmTarget = "1.8"
+ }
+ buildFeatures {
+ viewBinding = true
+ }
+}
+
+dependencies {
+ implementation("androidx.core:core-ktx:1.8.0")
+ implementation("androidx.appcompat:appcompat:1.5.0")
+ implementation("com.google.android.material:material:1.6.1")
+ implementation("androidx.constraintlayout:constraintlayout:2.1.4")
+ testImplementation("junit:junit:4.13.2")
+}
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app/src/main/AndroidManifest.xml b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..358fac25
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app/src/main/java/kotlinx/kover/test/android/DebugUtil.kt b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app/src/main/java/kotlinx/kover/test/android/DebugUtil.kt
new file mode 100644
index 00000000..efe82040
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app/src/main/java/kotlinx/kover/test/android/DebugUtil.kt
@@ -0,0 +1,7 @@
+package kotlinx.kover.test.android
+
+object DebugUtil {
+ fun log(message: String) {
+ println("DEBUG: $message")
+ }
+}
\ No newline at end of file
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app/src/main/java/kotlinx/kover/test/android/MainActivity.kt b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app/src/main/java/kotlinx/kover/test/android/MainActivity.kt
new file mode 100644
index 00000000..1caaf5b6
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app/src/main/java/kotlinx/kover/test/android/MainActivity.kt
@@ -0,0 +1,13 @@
+package kotlinx.kover.test.android
+
+import android.os.Bundle
+import android.app.Activity
+
+class MainActivity : Activity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_main)
+ }
+
+}
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app/src/main/java/kotlinx/kover/test/android/Maths.kt b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app/src/main/java/kotlinx/kover/test/android/Maths.kt
new file mode 100644
index 00000000..03edc099
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app/src/main/java/kotlinx/kover/test/android/Maths.kt
@@ -0,0 +1,13 @@
+package kotlinx.kover.test.android
+
+object Maths {
+ fun sum(a: Int, b: Int): Int {
+ DebugUtil.log("invoked sum")
+ return a + b
+ }
+
+ fun sub(a: Int, b: Int): Int {
+ DebugUtil.log("invoked sub")
+ return a - b
+ }
+}
\ No newline at end of file
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app/src/main/res/layout/activity_main.xml b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 00000000..ee57d166
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app/src/main/res/values/colors.xml b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app/src/main/res/values/colors.xml
new file mode 100644
index 00000000..f8c6127d
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app/src/main/res/values/colors.xml
@@ -0,0 +1,10 @@
+
+
+ #FFBB86FC
+ #FF6200EE
+ #FF3700B3
+ #FF03DAC5
+ #FF018786
+ #FF000000
+ #FFFFFFFF
+
\ No newline at end of file
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app/src/main/res/values/strings.xml b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app/src/main/res/values/strings.xml
new file mode 100644
index 00000000..fa43411e
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ Android Test
+
\ No newline at end of file
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app/src/main/res/values/themes.xml b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app/src/main/res/values/themes.xml
new file mode 100644
index 00000000..0b4cfc4c
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app/src/main/res/values/themes.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app/src/test/java/kotlinx/kover/test/android/LocalTests.kt b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app/src/test/java/kotlinx/kover/test/android/LocalTests.kt
new file mode 100644
index 00000000..c6453c26
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/app/src/test/java/kotlinx/kover/test/android/LocalTests.kt
@@ -0,0 +1,13 @@
+package kotlinx.kover.test.android
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+
+class LocalTests {
+ @Test
+ fun testDebugUtils() {
+ assertEquals(3, Maths.sum(1, 2))
+ }
+}
\ No newline at end of file
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/build.gradle.kts b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/build.gradle.kts
new file mode 100644
index 00000000..c3ef99cd
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/build.gradle.kts
@@ -0,0 +1,6 @@
+plugins {
+ id("com.android.application") version "7.4.0" apply false
+ id("com.android.library") version "7.4.0" apply false
+ id("org.jetbrains.kotlin.android") version "1.8.20" apply false
+ id("org.jetbrains.kotlinx.kover") version "0.7.1" apply false
+}
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/gradle.properties b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/gradle.properties
new file mode 100644
index 00000000..3c5031eb
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/gradle.properties
@@ -0,0 +1,23 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app's APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Kotlin code style for this project: "official" or "obsolete":
+kotlin.code.style=official
+# Enables namespacing of each library's R class so that its R class includes only the
+# resources declared in the library itself and none from the library's dependencies,
+# thereby reducing the size of the R class for that library
+android.nonTransitiveRClass=true
\ No newline at end of file
diff --git a/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/settings.gradle.kts b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/settings.gradle.kts
new file mode 100644
index 00000000..cb1fa4ea
--- /dev/null
+++ b/kover-gradle-plugin/src/functionalTest/templates/builds/no-dependency-variant-android/settings.gradle.kts
@@ -0,0 +1,19 @@
+pluginManagement {
+ repositories {
+ google()
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+
+dependencyResolutionManagement {
+ repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+ repositories {
+ google()
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+
+rootProject.name = "android_kts"
+include(":app", ":app-extra")
diff --git a/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/DependencyCheckListener.kt b/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/DependencyCheckListener.kt
new file mode 100644
index 00000000..b922f0c2
--- /dev/null
+++ b/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/DependencyCheckListener.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2017-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.kover.gradle.plugin
+
+import kotlinx.kover.gradle.plugin.commons.*
+import kotlinx.kover.gradle.plugin.commons.KoverIllegalConfigException
+import kotlinx.kover.gradle.plugin.commons.KoverMarkerAttr
+import org.gradle.api.artifacts.DependencyResolutionListener
+import org.gradle.api.artifacts.ResolvableDependencies
+import org.gradle.api.artifacts.component.ComponentIdentifier
+import org.gradle.api.artifacts.component.ProjectComponentIdentifier
+
+
+internal class DependencyCheckListener : DependencyResolutionListener {
+
+ override fun beforeResolve(dependencies: ResolvableDependencies) {
+ // no-op before
+ }
+
+ override fun afterResolve(dependencies: ResolvableDependencies) {
+ // Only Kover dependency consumers requests KoverMarkerAttr attribute
+ dependencies.attributes.getAttribute(KoverMarkerAttr.ATTRIBUTE) ?: return
+
+ /*
+ Gradle can resolve a random artifact from the dependency if the desired option was not found, see:
+ https://github.com/Kotlin/kotlinx-kover/issues/478
+ https://github.com/gradle/gradle/issues/27019
+ https://docs.gradle.org/current/userguide/variant_model.html#sec:variant-aware-matching
+ */
+ dependencies.artifacts.resolvedArtifacts.get().forEach { artifact ->
+
+ val marker = artifact.variant.attributes.getAttribute(KoverMarkerAttr.ATTRIBUTE)
+ if (marker == null) {
+ // no Kover marker - Kover plugin don't applied in the dependency
+ val dependencyPath = artifact.id.componentIdentifier.projectPath
+ val projectPath = dependencies.resolutionResult.rootComponent.get().id.projectPath
+
+ val message = "Kover plugin is not applied in dependency '$dependencyPath' of project '$projectPath'. Apply Kover plugin in the '$dependencyPath' project."
+ throw KoverIllegalConfigException(message)
+ }
+
+ val requestedBuildType = dependencies.attributes.getAttribute(BuildTypeAttr.ATTRIBUTE)
+ val givenBuildType = artifact.variant.attributes.getAttribute(BuildTypeAttr.ATTRIBUTE)
+ if (requestedBuildType != null && givenBuildType == null) {
+ // consumer expects android variant but default variant were selected - invalid selection
+ val dependencyPath = artifact.id.componentIdentifier.projectPath
+ val projectPath = dependencies.resolutionResult.rootComponent.get().id.projectPath
+
+ val suffix = dependencies.name.substringAfter("koverExternalArtifacts")
+ val variantName = if (suffix.isNotEmpty()) suffix.replaceFirstChar { it.lowercase() } else ""
+ val message =
+ "Kover android variant '$variantName' was not matched with any variant from dependency '$dependencyPath' of project '$projectPath'. Check that the Kover plugin is applied in the '$dependencyPath' project and there is a variant compatible with '$variantName' in it."
+ throw KoverIllegalConfigException(message)
+ }
+ }
+ }
+
+ private val ComponentIdentifier.projectPath: String
+ get() = if (this is ProjectComponentIdentifier) projectPath else displayName
+}
\ No newline at end of file
diff --git a/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/KoverGradlePlugin.kt b/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/KoverGradlePlugin.kt
index 86d46ea6..037f66a1 100644
--- a/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/KoverGradlePlugin.kt
+++ b/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/KoverGradlePlugin.kt
@@ -12,6 +12,9 @@ import org.gradle.api.*
import org.gradle.api.invocation.*
import org.gradle.api.tasks.testing.Test
import org.gradle.kotlin.dsl.*
+import org.jetbrains.kotlin.gradle.plugin.extraProperties
+
+private const val LISTENER_ADDED_PROPERTY_NAME = "kover-dependency-listener-added"
/**
* Gradle Plugin for JVM Coverage Tools.
@@ -29,6 +32,7 @@ class KoverGradlePlugin : Plugin {
val applier = ProjectApplier(target)
applier.onApply()
+ target.addDependencyListener()
target.addDeprecations()
}
@@ -51,4 +55,18 @@ class KoverGradlePlugin : Plugin {
this.extensions.create("kover")
}
}
+
+ private fun Project.addDependencyListener() {
+ /*
+ The plugin is applied for each project, but different projects in the same build have the same `gradle` object
+ In order not to add the listener again, it is necessary to check whether we added it earlier.
+
+ The most reliable way is to use the extra properties extension,
+ because it is always present and tied to a specific instance of the `Gradle`.
+ */
+ if (gradle.extraProperties.properties[LISTENER_ADDED_PROPERTY_NAME] == null) {
+ gradle.extraProperties.properties[LISTENER_ADDED_PROPERTY_NAME] = true
+ gradle.addListener(DependencyCheckListener())
+ }
+ }
}
diff --git a/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/appliers/reports/AndroidVariantApplier.kt b/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/appliers/reports/AndroidVariantApplier.kt
index 490184cd..5a4426f5 100644
--- a/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/appliers/reports/AndroidVariantApplier.kt
+++ b/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/appliers/reports/AndroidVariantApplier.kt
@@ -53,6 +53,8 @@ internal class AndroidVariantApplier(
dependencies.configure {
attributes {
// set attribute requirements
+ attribute(KoverMarkerAttr.ATTRIBUTE, project.objects.named("Kover"))
+
attribute(BuildTypeAttr.ATTRIBUTE, project.objects.named(kit.buildType))
kit.missingDimensions.forEach { (dimension, flavorName) ->
diff --git a/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/appliers/reports/DefaultVariantApplier.kt b/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/appliers/reports/DefaultVariantApplier.kt
index d9ac00a3..2fe4d7a0 100644
--- a/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/appliers/reports/DefaultVariantApplier.kt
+++ b/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/appliers/reports/DefaultVariantApplier.kt
@@ -4,10 +4,7 @@
package kotlinx.kover.gradle.plugin.appliers.reports
-import kotlinx.kover.gradle.plugin.commons.DEFAULT_KOVER_VARIANT_NAME
-import kotlinx.kover.gradle.plugin.commons.JvmCompilationKit
-import kotlinx.kover.gradle.plugin.commons.ReportsVariantType
-import kotlinx.kover.gradle.plugin.commons.VariantNameAttr
+import kotlinx.kover.gradle.plugin.commons.*
import kotlinx.kover.gradle.plugin.tools.CoverageTool
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
@@ -15,7 +12,7 @@ import org.gradle.api.provider.Provider
import org.gradle.kotlin.dsl.named
internal class DefaultVariantApplier(
- project: Project,
+ private val project: Project,
koverDependencies: Configuration,
reportClasspath: Configuration,
toolProvider: Provider
@@ -31,6 +28,7 @@ internal class DefaultVariantApplier(
// always configure dependencies because variant name is constant for default reports
dependencies.configure {
attributes {
+ attribute(KoverMarkerAttr.ATTRIBUTE, project.objects.named("Kover"))
attribute(VariantNameAttr.ATTRIBUTE, project.objects.named(DEFAULT_KOVER_VARIANT_NAME))
}
}
diff --git a/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/appliers/reports/ReportsVariantApplier.kt b/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/appliers/reports/ReportsVariantApplier.kt
index ee72c27d..a44aee01 100644
--- a/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/appliers/reports/ReportsVariantApplier.kt
+++ b/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/appliers/reports/ReportsVariantApplier.kt
@@ -73,6 +73,7 @@ internal abstract class ReportsVariantApplier(
asProducer()
attributes {
// common Kover artifact attributes
+ attribute(KoverMarkerAttr.ATTRIBUTE, project.objects.named("Kover"))
attribute(VariantNameAttr.ATTRIBUTE, project.objects.named(variantName))
attribute(ProjectPathAttr.ATTRIBUTE, project.objects.named(project.path))
}
@@ -83,6 +84,7 @@ internal abstract class ReportsVariantApplier(
dependencies = project.configurations.register(externalArtifactConfigurationName(variantName)) {
asConsumer()
+ isTransitive = false
extendsFrom(koverDependencies)
}
diff --git a/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/commons/Artifacts.kt b/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/commons/Artifacts.kt
index 2ae9842d..888a076f 100644
--- a/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/commons/Artifacts.kt
+++ b/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/commons/Artifacts.kt
@@ -54,7 +54,7 @@ internal fun ArtifactContent.write(artifactFile: File, rootDir: File) {
* Read Kover artifact content from the file.
*/
internal fun File.parseArtifactFile(rootDir: File): ArtifactContent {
- if (!exists()) return ArtifactContent(emptySet(), emptySet(), emptySet())
+ if (!exists() || !name.endsWith(".artifact")) return ArtifactContent(emptySet(), emptySet(), emptySet())
val iterator = readLines().iterator()
diff --git a/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/commons/Configurations.kt b/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/commons/Configurations.kt
index 242b9711..2511f97e 100644
--- a/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/commons/Configurations.kt
+++ b/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/commons/Configurations.kt
@@ -8,6 +8,18 @@ import org.gradle.api.*
import org.gradle.api.artifacts.*
import org.gradle.api.attributes.*
+/**
+ * Attribute to mark any Kover artifact.
+ */
+internal interface KoverMarkerAttr : Named {
+ companion object {
+ val ATTRIBUTE = Attribute.of(
+ "kotlinx.kover.marker",
+ VariantNameAttr::class.java
+ )
+ }
+}
+
/**
* Name of the published artifact.
*/