package com.squareup.leakcanary.deobfuscation import org.assertj.core.api.Assertions.assertThat import org.gradle.testkit.runner.GradleRunner import org.gradle.testkit.runner.TaskOutcome.SUCCESS import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder import java.io.File import java.util.zip.ZipFile class LeakCanaryLeakDeobfuscationPluginTest { @get:Rule val tempFolder = TemporaryFolder() private lateinit var buildFile: File @Before fun setup() { buildFile = tempFolder.newFile("build.gradle") val localPropertiesFile = File("../local.properties") if (localPropertiesFile.exists()) { localPropertiesFile.copyTo(File(tempFolder.root, "local.properties"), overwrite = true) } else { System.getenv("ANDROID_HOME")?.let { androidHome -> tempFolder.newFile("local.properties").apply { writeText("sdk.dir=$androidHome") } } } File("src/test/test-project").copyRecursively(tempFolder.root) val proguardRules = tempFolder.newFile("proguard-rules.pro") proguardRules.writeText( """ -keep class com.leakcanary.test.** {*;} """.trimIndent() ) } @Test fun `leakcanary deobfuscation plugin runs and copies mapping file into the apk assets dir`() { buildFile.writeText( """ plugins { id 'com.android.application' id 'com.squareup.leakcanary.deobfuscation' } allprojects { repositories { google() jcenter() } } android { compileSdk 29 defaultConfig { minSdk 29 } buildTypes { debug { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } leakCanary { filterObfuscatedVariants { variant -> variant.name == "debug" } } """.trimIndent() ) val result = GradleRunner.create() .withProjectDir(tempFolder.root) .withArguments("clean", "assembleDebug") .withPluginClasspath() .build() // task has been run assertThat( result.task(":leakCanaryCopyObfuscationMappingForDebug")?.outcome == SUCCESS ).isTrue() // apk has been built val apkFile = File(tempFolder.root, "build/outputs/apk/debug") .listFiles() ?.firstOrNull { it.extension == "apk" } assertThat(apkFile != null).isTrue() // mapping file has been generated by proguard/r8 val mappingFile = File(tempFolder.root, "build/outputs/mapping/debug/mapping.txt") assertThat(mappingFile.exists()).isTrue() // apk contains obfuscation mapping file in assets dir val obfuscationMappingEntry = ZipFile(apkFile).use { zipFile -> zipFile.entries().toList().firstOrNull { entry -> entry.name.contains("assets/leakCanaryObfuscationMapping.txt") } } assertThat(obfuscationMappingEntry != null).isTrue() } @Test fun `leakcanary deobfuscation plugin doesn't copy mapping file if it hasn't been configured`() { buildFile.writeText( """ plugins { id 'com.squareup.leakcanary.deobfuscation' id 'com.android.application' } allprojects { repositories { google() jcenter() } } android { compileSdk 29 defaultConfig { minSdk 29 } buildTypes { debug { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } """.trimIndent() ) GradleRunner.create() .withProjectDir(tempFolder.root) .withArguments("clean", "assembleDebug") .withPluginClasspath() .build() // apk has been built val apkFile = File(tempFolder.root, "build/outputs/apk/debug") .listFiles() ?.firstOrNull { it.extension == "apk" } assertThat(apkFile != null).isTrue() // apk doesn't contain obfuscation mapping file in assets dir val obfuscationMappingEntry = ZipFile(apkFile).use { zipFile -> zipFile.entries().toList().firstOrNull { entry -> entry.name.contains("assets/leakCanaryObfuscationMapping.txt") } } assertThat(obfuscationMappingEntry == null).isTrue() } @Test fun `should throw if there is no variant with enabled minification`() { buildFile.writeText( """ plugins { id 'com.android.application' id 'com.squareup.leakcanary.deobfuscation' } allprojects { repositories { google() jcenter() } } android { compileSdk 29 defaultConfig { minSdk 29 } buildTypes { debug {} } } leakCanary { filterObfuscatedVariants { variant -> variant.name == "debug" } } """.trimIndent() ) val result = GradleRunner.create() .withProjectDir(tempFolder.root) .withArguments("clean", "assembleDebug") .withPluginClasspath() .buildAndFail() assertThat( result.output.contains( "LeakCanary deobfuscation plugin couldn't find any variant with minification enabled." ) ).isTrue() } }