main

square/leakcanary

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

HeapAnalysisStringRenderingTest.kt

TLDR

This file is a test class for the HeapAnalysisStringRendering class in the shark package. It contains three test methods: emptyFile(), successNoLeak(), and successWithLeaks(). Each test method sets up a scenario, performs an analysis, and tests the rendering of the analysis result using a regular expression.

Methods

emptyFile

This method sets up an empty file, initializes a HeapAnalyzer object, and analyzes the empty file. The analysis result is then tested against a regular expression to check if it matches the expected string.

successNoLeak

This method sets up a scenario by creating an hprof file with a single object of type "GcRoot" and performs a leak analysis on that file. The analysis result is then tested against a regular expression to check if it matches the expected string.

successWithLeaks

This method sets up a scenario by creating an hprof file with a single object of type "GcRoot" with a static field named "leak". It performs a leak analysis on that file and tests the analysis result against a regular expression to check if it matches the expected string.

package shark

import org.assertj.core.api.Assertions.assertThat
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
import java.io.File
import java.util.regex.Pattern

class HeapAnalysisStringRenderingTest {

  @get:Rule
  var testFolder = TemporaryFolder()
  private lateinit var hprofFile: File

  @Before
  fun setUp() {
    hprofFile = testFolder.newFile("temp.hprof")
  }

  @Test fun emptyFile() {
    val heapAnalyzer = HeapAnalyzer(OnAnalysisProgressListener.NO_OP)
    val analysis = heapAnalyzer.analyze(hprofFile, leakingObjectFinder = { error("never called") })

    analysis renders """
      |====================================
      |HEAP ANALYSIS FAILED
      |
      |You can report this failure at https://github.com/square/leakcanary/issues
      |Please provide the stacktrace, metadata and the heap dump file.
      |====================================
      |STACKTRACE
      |
      |java.lang.IllegalArgumentException: Source has no available bytes
      |.*
      |====================================
      |METADATA
      |
      |Build.VERSION.SDK_INT: -1
      |Build.MANUFACTURER: Unknown
      |LeakCanary version: Unknown
      |Analysis duration: \d* ms
      |Heap dump file path: ${hprofFile.absolutePath}
      |Heap dump timestamp: \d*
      |===================================="""
  }

  @Test fun successNoLeak() {
    hprofFile.dump {
      "GcRoot" clazz {}
    }

    val analysis = hprofFile.checkForLeaks<HeapAnalysis>()


    analysis renders """
      |====================================
      |HEAP ANALYSIS RESULT
      |====================================
      |0 APPLICATION LEAKS
      |
      |References underlined with "~~~" are likely causes.
      |Learn more at https://squ.re/leaks.
      |====================================
      |0 LIBRARY LEAKS
      |
      |A Library Leak is a leak caused by a known bug in 3rd party code that you do not have control over.
      |See https://square.github.io/leakcanary/fundamentals-how-leakcanary-works/#4-categorizing-leaks
      |====================================
      |0 UNREACHABLE OBJECTS
      |
      |An unreachable object is still in memory but LeakCanary could not find a strong reference path
      |from GC roots.
      |====================================
      |METADATA
      |
      |Please include this in bug reports and Stack Overflow questions.
      |
      |Analysis duration: \d* ms
      |Heap dump file path: ${hprofFile.absolutePath}
      |Heap dump timestamp: \d*
      |Heap dump duration: Unknown
      |===================================="""
  }

  @Test fun successWithLeaks() {
    hprofFile.dump {
      "GcRoot" clazz {
        staticField["leak"] = "Leaking" watchedInstance {}
      }
    }

    val analysis = hprofFile.checkForLeaks<HeapAnalysis>()


    analysis renders """
      |====================================
      |HEAP ANALYSIS RESULT
      |====================================
      |1 APPLICATION LEAKS
      |
      |References underlined with "~~~" are likely causes.
      |Learn more at https://squ.re/leaks.
      |
      |Signature: a49095c3373b957532aff14eb32987bb75ffe9d5
      |┬───
      |│ GC Root: System class
      |│
      |├─ GcRoot class
      |.*
      |====================================
      |0 LIBRARY LEAKS
      |
      |A Library Leak is a leak caused by a known bug in 3rd party code that you do not have control over.
      |See https://square.github.io/leakcanary/fundamentals-how-leakcanary-works/#4-categorizing-leaks
      |====================================
      |0 UNREACHABLE OBJECTS
      |
      |An unreachable object is still in memory but LeakCanary could not find a strong reference path
      |from GC roots.
      |====================================
      |METADATA
      |
      |Please include this in bug reports and Stack Overflow questions.
      |
      |Analysis duration: \d* ms
      |Heap dump file path: ${hprofFile.absolutePath}
      |Heap dump timestamp: \d*
      |Heap dump duration: Unknown
      |===================================="""
  }

  private infix fun HeapAnalysis.renders(multilineRegexString: String) {
    val regex: Pattern =
      Pattern.compile("^" + multilineRegexString.trimMargin() + "$", Pattern.DOTALL)
    assertThat(toString()).matches(regex)
  }
}