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

<lambda>null1 package shark
2 
3 import org.assertj.core.api.Assertions.assertThat
4 import org.junit.Test
5 import shark.LeakTraceObject.LeakingStatus.LEAKING
6 import shark.LeakTraceObject.LeakingStatus.NOT_LEAKING
7 import shark.LeakTraceObject.ObjectType.INSTANCE
8 
9 class AndroidObjectInspectorsTest {
10 
11   @Test fun `RECOMPOSER leaking status relies on state`() {
12     val hprofFile = "compose_leak.hprof".classpathFile()
13     val heapAnalyzer = HeapAnalyzer(OnAnalysisProgressListener.NO_OP)
14     val analysis = heapAnalyzer.analyze(
15       heapDumpFile = hprofFile,
16       leakingObjectFinder = { graph ->
17         val composeViewClass =
18           graph.findClassByName("androidx.compose.ui.platform.AndroidComposeView")
19         composeViewClass!!.instances.filter { instance ->
20           val filter = AndroidObjectInspectors.VIEW.leakingObjectFilter!!
21           filter.invoke(instance)
22           true
23         }.map { it.objectId }.toSet()
24       },
25       referenceMatchers = AndroidReferenceMatchers.appDefaults,
26       objectInspectors = AndroidObjectInspectors.appDefaults
27     )
28     println(analysis)
29     analysis as HeapAnalysisSuccess
30     val recomposerNode = analysis.applicationLeaks.single()
31       .leakTraces.single()
32       .referencePath.single {
33         it.originObject.type == INSTANCE
34           && it.owningClassSimpleName == "Recomposer"
35       }
36     assertThat(recomposerNode.originObject.leakingStatus == NOT_LEAKING)
37     assertThat(recomposerNode.originObject.leakingStatusReason == "Recomposer is in state PendingWork")
38   }
39 
40   @Test fun `COMPOSITION_IMPL leaking status relies on disposal`() {
41     val hprofFile = "compose_leak.hprof".classpathFile()
42     val heapAnalyzer = HeapAnalyzer(OnAnalysisProgressListener.NO_OP)
43     val analysis = heapAnalyzer.analyze(
44       heapDumpFile = hprofFile,
45       leakingObjectFinder = { graph ->
46         val composeViewClass =
47           graph.findClassByName("androidx.compose.ui.platform.AndroidComposeView")
48         composeViewClass!!.instances.filter { instance ->
49           val filter = AndroidObjectInspectors.VIEW.leakingObjectFilter!!
50           filter.invoke(instance)
51           true
52         }.map { it.objectId }.toSet()
53       },
54       referenceMatchers = AndroidReferenceMatchers.appDefaults,
55       objectInspectors = AndroidObjectInspectors.appDefaults
56     )
57     println(analysis)
58     analysis as HeapAnalysisSuccess
59     val recomposerNode = analysis.applicationLeaks.single()
60       .leakTraces.single()
61       .referencePath.single {
62         it.owningClassSimpleName == "CompositionImpl"
63       }
64     assertThat(recomposerNode.originObject.leakingStatus == LEAKING)
65     assertThat(recomposerNode.originObject.leakingStatusReason == "Composition disposed")
66   }
67 }
68