main

square/leakcanary

Last updated at: 29/12/2023 09:37

LeakCanaryLeakDeobfuscationPluginTest.kt

TLDR

This file contains the unit tests for the LeakCanaryLeakDeobfuscationPlugin class in the leakcanary.deobfuscation package.

Methods

No methods are defined in this file.

Classes

LeakCanaryLeakDeobfuscationPluginTest

This class contains unit tests for the LeakCanaryLeakDeobfuscationPlugin class. The tests verify that the plugin correctly copies the mapping file into the APK assets directory, doesn't copy the mapping file if it hasn't been configured, and throws an exception if there is no variant with enabled minification.

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 {
          namespace 'com.leakcanary.test'
          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 {
          namespace 'com.leakcanary.test'
          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 {
          namespace 'com.leakcanary.test'
          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()
  }
}