From 9489ad8b3350ee2ce445dd0d4f11cea86fcd11f5 Mon Sep 17 00:00:00 2001 From: WillRabalais04 <69363495+WillRabalais04@users.noreply.github.com> Date: Fri, 24 Mar 2023 01:47:55 -0400 Subject: [PATCH 1/6] Bugfix for Issue #606 Updates the getStringValue method of the VariableNode class so that it correctly handles multidimensional arrays. The default formatting of multidimensional arrays is to have the size of the first array written in the last set of brackets eg.int[][5]. This changes it so that the returned value has the size of the first array written in the first set of brackets eg.int[5][]. This can parse multidimensional arrays of any size. --- .../processing/mode/java/debug/VariableNode.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/java/src/processing/mode/java/debug/VariableNode.java b/java/src/processing/mode/java/debug/VariableNode.java index b8b2684471..fb3df50027 100644 --- a/java/src/processing/mode/java/debug/VariableNode.java +++ b/java/src/processing/mode/java/debug/VariableNode.java @@ -95,6 +95,19 @@ public String getStringValue() { } 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 { From 2fdd3e5f362f17241ff698ffed7eda2a902b3393 Mon Sep 17 00:00:00 2001 From: A Samuel Pottinger Date: Tue, 9 May 2023 18:12:27 +0000 Subject: [PATCH 2/6] Refactor to regex and tests. Closes Debugger lists immediate array dimension last #606. --- .../mode/java/debug/VariableNode.java | 68 +++++++++------- .../mode/java/debug/VariableNodeTests.java | 81 +++++++++++++++++++ 2 files changed, 121 insertions(+), 28 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 fb3df50027..57a60a00ca 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.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 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(" ")); - /* - *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(); - } + 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; } @@ -393,4 +385,24 @@ 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(""); + 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 0000000000..fb03d24326 --- /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; + } + +} From cd313c61389b9703000bbd483668290f611c7ddd Mon Sep 17 00:00:00 2001 From: A Samuel Pottinger Date: Tue, 9 May 2023 18:26:15 +0000 Subject: [PATCH 3/6] Add test to describe null on #713. --- java/test/processing/mode/java/debug/VariableNodeTests.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/java/test/processing/mode/java/debug/VariableNodeTests.java b/java/test/processing/mode/java/debug/VariableNodeTests.java index fb03d24326..f8763b9343 100644 --- a/java/test/processing/mode/java/debug/VariableNodeTests.java +++ b/java/test/processing/mode/java/debug/VariableNodeTests.java @@ -10,6 +10,12 @@ 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"); From 5c3fa69f57980ac94410882bb9e765aa53b9981f Mon Sep 17 00:00:00 2001 From: A Samuel Pottinger Date: Tue, 9 May 2023 18:37:08 +0000 Subject: [PATCH 4/6] Add failsafe for #713. --- java/src/processing/mode/java/debug/VariableNode.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/java/src/processing/mode/java/debug/VariableNode.java b/java/src/processing/mode/java/debug/VariableNode.java index 57a60a00ca..9b8c418dee 100644 --- a/java/src/processing/mode/java/debug/VariableNode.java +++ b/java/src/processing/mode/java/debug/VariableNode.java @@ -399,7 +399,10 @@ public int hashCode() { private String describeArray(String fullDescription) { Matcher matcher = ARRAY_REGEX.matcher(fullDescription); StringJoiner joiner = new StringJoiner(""); - System.out.println(matcher.matches()); + 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 From 674cfe0766e3769f8bac86b845a927e3748a4f91 Mon Sep 17 00:00:00 2001 From: A Samuel Pottinger Date: Tue, 9 May 2023 18:41:36 +0000 Subject: [PATCH 5/6] Add test for failsafe. --- .../test/processing/mode/java/debug/VariableNodeTests.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/java/test/processing/mode/java/debug/VariableNodeTests.java b/java/test/processing/mode/java/debug/VariableNodeTests.java index f8763b9343..9b5530ffde 100644 --- a/java/test/processing/mode/java/debug/VariableNodeTests.java +++ b/java/test/processing/mode/java/debug/VariableNodeTests.java @@ -72,6 +72,13 @@ public void describeNestedArrayMixed() { Assert.assertEquals(node.getStringValue(), "instance of int[5][7][][]"); } + @Test + public void describeArrayFailsafe() { + Value value = buildMockValue("instance of int[x][7] (id=998)"); + VariableNode node = new VariableNode("test", "int[][][][]", value); + Assert.assertEquals(node.getStringValue(), "instance of int[x][7] (id=998)); + } + private Value buildMockValue(String toStringValue) { Value value = Mockito.mock(Value.class); Mockito.when(value.toString()).thenReturn(toStringValue); From 0987f67fc9add3b8609f11acb8d0df218bf30c66 Mon Sep 17 00:00:00 2001 From: A Samuel Pottinger Date: Wed, 10 May 2023 14:01:46 +0000 Subject: [PATCH 6/6] Clarify unneeded section. --- java/src/processing/mode/java/debug/VariableNode.java | 2 +- .../processing/mode/java/debug/VariableNodeTests.java | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/java/src/processing/mode/java/debug/VariableNode.java b/java/src/processing/mode/java/debug/VariableNode.java index 9b8c418dee..7056854b2d 100644 --- a/java/src/processing/mode/java/debug/VariableNode.java +++ b/java/src/processing/mode/java/debug/VariableNode.java @@ -56,7 +56,7 @@ public class VariableNode implements MutableTreeNode { public static final int TYPE_VOID = 11; private static final Pattern ARRAY_REGEX = Pattern.compile( - "^(?[^\\]]+)(?(\\[\\])*)(?(\\[\\d+\\])+).*$" + "^(?[^\\[]+)(?(\\[\\])*)(?(\\[\\d+\\])+)(?[^\\[]*)$" ); protected String type; diff --git a/java/test/processing/mode/java/debug/VariableNodeTests.java b/java/test/processing/mode/java/debug/VariableNodeTests.java index 9b5530ffde..427f902150 100644 --- a/java/test/processing/mode/java/debug/VariableNodeTests.java +++ b/java/test/processing/mode/java/debug/VariableNodeTests.java @@ -74,9 +74,16 @@ public void describeNestedArrayMixed() { @Test public void describeArrayFailsafe() { - Value value = buildMockValue("instance of int[x][7] (id=998)"); + 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=998)); + 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) {