HprofDeobfuscatorTest.kt
TLDR
The HprofDeobfuscatorTest.kt
file contains test cases for the HprofDeobfuscator
class in the shark
package. It tests various scenarios where the HprofDeobfuscator
is used to deobfuscate class and field names in a Hprof format file.
Classes
HprofDeobfuscatorTest
This class contains test methods to validate the functionality of the HprofDeobfuscator
class. It creates mock Hprof files with obfuscated class and field names and asserts that the deobfuscated files contain the expected class and field names.
Methods
setUp()
This method is executed before each test method and is responsible for setting up the necessary resources for the test cases. It creates a temporary file named "temp.hprof" using the TemporaryFolder
rule.
deobfuscateHprofClassName()
This test method validates the deobfuscation of class names in a Hprof file. It creates a mock Hprof file with a class "a" and uses the HprofDeobfuscator
to deobfuscate the class name "Foo" mapped to "a". It asserts that the deobfuscated file contains the expected deobfuscated class name.
deobfuscateHprofStaticFieldName()
This test method validates the deobfuscation of static field names in a Hprof file. It creates a mock Hprof file with a class "a" containing a static field "b", and uses the HprofDeobfuscator
to deobfuscate the class name "Foo" mapped to "a". It asserts that the deobfuscated file contains the expected deobfuscated static field name.
deobfuscateHprofMemberFieldName()
This test method validates the deobfuscation of member field names in a Hprof file. It creates a mock Hprof file with a class "a" containing an instance field "b", and uses the HprofDeobfuscator
to deobfuscate the class name "Foo" mapped to "a". It asserts that the deobfuscated file contains the expected deobfuscated member field name.
deobfuscateHprofClassNameUsedAsFieldName()
This test method validates the deobfuscation of a class name used as a field name in a Hprof file. It creates a mock Hprof file with a class "a" containing an instance field with the same name "a", and uses the HprofDeobfuscator
to deobfuscate the class name "Foo" mapped to "a". It asserts that the deobfuscated file contains the expected deobfuscated field name.
deobfuscateHprofClassNameUsedAsStaticFieldName()
This test method validates the deobfuscation of a class name used as a static field name in a Hprof file. It creates a mock Hprof file with a class containing a static field with the same name as the class, and uses the HprofDeobfuscator
to deobfuscate the class name "Foo" mapped to "a". It asserts that the deobfuscated file contains the expected deobfuscated static field name.
deobfuscateHprofTwoFieldsWithSameName()
This test method validates the deobfuscation of two fields with the same name in different classes in a Hprof file. It creates a mock Hprof file with classes "Foo" and "Bar" containing fields with the same name "c" mapped to different obfuscated names, and uses the HprofDeobfuscator
to deobfuscate the class names and field names. It asserts that the deobfuscated file contains the expected deobfuscated field names for both classes.
File.readHprof(block: (HeapGraph) -> Unit)
This private extension method reads a Hprof file using the openHeapGraph
method of HprofHeapGraph
and executes a block of code with the resulting HeapGraph
object.
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 shark.ValueHolder.IntHolder
import java.io.File
import shark.HprofHeapGraph.Companion.openHeapGraph
class HprofDeobfuscatorTest {
@get:Rule
var testFolder = TemporaryFolder()
private lateinit var hprofFile: File
@Before
fun setUp() {
hprofFile = testFolder.newFile("temp.hprof")
}
@Test
fun deobfuscateHprofClassName() {
val proguardMapping = ProguardMapping().create {
clazz("Foo" to "a")
}
hprofFile.dump {
"a" clazz {}
}
val deobfuscator = HprofDeobfuscator()
val deobfuscatedFile = deobfuscator.deobfuscate(proguardMapping, hprofFile)
deobfuscatedFile.readHprof { graph ->
val fooClass = graph.findClassByName("Foo")
assertThat(fooClass).isNotNull
}
}
@Test
fun deobfuscateHprofStaticFieldName() {
val proguardMapping = ProguardMapping().create {
clazz("Foo" to "a") {
field { "staticField" to "b" }
}
}
hprofFile.dump {
"a" clazz {
staticField["b"] = IntHolder(42)
}
}
val deobfuscator = HprofDeobfuscator()
val deobfuscatedFile = deobfuscator.deobfuscate(proguardMapping, hprofFile)
deobfuscatedFile.readHprof { graph ->
val fooClass = graph.findClassByName("Foo")!!
assertThat(
fooClass.readStaticFields()
.map { it.name }
.toList()
).contains("staticField")
}
}
@Test
fun deobfuscateHprofMemberFieldName() {
val proguardMapping = ProguardMapping().create {
clazz("Foo" to "a") {
field { "instanceField" to "b" }
}
}
hprofFile.dump {
val classId = clazz(
className = "a",
fields = listOf("b" to IntHolder::class)
)
instance(classId, listOf(IntHolder(0)))
}
val deobfuscator = HprofDeobfuscator()
val deobfuscatedFile = deobfuscator.deobfuscate(proguardMapping, hprofFile)
deobfuscatedFile.readHprof { graph ->
val instance = graph.instances.find { heapInstance ->
heapInstance.instanceClassName == "Foo"
}!!
assertThat(
instance.readFields()
.map { it.name }
.toList()
).contains("instanceField")
}
}
@Test
fun deobfuscateHprofClassNameUsedAsFieldName() {
val proguardMapping = ProguardMapping().create {
clazz("Foo" to "a") {
field { "instanceField" to "a" }
}
}
hprofFile.dump {
val classNameRecord = stringRecord("a")
val classId = clazz(
classNameRecord = classNameRecord,
fields = listOf(classNameRecord.id to IntHolder::class)
)
instance(classId, listOf(IntHolder(0)))
}
val deobfuscator = HprofDeobfuscator()
val deobfuscatedFile = deobfuscator.deobfuscate(proguardMapping, hprofFile)
deobfuscatedFile.readHprof { graph ->
val instance = graph.instances.find { heapInstance ->
heapInstance.instanceClassName == "Foo"
}!!
assertThat(
instance.readFields()
.map { it.name }
.toList()
).contains("instanceField")
}
}
@Test
fun deobfuscateHprofClassNameUsedAsStaticFieldName() {
val proguardMapping = ProguardMapping().create {
clazz("Foo" to "a") {
field { "staticField" to "a" }
}
}
hprofFile.dump {
val classNameRecord = stringRecord("a")
clazz(
classNameRecord = classNameRecord,
staticFields = listOf(classNameRecord.id to IntHolder(42))
)
}
val deobfuscator = HprofDeobfuscator()
val deobfuscatedFile = deobfuscator.deobfuscate(proguardMapping, hprofFile)
deobfuscatedFile.readHprof { graph ->
val fooClass = graph.findClassByName("Foo")!!
assertThat(
fooClass.readStaticFields()
.map { it.name }
.toList()
).contains("staticField")
}
}
@Test
fun deobfuscateHprofTwoFieldsWithSameName() {
val proguardMapping = ProguardMapping().create {
clazz("Foo" to "a") {
field { "instanceField1" to "c" }
}
clazz("Bar" to "b") {
field { "instanceField2" to "c" }
}
}
hprofFile.dump {
val fooClassNameRecord = stringRecord("a")
val barClassNameRecord = stringRecord("b")
val fieldNameRecord = stringRecord("c")
val fooClassId = clazz(
classNameRecord = fooClassNameRecord,
fields = listOf(fieldNameRecord.id to IntHolder::class)
)
instance(fooClassId, listOf(IntHolder(0)))
val barClassId = clazz(
classNameRecord = barClassNameRecord,
fields = listOf(fieldNameRecord.id to IntHolder::class)
)
instance(barClassId, listOf(IntHolder(0)))
}
val deobfuscator = HprofDeobfuscator()
val deobfuscatedFile = deobfuscator.deobfuscate(proguardMapping, hprofFile)
deobfuscatedFile.readHprof { graph ->
val fooInstance = graph.instances.find { heapInstance ->
heapInstance.instanceClassName == "Foo"
}!!
assertThat(
fooInstance.readFields()
.map { it.name }
.toList()
).contains("instanceField1")
val barInstance = graph.instances.find { heapInstance ->
heapInstance.instanceClassName == "Bar"
}!!
assertThat(
barInstance.readFields()
.map { it.name }
.toList()
).contains("instanceField2")
}
}
private fun File.readHprof(block: (HeapGraph) -> Unit) {
openHeapGraph().use { block(it) }
}
}