From 2fdd3e5f362f17241ff698ffed7eda2a902b3393 Mon Sep 17 00:00:00 2001 From: A Samuel Pottinger Date: Tue, 9 May 2023 18:12:27 +0000 Subject: [PATCH] Refactor to regex and tests. Closes Debugger lists immediate array dimension last #606. --- .../mode/java/debug/VariableNode.java | 70 +++++++++------- .../mode/java/debug/VariableNodeTests.java | 81 +++++++++++++++++++ 2 files changed, 122 insertions(+), 29 deletions(-) create mode 100644 java/test/processing/mode/java/debug/VariableNodeTests.java diff --git a/java/src/processing/mode/java/debug/VariableNode.java b/java/src/processing/mode/java/debug/VariableNode.java index fb3df5002..57a60a00c 100644 --- a/java/src/processing/mode/java/debug/VariableNode.java +++ b/java/src/processing/mode/java/debug/VariableNode.java @@ -29,6 +29,9 @@ import java.util.ArrayList; 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; @@ -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( + "^(?[^\\]]+)(?(\\[\\])*)(?(\\[\\d+\\])+).*$" + ); + protected String type; protected String name; protected Value value; protected List children = new ArrayList<>(); protected MutableTreeNode parent; - /** * Construct a {@link VariableNode}. * @param name the name @@ -88,35 +94,21 @@ public class VariableNode implements MutableTreeNode { * @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(" ")); - /* - *formats multidimensional array values to have the size of the first array in - *the first bracket eg.int[][5]-->int[5][] - */ - // resolves issue #606: https://github.com/processing/processing4/issues/606 - if (str.contains("][")) { - String brackets = str.substring(str.indexOf('[')); - int arrayDimensions = 0; - String num = brackets.replaceAll("[^\\d]", ""); - arrayDimensions = (brackets.length() - num.length()) / 2; - brackets = "[" + num + "]" + "[]".repeat(arrayDimensions - 1); - str = str.substring(0, str.indexOf('[')) + brackets; - } - } else if (getType() == TYPE_STRING) { - str = ((StringReference) value).value(); // use original string value (without quotes) - } else { - str = value.toString(); - } - } else { - str = "null"; + 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 { + return value.toString(); } - return str; } @@ -393,4 +385,24 @@ public class VariableNode implements MutableTreeNode { 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(""); + System.out.println(matcher.matches()); + 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(); + } } diff --git a/java/test/processing/mode/java/debug/VariableNodeTests.java b/java/test/processing/mode/java/debug/VariableNodeTests.java new file mode 100644 index 000000000..fb03d2432 --- /dev/null +++ b/java/test/processing/mode/java/debug/VariableNodeTests.java @@ -0,0 +1,81 @@ +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 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][][]"); + } + + 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; + } + +}