blob: 4f50bb916a4fc8713313080212db4210afea3a2c [file] [log] [blame]
package com.squareup.leakcanary;
import com.squareup.haha.perflib.ArrayInstance;
import com.squareup.haha.perflib.ClassInstance;
import com.squareup.haha.perflib.ClassObj;
import com.squareup.haha.perflib.Field;
import com.squareup.haha.perflib.Snapshot;
import com.squareup.haha.perflib.Type;
import com.squareup.haha.perflib.io.HprofBuffer;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@RunWith(JUnit4.class)
public class HahaHelperTest {
private static final int STRING_CLASS_ID = 100;
private static final int CHAR_ARRAY_CLASS_ID = 101;
private static final int STRING_INSTANCE_ID = 102;
private static final int VALUE_ARRAY_INSTANCE_ID = 103;
private static final int BYTE_ARRAY_CLASS_ID = 104;
private static final int VALUE_ARRAY_LENGTH = 6;
private static final int COUNT_VALUE = 5;
private static final int OFFSET_VALUE = 1;
private FakeHprofBuffer buffer;
private Snapshot snapshot;
@Before
public void setUp() {
buffer = new FakeHprofBuffer();
initSnapshot(buffer);
}
private void initSnapshot(HprofBuffer buffer) {
snapshot = new Snapshot(buffer);
// set HPROF identifier size; required for Object instance field lookups
// cf. https://java.net/downloads/heap-snapshot/hprof-binary-format.html
snapshot.setIdSize(4);
}
@Test public void readStringOffsetFromHeapDumpInstance_pre_O() {
buffer.setIntsToRead(COUNT_VALUE, OFFSET_VALUE, VALUE_ARRAY_INSTANCE_ID);
buffer.setStringsToRead("abcdef");
addStringClassToSnapshotWithFields(snapshot, new Field[]{
new Field(Type.INT, "count"),
new Field(Type.INT, "offset"),
new Field(Type.OBJECT, "value")
});
ClassInstance stringInstance = createStringInstance();
createCharArrayValueInstance();
String actual = HahaHelper.asString(stringInstance);
assertTrue(actual.equals("bcdef"));
}
@Test public void defaultToZeroStringOffsetWhenHeapDumpInstanceIsMissingOffsetValue_pre_O() {
buffer.setIntsToRead(COUNT_VALUE, VALUE_ARRAY_INSTANCE_ID);
buffer.setStringsToRead("abcdef");
addStringClassToSnapshotWithFields(snapshot, new Field[]{
new Field(Type.INT, "count"),
new Field(Type.OBJECT, "value")
});
ClassInstance stringInstance = createStringInstance();
createCharArrayValueInstance();
String actual = HahaHelper.asString(stringInstance);
assertTrue(actual.equals("abcde"));
}
@Test public void readStringAsByteArrayFromHeapDumpInstance_O() {
// O uses default charset UTF-8
buffer = new FakeHprofBuffer("UTF-8");
initSnapshot(buffer);
buffer.setIntsToRead(COUNT_VALUE, VALUE_ARRAY_INSTANCE_ID);
buffer.setStringsToRead("abcdef");
addStringClassToSnapshotWithFields_O(snapshot, new Field[]{
new Field(Type.INT, "count"),
new Field(Type.OBJECT, "value")
});
ClassInstance stringInstance = createStringInstance();
createByteArrayValueInstance();
String actual = HahaHelper.asString(stringInstance);
assertTrue(actual.equals("abcde"));
}
@Test public void throwExceptionWhenNotArrayValueForString() {
buffer.setIntsToRead(COUNT_VALUE, OFFSET_VALUE, VALUE_ARRAY_INSTANCE_ID);
buffer.setStringsToRead("abcdef");
addStringClassToSnapshotWithFields(snapshot, new Field[]{
new Field(Type.INT, "count"),
new Field(Type.INT, "offset"),
new Field(Type.OBJECT, "value")
});
ClassInstance stringInstance = createStringInstance();
createObjectValueInstance();
try {
HahaHelper.asString(stringInstance);
fail("this test should have thrown UnsupportedOperationException");
}
catch (UnsupportedOperationException uoe) {
String message = uoe.getMessage();
assertTrue(message.equals("Could not find char array in " + stringInstance));
}
}
private void addStringClassToSnapshotWithFields(Snapshot snapshot, Field[] fields) {
ClassObj charArrayClass = new ClassObj(0, null, "char[]", 0);
snapshot.addClass(CHAR_ARRAY_CLASS_ID, charArrayClass);
ClassObj stringClass = new ClassObj(0, null, "string", 0);
stringClass.setFields(fields);
snapshot.addClass(STRING_CLASS_ID, stringClass);
}
private void addStringClassToSnapshotWithFields_O(Snapshot snapshot, Field[] fields) {
ClassObj byteArrayClass = new ClassObj(0, null, "byte[]", 0);
snapshot.addClass(BYTE_ARRAY_CLASS_ID, byteArrayClass);
ClassObj stringClass = new ClassObj(0, null, "string", 0);
stringClass.setFields(fields);
snapshot.addClass(STRING_CLASS_ID, stringClass);
}
private void createCharArrayValueInstance() {
ArrayInstance valueArrayInstance = new ArrayInstance(0, null, Type.CHAR, VALUE_ARRAY_LENGTH, 0);
snapshot.addInstance(VALUE_ARRAY_INSTANCE_ID, valueArrayInstance);
}
private void createByteArrayValueInstance() {
ArrayInstance valueArrayInstance = new ArrayInstance(0, null, Type.BYTE, VALUE_ARRAY_LENGTH, 0);
snapshot.addInstance(VALUE_ARRAY_INSTANCE_ID, valueArrayInstance);
}
private void createObjectValueInstance() {
ClassInstance valueInstance = new ClassInstance(0, null, 0);
snapshot.addInstance(VALUE_ARRAY_INSTANCE_ID, valueInstance);
}
private ClassInstance createStringInstance() {
ClassInstance stringInstance = new ClassInstance(STRING_INSTANCE_ID, null, 100);
stringInstance.setClassId(STRING_CLASS_ID);
snapshot.addInstance(0, stringInstance);
return stringInstance;
}
}