Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 43 additions & 15 deletions java/src/processing/mode/java/debug/VariableNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.StringJoiner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreeNode;

Expand All @@ -52,13 +55,16 @@ public class VariableNode implements MutableTreeNode {
public static final int TYPE_SHORT = 10;
public static final int TYPE_VOID = 11;

private static final Pattern ARRAY_REGEX = Pattern.compile(
"^(?<prefix>[^\\[]+)(?<unbounded>(\\[\\])*)(?<bounded>(\\[\\d+\\])+)(?<unneeded>[^\\[]*)$"
);

protected String type;
protected String name;
protected Value value;
protected List<MutableTreeNode> children = new ArrayList<>();
protected MutableTreeNode parent;


/**
* Construct a {@link VariableNode}.
* @param name the name
Expand Down Expand Up @@ -88,22 +94,21 @@ public Value getValue() {
* @return a String representing the value.
*/
public String getStringValue() {
String str;
if (value != null) {
if (getType() == TYPE_OBJECT) {
str = "instance of " + type;
} else if (getType() == TYPE_ARRAY) {
//instance of int[5] (id=998) --> instance of int[5]
str = value.toString().substring(0, value.toString().lastIndexOf(" "));
} else if (getType() == TYPE_STRING) {
str = ((StringReference) value).value(); // use original string value (without quotes)
} else {
str = value.toString();
}
if (value == null) {
return "null";
}

int typeDescriptor = getType();
if (typeDescriptor == TYPE_OBJECT) {
return "instance of " + type;
} else if (typeDescriptor == TYPE_ARRAY) {
return describeArray(value.toString());
} else if (typeDescriptor == TYPE_STRING) {
// use original string value (without quotes)
return ((StringReference) value).value();
} else {
str = "null";
return value.toString();
}
return str;
}


Expand Down Expand Up @@ -380,4 +385,27 @@ public int hashCode() {
hash = 97 * hash + (this.value != null ? this.value.hashCode() : 0);
return hash;
}


/**
* Describe an array in a human friendly description.
*
* @see Issue #606
* @param fullDescrition The full description of the array like "instance of
* int[5] (id=998)" or "instance of int[][5] (id=998)"
* @return Human-friendly description like "instance of int[5]" or
* "instance of int[5][]".
*/
private String describeArray(String fullDescription) {
Matcher matcher = ARRAY_REGEX.matcher(fullDescription);
StringJoiner joiner = new StringJoiner("");
if (!matcher.matches()) {
return fullDescription;
}

joiner.add(matcher.group("prefix")); // Type without brackets
joiner.add(matcher.group("bounded")); // Brackets with numbers
joiner.add(matcher.group("unbounded")); // Brackets without numbers
return joiner.toString();
}
}
101 changes: 101 additions & 0 deletions java/test/processing/mode/java/debug/VariableNodeTests.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package processing.mode.java.debug;

import com.sun.jdi.StringReference;
import com.sun.jdi.Value;

import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;


public class VariableNodeTests {

@Test
public void describeNull() {
VariableNode node = new VariableNode("test", "null", null);
Assert.assertEquals(node.getStringValue(), "null");
}

@Test
public void describeInt() {
Value value = buildMockValue("5");
VariableNode node = new VariableNode("test", "int", value);
Assert.assertEquals(node.getStringValue(), "5");
}

@Test
public void describeFloat() {
Value value = buildMockValue("5.5");
VariableNode node = new VariableNode("test", "float", value);
Assert.assertEquals(node.getStringValue(), "5.5");
}

@Test
public void describeObject() {
Value value = buildMockValue("5.5");
VariableNode node = new VariableNode("test", "Other", value);
Assert.assertEquals(node.getStringValue(), "instance of Other");
}

@Test
public void describeString() {
Value value = buildMockString("testing");
VariableNode node = new VariableNode("test", "java.lang.String", value);
Assert.assertEquals(node.getStringValue(), "testing");
}

@Test
public void describeSimpleArray() {
Value value = buildMockValue("instance of int[5] (id=998)");
VariableNode node = new VariableNode("test", "int[]", value);
Assert.assertEquals(node.getStringValue(), "instance of int[5]");
}

@Test
public void describeNestedArraySingleDimensionUnknown() {
Value value = buildMockValue("instance of int[][5] (id=998)");
VariableNode node = new VariableNode("test", "int[][]", value);
Assert.assertEquals(node.getStringValue(), "instance of int[5][]");
}

@Test
public void describeNestedArrayMultiDimensionUnknown() {
Value value = buildMockValue("instance of int[][][5] (id=998)");
VariableNode node = new VariableNode("test", "int[][][]", value);
Assert.assertEquals(node.getStringValue(), "instance of int[5][][]");
}

@Test
public void describeNestedArrayMixed() {
Value value = buildMockValue("instance of int[][][5][7] (id=998)");
VariableNode node = new VariableNode("test", "int[][][][]", value);
Assert.assertEquals(node.getStringValue(), "instance of int[5][7][][]");
}

@Test
public void describeArrayFailsafe() {
Value value = buildMockValue("instance of int[x][7] (id=98)");
VariableNode node = new VariableNode("test", "int[][][][]", value);
Assert.assertEquals(node.getStringValue(), "instance of int[x][7] (id=98)");
}

@Test
public void describeArrayUnexpectedOrder() {
Value value = buildMockValue("instance of int[7][] (id=98)");
VariableNode node = new VariableNode("test", "int[][][][]", value);
Assert.assertEquals(node.getStringValue(), "instance of int[7][] (id=98)");
}

private Value buildMockValue(String toStringValue) {
Value value = Mockito.mock(Value.class);
Mockito.when(value.toString()).thenReturn(toStringValue);
return value;
}

private StringReference buildMockString(String innerValue) {
StringReference value = Mockito.mock(StringReference.class);
Mockito.when(value.value()).thenReturn(innerValue);
return value;
}

}