main

square/leakcanary

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

AndroidResourceIdNamesTest.kt

TLDR

The AndroidResourceIdNamesTest file is a test file that contains tests for the AndroidResourceIdNames class. These tests verify the functionality of methods related to caching, saving and retrieving resource IDs in Android applications.

Methods

setUp

This method is executed before each test and is responsible for resetting the AndroidResourceIdNames state for testing purposes.

tearDown

This method is executed after each test and is responsible for resetting the AndroidResourceIdNames state for testing purposes.

saveToMemory call is cached

This test verifies that the saveToMemory method caches the resource type names by mocking the getResourceTypeName function and checking if it is invoked the expected number of times.

AndroidResourceIdNames available in heap dump when saveToMemory is called

This test verifies that the AndroidResourceIdNames is available in the heap dump after calling the saveToMemory method. It uses a temporary heap dump file, reads the heap using openHeapGraph, and checks if the resIdNames are not null.

AndroidResourceIdNames not available in heap dump when saveToMemory is not called

This test verifies that the AndroidResourceIdNames is not available in the heap dump if the saveToMemory method is not called. It uses a temporary heap dump file, reads the heap using openHeapGraph, and checks if the resIdNames are null.

saveToMemory stores and retrieves resource id

This test verifies that the saveToMemory method properly stores and retrieves resource IDs. It uses a mock getResourceTypeName and getResourceEntryName functions to simulate the mappings and checks if the retrieved resource ID matches the expected value.

id type starts after layout

This test verifies that the ID resource type starts after the layout resource type. It uses a mock getResourceTypeName and getResourceEntryName functions to simulate the mappings and checks if the retrieved resource ID matches the expected value.

two consecutive id resource ids

This test verifies that two consecutive ID resource IDs are properly saved and retrieved. It uses a mock getResourceTypeName and getResourceEntryName functions to simulate the mappings and checks if the retrieved resource ID matches the expected value.

dumpAndReadHeap

This method is a helper method used by the above tests to create a temporary heap dump file, read the heap using openHeapGraph, and perform operations on the heap data. It takes a block of code as a parameter that accepts the AndroidResourceIdNames and performs the necessary operations.

Classes

There are no additional classes in this file.

package shark

import com.nhaarman.mockitokotlin2.any
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.verify
import com.nhaarman.mockitokotlin2.whenever
import java.io.File
import org.assertj.core.api.Assertions.assertThat
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
import shark.AndroidResourceIdNames.Companion.FIRST_APP_RESOURCE_ID
import shark.AndroidResourceIdNames.Companion.RESOURCE_ID_TYPE_ITERATOR
import shark.HprofHeapGraph.Companion.openHeapGraph

class AndroidResourceIdNamesTest {

  @get:Rule
  var testFolder = TemporaryFolder()

  @Before fun setUp() {
    AndroidResourceIdNames.resetForTests()
  }

  @After fun tearDown() {
    AndroidResourceIdNames.resetForTests()
  }

  @Test fun `saveToMemory call is cached`() {
    val getResourceTypeName: (Int) -> String? = mock()

    for (i in 0..2) {
      AndroidResourceIdNames.saveToMemory(
        getResourceTypeName = getResourceTypeName,
        getResourceEntryName = { null }
      )
    }

    verify(getResourceTypeName).invoke(any())
  }

  @Test fun `AndroidResourceIdNames available in heap dump when saveToMemory is called`() {
    AndroidResourceIdNames.saveToMemory(
      getResourceTypeName = { null }, getResourceEntryName = { null })

    dumpAndReadHeap { resIdNames ->
      assertThat(resIdNames).isNotNull
    }
  }

  @Test fun `AndroidResourceIdNames not available in heap dump when saveToMemory is not called`() {
    dumpAndReadHeap { resIdNames ->
      assertThat(resIdNames).isNull()
    }
  }

  @Test fun `saveToMemory stores and retrieves resource id`() {
    val firstIdResourceId = FIRST_APP_RESOURCE_ID

    val getResourceTypeName =
      createGetResourceTypeName(mapOf(firstIdResourceId to "id"))

    val getResourceEntryName =
      createGetResourceEntryName(mapOf(FIRST_APP_RESOURCE_ID to "view_container"))

    AndroidResourceIdNames.saveToMemory(getResourceTypeName, getResourceEntryName)

    dumpAndReadHeap { resIdNames ->
      assertThat(resIdNames!![firstIdResourceId]).isEqualTo("view_container")
    }
  }

  @Test fun `id type starts after layout`() {
    val layoutResourceId = FIRST_APP_RESOURCE_ID
    val firstIdResourceId = layoutResourceId + RESOURCE_ID_TYPE_ITERATOR

    val getResourceTypeName =
      createGetResourceTypeName(
        mapOf(
          layoutResourceId to "layout",
          firstIdResourceId to "id"
        )
      )
    val getResourceEntryName =
      createGetResourceEntryName(mapOf(firstIdResourceId to "view_container"))

    AndroidResourceIdNames.saveToMemory(getResourceTypeName, getResourceEntryName)

    dumpAndReadHeap { resIdNames ->
      assertThat(resIdNames!![firstIdResourceId]).isEqualTo("view_container")
    }
  }

  @Test fun `two consecutive id resource ids`() {
    val firstIdResourceId = FIRST_APP_RESOURCE_ID
    val secondIdResourceId = FIRST_APP_RESOURCE_ID + 1

    val getResourceTypeName =
      createGetResourceTypeName(
        mapOf(
          firstIdResourceId to "id"
        )
      )
    val getResourceEntryName = createGetResourceEntryName(
      mapOf(
        firstIdResourceId to "view_container",
        secondIdResourceId to "menu_button"
      )
    )

    AndroidResourceIdNames.saveToMemory(getResourceTypeName, getResourceEntryName)

    dumpAndReadHeap { resIdNames ->
      assertThat(resIdNames!![secondIdResourceId]).isEqualTo("menu_button")
    }
  }

  private fun createGetResourceEntryName(resourceIdMap: Map<Int, String>): (Int) -> String? {
    val getResourceEntryName: (Int) -> String? = mock()
    resourceIdMap.forEach { (resourceId, resourceName) ->
      whenever(getResourceEntryName.invoke(resourceId)).thenReturn(resourceName)
    }
    return getResourceEntryName
  }

  private fun createGetResourceTypeName(resourceIdMap: Map<Int, String>): (Int) -> String? {
    val getResourceTypeName: (Int) -> String? = mock()
    resourceIdMap.forEach { (resourceId, resourceName) ->
      whenever(getResourceTypeName.invoke(resourceId)).thenReturn(resourceName)
    }
    return getResourceTypeName
  }

  fun dumpAndReadHeap(block: (AndroidResourceIdNames?) -> Unit) {
    val hprofFolder = testFolder.newFolder()
    val hprofFile = File(hprofFolder, "heapdump.hprof")
    JvmTestHeapDumper.dumpHeap(hprofFile.absolutePath)
    hprofFile.openHeapGraph().use {graph ->
      val idNames = AndroidResourceIdNames.readFromHeap(graph)
      block(idNames)
    }
  }
}