diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index be0a074..b8a7941 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -33,6 +33,9 @@ jobs: - name: Publish bootstrap artifacts run: ./gradlew -p paranoid publishToMavenLocal -Ppablo.shadow.enabled=true ${{ env.PABLO_OPTS }} + - name: Run functional test + run: ./gradlew -p paranoid -Ppablo.shadow.enabled=true functionalTest + - name: Run unit tests run: ./gradlew check -x lint -Pdevelopment=false -Dorg.gradle.unsafe.configuration-cache=true diff --git a/paranoid/build.gradle b/paranoid/build.gradle index aec09d6..ae2c329 100644 --- a/paranoid/build.gradle +++ b/paranoid/build.gradle @@ -1,26 +1,49 @@ buildscript { apply from: '../versions.gradle' -} -allprojects { - group = PARANOID_GROUP - version = PARANOID_VERSION + allprojects { + group = PARANOID_GROUP + version = PARANOID_VERSION + + buildscript { + repositories { + google() + mavenCentral() + } + + dependencies { + classpath "com.android.tools.build:gradle:$androidToolsVersion" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" + classpath "io.michaelrocks.pablo:pablo:$pabloVersion" + } + } - buildscript { repositories { google() mavenCentral() } - - dependencies { - classpath "com.android.tools.build:gradle:$androidToolsVersion" - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" - classpath "io.michaelrocks.pablo:pablo:$pabloVersion" - } } +} - repositories { - google() - mavenCentral() +apply plugin: 'kotlin' + +dependencies { + testImplementation gradleTestKit() + testImplementation "junit:junit:$junitVersion" +} + +tasks.register("functionalTest", Test.class) { + description = "Runs the functional tests." + group = "verification" + + testClassesDirs = sourceSets.test.output.classesDirs + classpath = sourceSets.test.runtimeClasspath +} + +afterEvaluate { + tasks.named("functionalTest") { + subprojects.each { + dependsOn(it.tasks.named("publishToMavenLocal")) + } } } diff --git a/paranoid/pablo.gradle b/paranoid/pablo.gradle index 95d6539..e543f83 100644 --- a/paranoid/pablo.gradle +++ b/paranoid/pablo.gradle @@ -39,4 +39,8 @@ pablo { url = 'https://github.com/joomcode/paranoid' } } + + signing { + enabled.set(providers.gradleProperty("development").map { !it.toBoolean() }) + } } diff --git a/paranoid/src/test/java/com/joom/paranoid/plugin/ParanoidPluginTest.kt b/paranoid/src/test/java/com/joom/paranoid/plugin/ParanoidPluginTest.kt new file mode 100644 index 0000000..74d9a02 --- /dev/null +++ b/paranoid/src/test/java/com/joom/paranoid/plugin/ParanoidPluginTest.kt @@ -0,0 +1,142 @@ +package com.joom.paranoid.plugin + +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.BuildTask +import org.gradle.testkit.runner.GradleRunner +import org.gradle.testkit.runner.TaskOutcome +import org.intellij.lang.annotations.Language +import org.junit.Assert +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TemporaryFolder +import java.io.File + +class ParanoidPluginTest { + + @get:Rule + val temporaryFolder = TemporaryFolder() + + @Test + fun `agp version with legacy transform`() { + val projectRoot = createProjectDirectory(agpVersion = "7.1.0") + + val result = createGradleRunner(projectRoot).build() + + val tasks = result.parseDryRunExecution() + Assert.assertTrue(tasks.any { it.path == ":transformClassesWithParanoidForDebug" }) + } + + @Test + fun `agp version with all classes transform`() { + val projectRoot = createProjectDirectory(agpVersion = "7.2.0") + + val result = createGradleRunner(projectRoot).build() + + val tasks = result.parseDryRunExecution() + Assert.assertTrue(tasks.any { it.path == ":paranoidTransformClassesDebug" }) + } + + @Test + fun `actual agp version`() { + val projectRoot = createProjectDirectory(agpVersion = "7.4.2") + + val result = createGradleRunner(projectRoot).build() + + val tasks = result.parseDryRunExecution() + Assert.assertTrue(tasks.any { it.path == ":paranoidTransformClassesDebug" }) + } + + private fun createProjectDirectory(agpVersion: String): File { + val projectRoot = temporaryFolder.newFolder() + writeText(createBuildGradle(agpVersion), File(projectRoot, "build.gradle")) + writeText(ANDROID_MANIFEST, File(projectRoot, "src/main/AndroidManifest.xml")) + return projectRoot + } + + private fun createGradleRunner(projectDir: File): GradleRunner { + return GradleRunner.create() + .forwardOutput() + .withProjectDir(projectDir) + .withArguments("assembleDebug", "--dry-run", "--stacktrace") + } + + private fun BuildResult.parseDryRunExecution(): List { + val split = output.split('\n') + return split.mapNotNull { + if (it.startsWith(":")) { + val (path, _) = it.split(" ") + TestBuildTask(path = path, outcome = TaskOutcome.SKIPPED) + } else { + null + } + } + } + + private fun writeText(content: String, destination: File) { + if (!destination.parentFile.exists() && !destination.parentFile.mkdirs()) { + error("Failed to create parent directory ${destination.parentFile}") + } + + destination.writeText(content) + } + + @Language("gradle") + private fun createBuildGradle(agpVersion: String, compileSdk: Int = 31, buildToolsVersion: String = "30.0.3"): String { + return """ + buildscript { + repositories { + google() + mavenLocal() + mavenCentral() + } + + dependencies { + classpath "com.android.tools.build:gradle:$agpVersion" + classpath "com.joom.paranoid:paranoid-gradle-plugin:+" + } + } + + apply plugin: "com.android.application" + apply plugin: "com.joom.paranoid" + + repositories { + google() + mavenCentral() + } + + android { + compileSdk $compileSdk + buildToolsVersion "$buildToolsVersion" + + defaultConfig { + applicationId "com.joom.paranoid.test" + namespace "com.joom.paranoid.test" + versionCode 1 + versionName "1" + } + } + """.trimIndent() + } + + private companion object { + @Language("xml") + private const val ANDROID_MANIFEST = """ + + +""" + } + + private data class TestBuildTask( + private val path: String, + private val outcome: TaskOutcome, + ) : BuildTask { + override fun getPath(): String { + return path + } + + override fun getOutcome(): TaskOutcome { + return outcome + } + + } +}