/**
* Copyright 2014 Alexey Ragozin
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.netbeans.lib.profiler.heap;
import static org.assertj.core.api.Assertions.assertThat;
import static org.gridkit.jvmtool.heapdump.HeapWalker.stringValue;
import static org.gridkit.jvmtool.heapdump.HeapWalker.valueOf;
import static org.gridkit.jvmtool.heapdump.HeapWalker.walkFirst;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import org.assertj.core.api.Assertions;
import org.gridkit.jvmtool.heapdump.HeapPathHelper;
import org.gridkit.jvmtool.heapdump.HeapWalker;
import org.junit.Assert;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
@FixMethodOrder(MethodSorters.JVM)
public abstract class BaseHeapTest {
public abstract Heap getHeap();
@Test
public void verify_DummyA_via_classes() {
Heap heap = getHeap();
JavaClass jclass = heap.getJavaClassByName(DummyA.class.getName());
int n = 0;
for(Instance i : jclass.getInstances()) {
++n;
assertThat(i.getFieldValues().size()).isEqualTo(1);
FieldValue fv = i.getFieldValues().get(0);
assertThat(fv).isInstanceOf(ObjectFieldValue.class);
Instance ii = ((ObjectFieldValue)fv).getInstance();
assertThat(ii).isInstanceOf(PrimitiveArrayInstance.class);
}
assertThat(n).isEqualTo(50);
}
@Test
public void verify_DummyA_via_scan() {
Heap heap = getHeap();
JavaClass jclass = heap.getJavaClassByName(DummyA.class.getName());
int n = 0;
for(Instance i : heap.getAllInstances()) {
if (i.getJavaClass() == jclass) {
++n;
assertThat(i.getFieldValues().size()).isEqualTo(1);
FieldValue fv = i.getFieldValues().get(0);
assertThat(fv).isInstanceOf(ObjectFieldValue.class);
Instance ii = ((ObjectFieldValue)fv).getInstance();
assertThat(ii).isInstanceOf(PrimitiveArrayInstance.class);
}
}
assertThat(n).isEqualTo(50);
}
@Test
public void verify_heap_walker_for_dummyB() {
Heap heap = getHeap();
JavaClass jclass = heap.getJavaClassByName(DummyB.class.getName());
int n = 0;
for(Instance i : jclass.getInstances()) {
++n;
int no = Integer.valueOf(stringValue(walkFirst(i, "seqNo")));
SortedSet<String> testSet = new TreeSet<String>();
for(Instance e : HeapWalker.walk(i, "list.elementData[*]")) {
if (e != null) {
testSet.add(stringValue(e));
}
}
assertThat(testSet).isEqualTo(testSet("", no));
testSet.clear();
for(Instance e : HeapWalker.walk(i, "map.table[*].key")) {
if (e != null) {
testSet.add(stringValue(e));
}
}
// some entries may be missing due to hash collisions
assertThat(testSet("k", no).containsAll(testSet)).isTrue();
testSet.clear();
for(Instance e : HeapWalker.walk(i, "map.table[*].value")) {
if (e != null) {
testSet.add(stringValue(e));
}
}
// some entries may be missing due to hash collisions
assertThat(testSet("v", no).containsAll(testSet)).isTrue();
}
assertThat(n).isEqualTo(50);
}
@Test
public void verify_heap_walker_for_dummyB_over_map() {
Heap heap = getHeap();
JavaClass jclass = heap.getJavaClassByName(DummyB.class.getName());
int n = 0;
for(Instance i : jclass.getInstances()) {
++n;
int no = Integer.valueOf(stringValue(walkFirst(i, "seqNo")));
SortedSet<String> testSet = new TreeSet<String>();
for(Instance e : HeapWalker.walk(i, "list.elementData[*]")) {
if (e != null) {
testSet.add(stringValue(e));
}
}
assertThat(testSet).isEqualTo(testSet("", no));
testSet.clear();
for(Instance e : HeapWalker.walk(i, "map?entrySet.key")) {
if (e != null) {
testSet.add(stringValue(e));
}
}
assertThat(testSet).isEqualTo(testSet("k", no));
testSet.clear();
for(Instance e : HeapWalker.walk(i, "map?entrySet.value")) {
if (e != null) {
testSet.add(stringValue(e));
}
}
assertThat(testSet).isEqualTo(testSet("v", no));
if (testSet.size() > 5) {
assertThat(HeapWalker.valueOf(i, "map?entrySet[key=k3].value")).isEqualTo("v3");
}
}
assertThat(n).isEqualTo(50);
}
@SuppressWarnings("unused")
@Test
public void verify_heap_walker_for_array_list() {
Heap heap = getHeap();
JavaClass jclass = heap.getJavaClassByName(ArrayList.class.getName());
int n = 0;
for(Instance i : jclass.getInstances()) {
int m = 0;
for(Instance e : HeapWalker.walk(i, "elementData[*](**.DummyA)")) {
++m;
}
if (m != 0) {
++n;
assertThat(m).isEqualTo(50);
}
}
assertThat(n).isEqualTo(1);
}
@Test
public void verify_heap_path_for_arrays() {
boolean[] bool_values = {true, false};
byte[] byte_values = {Byte.MIN_VALUE, Byte.MAX_VALUE};
short[] short_values = {Short.MIN_VALUE, Short.MAX_VALUE};
char[] char_values = {Character.MIN_VALUE, Character.MAX_VALUE};
int[] int_values = {Integer.MIN_VALUE, Integer.MAX_VALUE};
long[] long_values = {Long.MIN_VALUE, Long.MAX_VALUE};
float[] float_values = {Float.MIN_VALUE, Float.NaN, Float.MAX_VALUE};
double[] double_values = {Double.MIN_VALUE, Double.NaN, Double.MAX_VALUE};
Heap heap = getHeap();
JavaClass jclass = heap.getJavaClassByName(DummyC.class.getName());
int n = 0;
for(Instance i : jclass.getInstances()) {
assertArrayEquals(bool_values, valueOf(i, "bool_values"));
assertArrayEquals(byte_values, valueOf(i, "byte_values"));
assertArrayEquals(short_values, valueOf(i, "short_values"));
assertArrayEquals(char_values, valueOf(i, "char_values"));
assertArrayEquals(int_values, valueOf(i, "int_values"));
assertArrayEquals(long_values, valueOf(i, "long_values"));
assertArrayEquals(float_values, valueOf(i, "float_values"));
assertArrayEquals(double_values, valueOf(i, "double_values"));
assertThat(valueOf(i, "bool_values[0]")).isEqualTo(Boolean.TRUE);
assertThat(valueOf(i, "byte_values[0]")).isEqualTo(Byte.MIN_VALUE);
assertThat(valueOf(i, "short_values[0]")).isEqualTo(Short.MIN_VALUE);
assertThat(valueOf(i, "char_values[0]")).isEqualTo(Character.MIN_VALUE);
assertThat(valueOf(i, "int_values[0]")).isEqualTo(Integer.MIN_VALUE);
assertThat(valueOf(i, "long_values[0]")).isEqualTo(Long.MIN_VALUE);
assertThat(valueOf(i, "float_values[0]")).isEqualTo(Float.MIN_VALUE);
assertThat(valueOf(i, "double_values[0]")).isEqualTo(Double.MIN_VALUE);
++n;
}
assertThat(n).isEqualTo(1);
}
@Test
public void verify_heap_path_tracker_over_null() {
Heap heap = getHeap();
JavaClass jclass = heap.getJavaClassByName(DummyD.class.getName());
Instance i = jclass.getInstances().get(0);
Assert.assertNull(HeapPathHelper.trackFirst(i, "nested.value"));
Assert.assertNull(HeapPathHelper.trackFirst(i, "nestedArray[0].value"));
Assert.assertEquals(".nestedArray[1].value", HeapPathHelper.trackFirst(i, "nestedArray[*].value"));
}
@Test
public void verify_heap_path_walker_over_null() {
Heap heap = getHeap();
JavaClass jclass = heap.getJavaClassByName(DummyD.class.getName());
Instance i = jclass.getInstances().get(0);
Assert.assertNull(HeapWalker.walkFirst(i, "nested.value"));
Assert.assertNull(HeapWalker.walkFirst(i, "nestedArray[0].value"));
Assert.assertEquals("somevalue", HeapWalker.valueOf(HeapWalker.walkFirst(i, "nestedArray[*].value")));
}
@Test
public void verify_DummyC_field_access() {
Heap heap = getHeap();
JavaClass jclass = heap.getJavaClassByName(DummyC.class.getName());
assertThat(jclass.getInstances()).hasSize(1);
Instance i = jclass.getInstances().get(0);
assertThat(HeapWalker.valueOf(i, "structField.trueField")).isEqualTo(true);
assertThat(HeapWalker.valueOf(i, "structField.falseField")).isEqualTo(false);
assertThat(HeapWalker.valueOf(i, "structField.byteField")).isEqualTo((byte) 13);
assertThat(HeapWalker.valueOf(i, "structField.shortField")).isEqualTo((short) -14);
assertThat(HeapWalker.valueOf(i, "structField.charField")).isEqualTo((char) 15);
assertThat(HeapWalker.valueOf(i, "structField.intField")).isEqualTo(0x66666666);
assertThat(HeapWalker.valueOf(i, "structField.longField")).isEqualTo(0x6666666666l);
assertThat(HeapWalker.valueOf(i, "structField.floatField")).isEqualTo(0.1f);
assertThat(HeapWalker.valueOf(i, "structField.doubleField")).isEqualTo(-0.2);
assertThat(HeapWalker.valueOf(i, "structField.trueBoxedField")).isEqualTo(true);
assertThat(HeapWalker.valueOf(i, "structField.falseBoxedField")).isEqualTo(false);
assertThat(HeapWalker.valueOf(i, "structField.byteBoxedField")).isEqualTo((byte) 13);
assertThat(HeapWalker.valueOf(i, "structField.shortBoxedField")).isEqualTo((short) -14);
assertThat(HeapWalker.valueOf(i, "structField.charBoxedField")).isEqualTo((char) 15);
assertThat(HeapWalker.valueOf(i, "structField.intBoxedField")).isEqualTo(0x66666666);
assertThat(HeapWalker.valueOf(i, "structField.longBoxedField")).isEqualTo(0x6666666666l);
assertThat(HeapWalker.valueOf(i, "structField.floatBoxedField")).isEqualTo(0.1f);
assertThat(HeapWalker.valueOf(i, "structField.doubleBoxedField")).isEqualTo(-0.2);
assertThat(HeapWalker.valueOf(i, "structField.textField")).isEqualTo("this is struct");
assertThat(HeapWalker.valueOf(i, "structArray[*].trueField")).isEqualTo(true);
assertThat(HeapWalker.valueOf(i, "structArray[*].falseField")).isEqualTo(false);
assertThat(HeapWalker.valueOf(i, "structArray[*].byteField")).isEqualTo((byte) 13);
assertThat(HeapWalker.valueOf(i, "structArray[*].shortField")).isEqualTo((short) -14);
assertThat(HeapWalker.valueOf(i, "structArray[*].charField")).isEqualTo((char) 15);
assertThat(HeapWalker.valueOf(i, "structArray[*].intField")).isEqualTo(0x66666666);
assertThat(HeapWalker.valueOf(i, "structArray[*].longField")).isEqualTo(0x6666666666l);
assertThat(HeapWalker.valueOf(i, "structArray[*].floatField")).isEqualTo(0.1f);
assertThat(HeapWalker.valueOf(i, "structArray[*].doubleField")).isEqualTo(-0.2);
assertThat(HeapWalker.valueOf(i, "structArray[*].trueBoxedField")).isEqualTo(true);
assertThat(HeapWalker.valueOf(i, "structArray[*].falseBoxedField")).isEqualTo(false);
assertThat(HeapWalker.valueOf(i, "structArray[*].byteBoxedField")).isEqualTo((byte) 13);
assertThat(HeapWalker.valueOf(i, "structArray[*].shortBoxedField")).isEqualTo((short) -14);
assertThat(HeapWalker.valueOf(i, "structArray[*].charBoxedField")).isEqualTo((char) 15);
assertThat(HeapWalker.valueOf(i, "structArray[*].intBoxedField")).isEqualTo(0x66666666);
assertThat(HeapWalker.valueOf(i, "structArray[*].longBoxedField")).isEqualTo(0x6666666666l);
assertThat(HeapWalker.valueOf(i, "structArray[*].floatBoxedField")).isEqualTo(0.1f);
assertThat(HeapWalker.valueOf(i, "structArray[*].doubleBoxedField")).isEqualTo(-0.2);
assertThat(HeapWalker.valueOf(i, "structArray[*].textField")).isEqualTo("this is struct #1");
}
private static void assertArrayEquals(Object expected, Object actual) {
if (expected instanceof boolean[]) {
assertThat(Arrays.toString((boolean[])actual)).isEqualTo(Arrays.toString((boolean[])expected));
}
else
if (expected instanceof byte[]) {
assertThat(Arrays.toString((byte[])actual)).isEqualTo(Arrays.toString((byte[])expected));
}
else
if (expected instanceof short[]) {
assertThat(Arrays.toString((short[])actual)).isEqualTo(Arrays.toString((short[])expected));
}
else
if (expected instanceof char[]) {
assertThat(Arrays.toString((char[])actual)).isEqualTo(Arrays.toString((char[])expected));
}
else
if (expected instanceof int[]) {
assertThat(Arrays.toString((int[])actual)).isEqualTo(Arrays.toString((int[])expected));
}
else
if (expected instanceof long[]) {
assertThat(Arrays.toString((long[])actual)).isEqualTo(Arrays.toString((long[])expected));
}
else
if (expected instanceof float[]) {
assertThat(Arrays.toString((float[])actual)).isEqualTo(Arrays.toString((float[])expected));
}
else
if (expected instanceof double[]) {
assertThat(Arrays.toString((double[])actual)).isEqualTo(Arrays.toString((double[])expected));
}
else {
Assertions.fail("Array type expected, but was " + actual);
}
}
private Set<String> testSet(String pref, int limit) {
Set<String> result = new TreeSet<String>();
for(int i = 0; i != limit; ++i) {
result.add(pref + i);
}
return result;
}
}