test/jdk/javax/management/remote/rest/JsonParserTest.java
branchjmx-rest-api
changeset 56004 da55d1429860
parent 56002 60ab3b595a8e
child 56026 bd531f08d7c7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/management/remote/rest/JsonParserTest.java	Tue Jan 02 13:33:08 2018 +0530
@@ -0,0 +1,361 @@
+
+/* @test
+ * @summary Test JSON parser for a random json node tree
+ * @modules java.management.rest/com.oracle.jmx.remote.rest.json
+ *          java.management.rest/com.oracle.jmx.remote.rest.json.parser
+ * @build JsonParserTest
+ * @run main JsonParserTest
+ */
+
+import com.oracle.jmx.remote.rest.json.parser.JSONParser;
+import com.oracle.jmx.remote.rest.json.parser.ParseException;
+
+import java.util.*;
+
+/**
+ * Below class tests JSON parser for a randomly generated JSON string.
+ * The Json string is generated by converting a randomly generated tree into a string
+ * Each node in the tree is either a json Object, array or a primitive.
+ * Primitive node generates string, number, boolean or null as a string.
+ * Json Number is generated according to the syntax graph as in json.org
+ * Json string is generated along with all the control characters, and by escaping
+ * only backslash and double quote characters.
+ */
+public class JsonParserTest {
+
+    static final Random RANDOM = new Random(System.currentTimeMillis());
+    static int maxChildrenPerNode;
+
+    public static void main(String[] args) throws ParseException {
+
+        for(int i=0; i<100; i++) {
+            maxChildrenPerNode = RANDOM.nextInt(90) + 10;
+            int totalNodes = RANDOM.nextInt(90000) + 10000;
+            boolean isArray = RANDOM.nextBoolean();         // Generate either a Json Array or a Json Object
+            JsonNode node;
+            if (isArray) {
+                node = JsonNodeGenerator.ArrayGenerator.generate(totalNodes);
+            } else {
+                node = JsonNodeGenerator.ObjectGenerator.generate(totalNodes);
+            }
+            String str = node.toJsonString();
+            JSONParser parser = new JSONParser(str);
+            com.oracle.jmx.remote.rest.json.JSONElement parse = parser.parse();
+            parse.toJsonString();
+            System.out.println("Finished iteration : " + i + ", Node count :" + totalNodes);
+        }
+    }
+}
+
+
+interface JsonNode {
+
+    class ObjectNode extends LinkedHashMap<String, JsonNode> implements JsonNode {
+
+        @Override
+        public String toJsonString() {
+            if (isEmpty()) {
+                return null;
+            }
+
+            StringBuilder sbuild = new StringBuilder();
+            sbuild.append("{");
+            keySet().forEach((elem) -> sbuild.append(elem).append(": ").
+                    append((get(elem) != null) ? get(elem).toJsonString() : "null").append(","));
+
+            sbuild.deleteCharAt(sbuild.lastIndexOf(","));
+            sbuild.append("}");
+            return sbuild.toString();
+        }
+    }
+
+    class ArrayNode extends ArrayList<JsonNode> implements JsonNode {
+
+        @Override
+        public String toJsonString() {
+            if (isEmpty()) {
+                return null;
+            }
+            StringBuilder sbuild = new StringBuilder();
+            sbuild.append("[");
+            for (JsonNode val : this) {
+                if (val != null) {
+                    sbuild.append(val.toJsonString()).append(", ");
+                } else {
+                    sbuild.append("null").append(", ");
+                }
+            }
+
+            sbuild.deleteCharAt(sbuild.lastIndexOf(","));
+            sbuild.append("]");
+            return sbuild.toString();
+        }
+    }
+
+    class PrimitiveNode implements JsonNode {
+
+        private final String s;
+
+        PrimitiveNode(String s) {
+            this.s = s;
+        }
+
+        @Override
+        public String toJsonString() {
+            return s;
+        }
+    }
+
+    String toJsonString();
+}
+
+interface JsonNodeGenerator {
+
+    class NumberGenerator {
+
+         // Node that returns the assigned label
+        private static class Node {
+            final private String label;
+
+            Node(String label) {
+                children = new LinkedList<>();
+                this.label = label;
+            }
+
+            Node() {
+                this("");
+            }
+
+            void add(Node node) {
+                if (!children.contains(node)) {
+                    children.add(node);
+                }
+            }
+
+            String getLabel() {
+                return label;
+            }
+
+            List<Node> children;
+        }
+
+        // Node that generates a random digit from 1-9
+        private static class Digit19 extends Node {
+            Digit19() {
+                super();
+            }
+
+            @Override
+            String getLabel() {
+                return "" + (JsonParserTest.RANDOM.nextInt(9) + 1);
+            }
+        }
+
+        // Node that generates a random digit from 0-9
+        private static class Digits extends Node {
+            Digits() {
+                super();
+            }
+
+            @Override
+            String getLabel() {
+                return "" + (JsonParserTest.RANDOM.nextInt(10));
+            }
+        }
+
+        private final static Node root;
+
+        // Setup a graph for the grammar productions for JSON number as outlined in json.org
+        // The graph below mimics the syntax diagram for JSON number.
+        // Node "R" is the start node and "T" is the terminal node
+        static {
+
+            // Create all the nodes
+            root = new Node("R");
+            Node minus1 = new Node("-");
+            Node zero = new Node("0");
+            Node digit19 = new Digit19();
+            Node digits1 = new Digits();
+            Node dot = new Node(".");
+            Node digits2 = new Digits();
+            Node e = new Node("e");
+            Node E = new Node("E");
+            Node plus = new Node("+");
+            Node minus2 = new Node("-");
+            Node digits3 = new Digits();
+            Node terminal = new Node("T");
+
+            //set up graph
+            root.add(zero);
+            root.add(minus1);
+            root.add(digit19);
+
+            minus1.add(zero);
+            minus1.add(digit19);
+
+            zero.add(dot);
+            zero.add(terminal);
+
+            digit19.add(dot);
+            digit19.add(digits1);
+            digit19.add(terminal);
+
+            digits1.add(dot);
+            digits1.add(digits1);
+            digits1.add(terminal);
+
+            dot.add(digits2);
+
+            digits2.add(digits2);
+            digits2.add(e);
+            digits2.add(E);
+            digits2.add(terminal);
+
+            e.add(plus);
+            e.add(minus2);
+            e.add(digits3);
+
+            E.add(plus);
+            E.add(minus2);
+            E.add(digits3);
+
+            plus.add(digits3);
+            minus2.add(digits3);
+
+            digits3.add(digits3);
+            digits3.add(terminal);
+        }
+
+        static String generate() {
+            // Get a random path from start to finish
+            StringBuilder sbuf = new StringBuilder();
+            Node parent = root;
+            Node child = parent.children.get(JsonParserTest.RANDOM.nextInt(parent.children.size()));
+            while (!child.getLabel().equals("T")) {
+                sbuf.append(child.getLabel());
+                parent = child;
+                child = parent.children.get(JsonParserTest.RANDOM.nextInt(parent.children.size()));
+            }
+            return sbuf.toString();
+        }
+    }
+
+    class StringGenerator {
+
+        private static final int minStringLength = 0;
+        private static final int maxStringLength = 50;
+
+        private static final String controlChars = "\b" + "\f" + "\n" + "\r" + "\t" + "\\b";
+//        private static final String escapedControls = "\\b" + "\\f" + "\\n" + "\\r" + "\\t" + "\\b";
+
+        private static final String specials = "\\" + "\"" + controlChars;// + escapedControls;    // TODO: "\\uxxxx"
+//        private static final String alphanums = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+
+        static String generate() {
+            char ch;
+            StringBuilder sbuf = new StringBuilder();
+            int len = minStringLength + JsonParserTest.RANDOM.nextInt(maxStringLength - minStringLength + 1);
+            sbuf.append("\"");
+            for (int i = 0; i < len; i++) {
+                if (JsonParserTest.RANDOM.nextInt(10) == 1) { // 1/10 chances of a control character
+                    ch = specials.charAt(JsonParserTest.RANDOM.nextInt(specials.length()));
+                } else {
+//                ch = alphanums.charAt(JsonParserTest.RANDOM.nextInt(alphanums.length()));
+                    ch = (char) JsonParserTest.RANDOM.nextInt(Character.MAX_VALUE + 1);
+                }
+                switch (ch) {
+                    case '\"':
+                    case '\\':
+                        sbuf.append('\\');
+                }
+                sbuf.append(ch);
+            }
+            sbuf.append("\"");
+            return sbuf.toString();
+        }
+    }
+
+    class ArrayGenerator {
+
+         static JsonNode.ArrayNode generate(int size) {
+            JsonNode.ArrayNode array = new JsonNode.ArrayNode();
+            if (size <= JsonParserTest.maxChildrenPerNode) {
+                for (int i = 0; i < size; i++) {
+                    array.add(PrimtiveGenerator.generate());
+                }
+            } else if (size >= JsonParserTest.maxChildrenPerNode) {
+                int newSize = size;
+                do {
+                    int childSize = JsonParserTest.RANDOM.nextInt(newSize);
+                    if (JsonParserTest.RANDOM.nextBoolean()) {
+                        array.add(ArrayGenerator.generate(childSize));
+                    } else {
+                        array.add(ObjectGenerator.generate(childSize));
+                    }
+                    newSize = newSize - childSize;
+                } while (newSize > JsonParserTest.maxChildrenPerNode);
+                if (JsonParserTest.RANDOM.nextBoolean()) {
+                    array.add(ArrayGenerator.generate(newSize));
+                } else {
+                    array.add(ObjectGenerator.generate(newSize));
+                }
+            }
+            return array;
+        }
+    }
+
+    class PrimtiveGenerator {
+
+        static JsonNode.PrimitiveNode generate() {
+            int primitiveTypre = JsonParserTest.RANDOM.nextInt(10) + 1;
+            switch (primitiveTypre) {
+                case 1:
+                case 2:
+                case 3:
+                case 4:
+                    return new JsonNode.PrimitiveNode(StringGenerator.generate());
+                case 5:
+                case 6:
+                case 7:
+                case 8:
+                    return new JsonNode.PrimitiveNode(NumberGenerator.generate());
+                case 9:
+                    return new JsonNode.PrimitiveNode(Boolean.toString(JsonParserTest.RANDOM.nextBoolean()));
+                case 10:
+                    return null;
+            }
+            return null;
+        }
+    }
+
+    class ObjectGenerator {
+
+        static JsonNode.ObjectNode generate(int size) {
+            JsonNode.ObjectNode jobj = new JsonNode.ObjectNode();
+            if (size <= JsonParserTest.maxChildrenPerNode) {
+                for (int i = 0; i < size; i++) {
+                    jobj.put(StringGenerator.generate(), PrimtiveGenerator.generate());
+                }
+            } else {
+                int newSize = size;
+                do {
+                    int childSize = JsonParserTest.RANDOM.nextInt(newSize);
+                    if (JsonParserTest.RANDOM.nextBoolean()) {
+                        jobj.put(StringGenerator.generate(), ArrayGenerator.generate(childSize));
+                    } else {
+                        jobj.put(StringGenerator.generate(), ObjectGenerator.generate(childSize));
+                    }
+                    newSize = newSize - childSize;
+                } while (newSize > JsonParserTest.maxChildrenPerNode);
+                if (JsonParserTest.RANDOM.nextBoolean()) {
+                    jobj.put(StringGenerator.generate(), ArrayGenerator.generate(newSize));
+                } else {
+                    jobj.put(StringGenerator.generate(), ObjectGenerator.generate(newSize));
+                }
+            }
+            return jobj;
+        }
+    }
+}
+
+