xref: /aosp_15_r20/external/leakcanary2/shark-android/src/test/java/shark/AndroidResourceIdNamesTest.kt (revision d9e8da70d8c9df9a41d7848ae506fb3115cae6e6)

<lambda>null1 package shark
2 
3 import com.nhaarman.mockitokotlin2.any
4 import com.nhaarman.mockitokotlin2.mock
5 import com.nhaarman.mockitokotlin2.verify
6 import com.nhaarman.mockitokotlin2.whenever
7 import org.assertj.core.api.Assertions.assertThat
8 import org.junit.After
9 import org.junit.Before
10 import org.junit.Rule
11 import org.junit.Test
12 import org.junit.rules.TemporaryFolder
13 import shark.AndroidResourceIdNames.Companion.FIRST_APP_RESOURCE_ID
14 import shark.AndroidResourceIdNames.Companion.RESOURCE_ID_TYPE_ITERATOR
15 import java.io.File
16 
17 class AndroidResourceIdNamesTest {
18 
19   @get:Rule
20   var testFolder = TemporaryFolder()
21 
22   @Before fun setUp() {
23     AndroidResourceIdNames.resetForTests()
24   }
25 
26   @After fun tearDown() {
27     AndroidResourceIdNames.resetForTests()
28   }
29 
30   @Test fun `saveToMemory call is cached`() {
31     val getResourceTypeName: (Int) -> String? = mock()
32 
33     for (i in 0..2) {
34       AndroidResourceIdNames.saveToMemory(
35         getResourceTypeName = getResourceTypeName,
36         getResourceEntryName = { null }
37       )
38     }
39 
40     verify(getResourceTypeName).invoke(any())
41   }
42 
43   @Test fun `AndroidResourceIdNames available in heap dump when saveToMemory is called`() {
44     AndroidResourceIdNames.saveToMemory(
45       getResourceTypeName = { null }, getResourceEntryName = { null })
46 
47     dumpAndReadHeap { resIdNames ->
48       assertThat(resIdNames).isNotNull
49     }
50   }
51 
52   @Test fun `AndroidResourceIdNames not available in heap dump when saveToMemory is not called`() {
53     dumpAndReadHeap { resIdNames ->
54       assertThat(resIdNames).isNull()
55     }
56   }
57 
58   @Test fun `saveToMemory stores and retrieves resource id`() {
59     val firstIdResourceId = FIRST_APP_RESOURCE_ID
60 
61     val getResourceTypeName =
62       createGetResourceTypeName(mapOf(firstIdResourceId to "id"))
63 
64     val getResourceEntryName =
65       createGetResourceEntryName(mapOf(FIRST_APP_RESOURCE_ID to "view_container"))
66 
67     AndroidResourceIdNames.saveToMemory(getResourceTypeName, getResourceEntryName)
68 
69     dumpAndReadHeap { resIdNames ->
70       assertThat(resIdNames!![firstIdResourceId]).isEqualTo("view_container")
71     }
72   }
73 
74   @Test fun `id type starts after layout`() {
75     val layoutResourceId = FIRST_APP_RESOURCE_ID
76     val firstIdResourceId = layoutResourceId + RESOURCE_ID_TYPE_ITERATOR
77 
78     val getResourceTypeName =
79       createGetResourceTypeName(
80         mapOf(
81           layoutResourceId to "layout",
82           firstIdResourceId to "id"
83         )
84       )
85     val getResourceEntryName =
86       createGetResourceEntryName(mapOf(firstIdResourceId to "view_container"))
87 
88     AndroidResourceIdNames.saveToMemory(getResourceTypeName, getResourceEntryName)
89 
90     dumpAndReadHeap { resIdNames ->
91       assertThat(resIdNames!![firstIdResourceId]).isEqualTo("view_container")
92     }
93   }
94 
95   @Test fun `two consecutive id resource ids`() {
96     val firstIdResourceId = FIRST_APP_RESOURCE_ID
97     val secondIdResourceId = FIRST_APP_RESOURCE_ID + 1
98 
99     val getResourceTypeName =
100       createGetResourceTypeName(
101         mapOf(
102           firstIdResourceId to "id"
103         )
104       )
105     val getResourceEntryName = createGetResourceEntryName(
106       mapOf(
107         firstIdResourceId to "view_container",
108         secondIdResourceId to "menu_button"
109       )
110     )
111 
112     AndroidResourceIdNames.saveToMemory(getResourceTypeName, getResourceEntryName)
113 
114     dumpAndReadHeap { resIdNames ->
115       assertThat(resIdNames!![secondIdResourceId]).isEqualTo("menu_button")
116     }
117   }
118 
119   private fun createGetResourceEntryName(resourceIdMap: Map<Int, String>): (Int) -> String? {
120     val getResourceEntryName: (Int) -> String? = mock()
121     resourceIdMap.forEach { (resourceId, resourceName) ->
122       whenever(getResourceEntryName.invoke(resourceId)).thenReturn(resourceName)
123     }
124     return getResourceEntryName
125   }
126 
127   private fun createGetResourceTypeName(resourceIdMap: Map<Int, String>): (Int) -> String? {
128     val getResourceTypeName: (Int) -> String? = mock()
129     resourceIdMap.forEach { (resourceId, resourceName) ->
130       whenever(getResourceTypeName.invoke(resourceId)).thenReturn(resourceName)
131     }
132     return getResourceTypeName
133   }
134 
135   fun dumpAndReadHeap(block: (AndroidResourceIdNames?) -> Unit) {
136     val hprofFolder = testFolder.newFolder()
137     val hprofFile = File(hprofFolder, "heapdump.hprof")
138     JvmTestHeapDumper.dumpHeap(hprofFile.absolutePath)
139     Hprof.open(hprofFile)
140       .use { hprof ->
141         val graph = HprofHeapGraph.indexHprof(hprof)
142         val idNames = AndroidResourceIdNames.readFromHeap(graph)
143         block(idNames)
144       }
145   }
146 }