Skip to content

Commit

Permalink
Added support for KMP/JVM targets (#196)
Browse files Browse the repository at this point in the history
  • Loading branch information
gmazzo authored Nov 26, 2024
1 parent 05974a1 commit 3ce120a
Show file tree
Hide file tree
Showing 26 changed files with 211 additions and 12 deletions.
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ plugins {
alias(libs.plugins.android.test) apply false
alias(libs.plugins.kotlin.jvm) apply false
alias(libs.plugins.kotlin.android) apply false
alias(libs.plugins.kotlin.multiplatform) apply false
alias(libs.plugins.publicationsReport)
}

Expand Down
2 changes: 1 addition & 1 deletion demo-project/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,6 @@ dependencies {
implementation(libs.androidx.navigation.fragment)
implementation(libs.androidx.navigation.ui)

testImplementation(libs.junit)
testImplementation(libs.kotlin.test)
testImplementation(libs.robolectric)
}
7 changes: 6 additions & 1 deletion demo-project/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ plugins {

testAggregation {
modules {
include(projects.demoProject.app, projects.demoProject.domain, projects.demoProject.login)
include(
projects.demoProject.app,
projects.demoProject.domain,
projects.demoProject.login,
projects.demoProject.kmp,
)
exclude(rootProject)
}
coverage {
Expand Down
2 changes: 1 addition & 1 deletion demo-project/domain/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ plugins {
java.toolchain.languageVersion.set(JavaLanguageVersion.of(11))

dependencies {
testImplementation(libs.junit)
testImplementation(libs.kotlin.test)
}
34 changes: 34 additions & 0 deletions demo-project/kmp/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension

plugins {
alias(libs.plugins.android.lib)
alias(libs.plugins.kotlin.multiplatform)
}

afterEvaluate {
rootProject.the<NodeJsRootExtension>().download = false
rootProject.the<YarnRootExtension>().download = false
}

java.toolchain.languageVersion.set(JavaLanguageVersion.of(11))

android {
namespace = "com.example.login"

compileSdk = libs.versions.android.compileSDK.get().toInt()
defaultConfig {
minSdk = libs.versions.android.minSDK.get().toInt()
}
}

kotlin {
androidTarget()
jvm()
js { nodejs() }
}

dependencies {
commonTestImplementation(libs.kotlin.test)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.example.kmp

object KMPObjectAndroid {

val platform = PLATFORM

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.example.kmp

internal actual val PLATFORM = "android"
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.example.kmp

import kotlin.test.Test
import kotlin.test.assertEquals

class KMPObjectAndroidTest {

@Test
fun testKMPObject() {
assertEquals(PLATFORM, KMPObjectAndroid.platform)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.example.kmp

object KMPObject {

val platform = PLATFORM

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.example.kmp

internal expect val PLATFORM: String
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.example.kmp

import kotlin.test.Test
import kotlin.test.assertEquals

class KMPObjectTest {

@Test
fun testKMPObject() {
assertEquals(PLATFORM, KMPObject.platform)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.example.kmp

object KMPObjectJS {

val platform = PLATFORM

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.example.kmp

internal actual val PLATFORM = "js"
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.example.kmp

import kotlin.test.Test
import kotlin.test.assertEquals

class KMPObjectJSTest {

@Test
fun testKMPObject() {
assertEquals(PLATFORM, KMPObjectJS.platform)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.example.kmp

object KMPObjectJVM {

val platform = PLATFORM

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.example.kmp

internal actual val PLATFORM = "jvm"
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.example.kmp

import kotlin.test.Test
import kotlin.test.assertEquals

class KMPObjectJVMTest {

@Test
fun testKMPObject() {
assertEquals(PLATFORM, KMPObjectJVM.platform)
}

}
2 changes: 1 addition & 1 deletion demo-project/login/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ dependencies {
implementation(libs.androidx.livedata)
implementation(libs.androidx.viewmodel)

testImplementation(libs.junit)
testImplementation(libs.kotlin.test)

androidTestImplementation(libs.androidx.test.junit)
androidTestImplementation(libs.androidx.test.espresso)
Expand Down
3 changes: 2 additions & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ androidx-viewmodel = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", ve
androidx-test-junit = "androidx.test.ext:junit:1.2.1"
androidx-test-espresso = "androidx.test.espresso:espresso-core:3.6.1"
google-material = "com.google.android.material:material:1.12.0"
junit = "junit:junit:4.13.2"
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
robolectric = "org.robolectric:robolectric:4.14.1"

[plugins]
Expand All @@ -28,6 +28,7 @@ android-test = { id = "com.android.test", version.ref = "agp" }
android-baseline = { id = "androidx.baselineprofile", version = "1.3.3" }
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
kotlin-samReceiver = { id = "org.jetbrains.kotlin.plugin.sam.with.receiver", version.ref = "kotlin" }
gradle-pluginPublish = { id = "com.gradle.plugin-publish", version = "1.3.0" }
publicationsReport = { id = "io.github.gmazzo.publications.report", version = "1.2.8" }
4 changes: 3 additions & 1 deletion plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,14 @@ dependencies {

compileOnly(gradleKotlinDsl())
compileOnly(plugin(libs.plugins.android))
compileOnly(plugin(libs.plugins.kotlin.multiplatform))

testImplementation(gradleKotlinDsl())
testImplementation(plugin(libs.plugins.android))
testImplementation(plugin(libs.plugins.kotlin.multiplatform))
}

testing.suites.withType<JvmTestSuite>() {
testing.suites.withType<JvmTestSuite> {
useKotlinTest(libs.versions.kotlin)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

package io.github.gmazzo.android.test.aggregation

import com.android.build.api.dsl.BuildType
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.plugins.ExtensionAware
import org.gradle.api.provider.Property
import org.gradle.kotlin.dsl.aggregateTestCoverage
import org.gradle.kotlin.dsl.apply
Expand All @@ -29,6 +31,13 @@ internal abstract class AndroidTestBaseAggregationPlugin : Plugin<Project> {
objects.property<Boolean>()
)
}
onKotlinJVMTargets {
(this as ExtensionAware).extensions.add(
typeOf<Property<Boolean>>(),
::aggregateTestCoverage.name,
objects.property<Boolean>()
)
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@ import org.gradle.api.attributes.VerificationType
import org.gradle.api.file.Directory
import org.gradle.api.file.DuplicatesStrategy
import org.gradle.api.file.RegularFile
import org.gradle.api.internal.provider.Providers
import org.gradle.api.plugins.ExtensionAware
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.Sync
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.testing.AbstractTestTask
import org.gradle.kotlin.dsl.USAGE_TEST_AGGREGATION
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.configure
Expand All @@ -31,7 +35,10 @@ import org.gradle.kotlin.dsl.property
import org.gradle.kotlin.dsl.provideDelegate
import org.gradle.kotlin.dsl.registering
import org.gradle.kotlin.dsl.the
import org.gradle.kotlin.dsl.invoke
import org.gradle.testing.jacoco.plugins.JacocoTaskExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.MAIN_COMPILATION_NAME

abstract class AndroidTestCoverageAggregationPlugin : Plugin<Project> {

Expand All @@ -55,7 +62,7 @@ abstract class AndroidTestCoverageAggregationPlugin : Plugin<Project> {
})
}

configurations.create("codeCoverageExecutionData") {
val codeCoverageExecutionData by configurations.registering {
isCanBeConsumed = true
isCanBeResolved = false
isVisible = false
Expand All @@ -73,10 +80,7 @@ abstract class AndroidTestCoverageAggregationPlugin : Plugin<Project> {
}
afterEvaluate {
jacocoVariants.all variant@{
val execData = unitTestTaskOf(this@variant)!!
.map { it.the<JacocoTaskExtension>().destinationFile!! }

outgoing.artifact(execData) {
outgoing.artifact(unitTestTaskOf(this@variant)!!.execData) {
type = ArtifactTypeDefinition.BINARY_DATA_TYPE
}
}
Expand Down Expand Up @@ -154,6 +158,24 @@ abstract class AndroidTestCoverageAggregationPlugin : Plugin<Project> {
type = ArtifactTypeDefinition.JVM_CLASS_DIRECTORY
}
}

onKotlinJVMTargets variant@{
val main = compilations[MAIN_COMPILATION_NAME]

codeCoverageExecutionData.configure {
outgoing.artifact(unitTestTaskOf(this@variant).execData) {
type = ArtifactTypeDefinition.BINARY_DATA_TYPE
}
}
allVariantsSourcesForCoverageReport.configure {
main.allKotlinSourceSets.forAll {
from(it.kotlin.srcDirs)
}
}
allVariantsClassesForCoverageReport.configure {
from(main.output.classesDirs)
}
}
}

private fun Project.addRobolectricTestsSupport() {
Expand All @@ -178,4 +200,7 @@ abstract class AndroidTestCoverageAggregationPlugin : Plugin<Project> {
}
}

private val TaskProvider<AbstractTestTask>.execData
get() = map { it.the<JacocoTaskExtension>().destinationFile!! }

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package io.github.gmazzo.android.test.aggregation
import com.android.build.api.variant.HasUnitTest
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.attributes.Category
import org.gradle.api.attributes.TestSuiteType
import org.gradle.api.attributes.Usage
import org.gradle.api.attributes.VerificationType
import org.gradle.kotlin.dsl.USAGE_TEST_AGGREGATION
import org.gradle.kotlin.dsl.aggregateTestCoverage
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.named

Expand Down Expand Up @@ -41,6 +43,14 @@ abstract class AndroidTestResultsAggregationPlugin : Plugin<Project> {
if (aggregate) listOf(unitTestTaskOf(variant)!!.flatMap { it.binaryResultsDirectory }) else emptyList()
})
}

onKotlinJVMTargets target@{
testResultsElements.outgoing.artifacts(provider {
val aggregate = this@target.aggregateTestCoverage.getOrElse(true)

if (aggregate) listOf(unitTestTaskOf(this@target).flatMap { it.binaryResultsDirectory }) else emptyList()
})
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,16 @@ import org.gradle.kotlin.dsl.aggregateTestCoverage
import org.gradle.kotlin.dsl.create
import org.gradle.kotlin.dsl.findByType
import org.gradle.kotlin.dsl.get
import org.gradle.kotlin.dsl.withType
import org.gradle.kotlin.dsl.getByName
import org.gradle.kotlin.dsl.named
import org.gradle.kotlin.dsl.testAggregation
import org.gradle.kotlin.dsl.the
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetsContainer
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMetadataTarget
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget

internal val Project.android
get() = the<BaseExtension>()
Expand Down Expand Up @@ -62,4 +68,12 @@ private fun TestAggregationExtension.Modules.includes(project: Project) =

internal fun Project.unitTestTaskOf(variant: Variant) = (variant as? HasUnitTest)
?.unitTest
?.let { tasks.named<AbstractTestTask>("test${it.name.capitalized()}") }
?.let { tasks.named<AbstractTestTask>("test${it.name.replaceFirstChar { it.uppercase() }}") }

internal fun Project.unitTestTaskOf(target: KotlinTarget) =
tasks.named<AbstractTestTask>("${(target.disambiguationClassifier ?: target.name)}Test")

internal fun Project.onKotlinJVMTargets(action: KotlinJvmTarget.() -> Unit) = plugins.withId("kotlin-multiplatform") {
the<KotlinTargetsContainer>().targets
.withType<KotlinJvmTarget>(action)
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import org.gradle.api.artifacts.Dependency
import org.gradle.api.artifacts.ProjectDependency
import org.gradle.api.artifacts.dsl.DependencyHandler
import org.gradle.api.attributes.Usage
import org.gradle.api.plugins.ExtensionAware
import org.gradle.api.provider.Property
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget

const val USAGE_TEST_AGGREGATION = "test-aggregation"

Expand All @@ -26,3 +28,6 @@ val BuildType.aggregateTestCoverage: Property<Boolean>

val ProductFlavor.aggregateTestCoverage: Property<Boolean>
get() = extensions.getByName<Property<Boolean>>(::aggregateTestCoverage.name)

val KotlinTarget.aggregateTestCoverage: Property<Boolean>
get() = (this as ExtensionAware).extensions.getByName<Property<Boolean>>(::aggregateTestCoverage.name)
Loading

0 comments on commit 3ce120a

Please sign in to comment.