summaryrefslogtreecommitdiffstats
path: root/contrib/ccan/json/test
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-06 00:55:53 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-06 00:55:53 +0000
commit3d0386f27ca66379acf50199e1d1298386eeeeb8 (patch)
treef87bd4a126b3a843858eb447e8fd5893c3ee3882 /contrib/ccan/json/test
parentInitial commit. (diff)
downloadknot-resolver-upstream.tar.xz
knot-resolver-upstream.zip
Adding upstream version 3.2.1.upstream/3.2.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'contrib/ccan/json/test')
-rw-r--r--contrib/ccan/json/test/common.h18
-rw-r--r--contrib/ccan/json/test/run-construction.c191
-rw-r--r--contrib/ccan/json/test/run-decode-encode.c77
-rw-r--r--contrib/ccan/json/test/run-stringify.c108
-rw-r--r--contrib/ccan/json/test/run-validate.c49
-rw-r--r--contrib/ccan/json/test/test-strings224
-rw-r--r--contrib/ccan/json/test/test-strings-reencoded90
7 files changed, 757 insertions, 0 deletions
diff --git a/contrib/ccan/json/test/common.h b/contrib/ccan/json/test/common.h
new file mode 100644
index 0000000..328cb73
--- /dev/null
+++ b/contrib/ccan/json/test/common.h
@@ -0,0 +1,18 @@
+#include <ccan/json/json.c>
+#include <ccan/tap/tap.h>
+
+#include <errno.h>
+#include <string.h>
+
+static char *chomp(char *s)
+{
+ char *e;
+
+ if (s == NULL || *s == 0)
+ return s;
+
+ e = strchr(s, 0);
+ if (e[-1] == '\n')
+ *--e = 0;
+ return s;
+}
diff --git a/contrib/ccan/json/test/run-construction.c b/contrib/ccan/json/test/run-construction.c
new file mode 100644
index 0000000..cc9a395
--- /dev/null
+++ b/contrib/ccan/json/test/run-construction.c
@@ -0,0 +1,191 @@
+/* Build a list of numbers with various appends and prepends, verify them by testing against their encoded value, do pointer consistency checks each time, do element lookups, and remove items as well. */
+
+#include "common.h"
+
+#define should_be(var, expected) should_be_(var, #var, expected)
+
+static void should_be_(const JsonNode *node, const char *name, const char *expected)
+{
+ char errmsg[256];
+ char *encoded;
+
+ if (!json_check(node, errmsg)) {
+ fail("Invariants check failed: %s", errmsg);
+ return;
+ }
+
+ encoded = json_encode(node);
+
+ if (strcmp(encoded, expected) == 0)
+ pass("%s is %s", name, expected);
+ else
+ fail("%s should be %s, but is actually %s", name, expected, encoded);
+
+ free(encoded);
+}
+
+static void test_string(void)
+{
+ JsonNode *str;
+
+ str = json_mkstring("Hello\tworld!\n\001");
+ should_be(str, "\"Hello\\tworld!\\n\\u0001\"");
+ json_delete(str);
+
+ str = json_mkstring("\"\\\b\f\n\r\t");
+ should_be(str, "\"\\\"\\\\\\b\\f\\n\\r\\t\"");
+ json_delete(str);
+}
+
+static void test_number(void)
+{
+ JsonNode *num;
+
+ num = json_mknumber(5678901234.0);
+ should_be(num, "5678901234");
+ json_delete(num);
+
+ num = json_mknumber(-5678901234.0);
+ should_be(num, "-5678901234");
+ json_delete(num);
+
+ num = json_mknumber(0.0 / 0.0);
+ should_be(num, "null");
+ json_delete(num);
+}
+
+static void test_array(void)
+{
+ JsonNode *array;
+ JsonNode *children[5 + 1];
+
+ array = json_mkarray();
+ should_be(array, "[]");
+
+ children[1] = json_mknumber(1);
+ children[2] = json_mknumber(2);
+ children[3] = json_mknumber(3);
+ children[4] = json_mknumber(4);
+ children[5] = json_mknumber(5);
+
+ json_append_element(array, children[3]);
+ should_be(array, "[3]");
+
+ json_remove_from_parent(children[3]);
+ should_be(array, "[]");
+
+ json_prepend_element(array, children[3]);
+ should_be(array, "[3]");
+
+ json_prepend_element(array, children[2]);
+ should_be(array, "[2,3]");
+
+ json_append_element(array, children[4]);
+ should_be(array, "[2,3,4]");
+
+ json_delete(children[3]);
+ should_be(array, "[2,4]");
+
+ json_prepend_element(array, children[1]);
+ should_be(array, "[1,2,4]");
+
+ json_delete(children[1]);
+ should_be(array, "[2,4]");
+
+ json_delete(children[4]);
+ should_be(array, "[2]");
+
+ ok1(json_find_element(array, 0) == children[2]);
+ ok1(json_find_element(array, -1) == NULL);
+ ok1(json_find_element(array, 1) == NULL);
+
+ json_append_element(array, children[5]);
+ should_be(array, "[2,5]");
+
+ ok1(json_find_element(array, 0) == children[2]);
+ ok1(json_find_element(array, 1) == children[5]);
+ ok1(json_find_element(array, -1) == NULL);
+ ok1(json_find_element(array, 2) == NULL);
+
+ json_delete(children[2]);
+ json_delete(children[5]);
+ should_be(array, "[]");
+
+ ok1(json_find_element(array, -1) == NULL);
+ ok1(json_find_element(array, 0) == NULL);
+ ok1(json_find_element(array, 1) == NULL);
+
+ json_delete(array);
+}
+
+static void test_object(void)
+{
+ JsonNode *object;
+ JsonNode *children[5 + 1];
+
+ object = json_mkobject();
+ should_be(object, "{}");
+
+ children[1] = json_mknumber(1);
+ children[2] = json_mknumber(2);
+ children[3] = json_mknumber(3);
+
+ ok1(json_find_member(object, "one") == NULL);
+ ok1(json_find_member(object, "two") == NULL);
+ ok1(json_find_member(object, "three") == NULL);
+
+ json_append_member(object, "one", children[1]);
+ should_be(object, "{\"one\":1}");
+
+ ok1(json_find_member(object, "one") == children[1]);
+ ok1(json_find_member(object, "two") == NULL);
+ ok1(json_find_member(object, "three") == NULL);
+
+ json_prepend_member(object, "two", children[2]);
+ should_be(object, "{\"two\":2,\"one\":1}");
+
+ ok1(json_find_member(object, "one") == children[1]);
+ ok1(json_find_member(object, "two") == children[2]);
+ ok1(json_find_member(object, "three") == NULL);
+
+ json_append_member(object, "three", children[3]);
+ should_be(object, "{\"two\":2,\"one\":1,\"three\":3}");
+
+ ok1(json_find_member(object, "one") == children[1]);
+ ok1(json_find_member(object, "two") == children[2]);
+ ok1(json_find_member(object, "three") == children[3]);
+
+ json_delete(object);
+}
+
+int main(void)
+{
+ JsonNode *node;
+
+ (void) chomp;
+
+ plan_tests(49);
+
+ ok1(json_find_element(NULL, 0) == NULL);
+ ok1(json_find_member(NULL, "") == NULL);
+ ok1(json_first_child(NULL) == NULL);
+
+ node = json_mknull();
+ should_be(node, "null");
+ json_delete(node);
+
+ node = json_mkbool(false);
+ should_be(node, "false");
+ json_delete(node);
+
+ node = json_mkbool(true);
+ should_be(node, "true");
+ json_delete(node);
+
+ test_string();
+ test_number();
+ test_array();
+ test_object();
+
+ return exit_status();
+}
diff --git a/contrib/ccan/json/test/run-decode-encode.c b/contrib/ccan/json/test/run-decode-encode.c
new file mode 100644
index 0000000..6bdf7c3
--- /dev/null
+++ b/contrib/ccan/json/test/run-decode-encode.c
@@ -0,0 +1,77 @@
+#include "common.h"
+
+int main(void)
+{
+ const char *strings_file = "test/test-strings";
+ const char *strings_reencoded_file = "test/test-strings-reencoded";
+ FILE *f, *f2;
+ char buffer[1024], buffer2[1024];
+
+ plan_tests(90);
+
+ f = fopen(strings_file, "rb");
+ if (f == NULL) {
+ diag("Could not open %s: %s", strings_file, strerror(errno));
+ return 1;
+ }
+ f2 = fopen(strings_reencoded_file, "rb");
+ if (f2 == NULL) {
+ diag("Could not open %s: %s", strings_reencoded_file, strerror(errno));
+ return 1;
+ }
+
+ while (fgets(buffer, sizeof(buffer), f)) {
+ const char *s = chomp(buffer);
+ bool valid;
+ JsonNode *node;
+
+ if (expect_literal(&s, "valid ")) {
+ valid = true;
+ } else if (expect_literal(&s, "invalid ")) {
+ valid = false;
+ } else {
+ fail("Invalid line in test-strings: %s", buffer);
+ continue;
+ }
+
+ node = json_decode(s);
+
+ if (valid) {
+ char *reencoded;
+ char errmsg[256];
+
+ if (node == NULL) {
+ fail("%s is valid, but json_decode returned NULL", s);
+ continue;
+ }
+
+ if (!json_check(node, errmsg)) {
+ fail("Corrupt tree produced by json_decode: %s", errmsg);
+ continue;
+ }
+
+ reencoded = json_encode(node);
+
+ if (!fgets(buffer2, sizeof(buffer2), f2)) {
+ fail("test-strings-reencoded is missing this line: %s", reencoded);
+ continue;
+ }
+ chomp(buffer2);
+
+ ok(strcmp(reencoded, buffer2) == 0, "re-encode %s -> %s", s, reencoded);
+
+ free(reencoded);
+ json_delete(node);
+ } else if (node != NULL) {
+ fail("%s is invalid, but json_decode returned non-NULL", s);
+ continue;
+ }
+ }
+
+ if (ferror(f) || fclose(f) != 0 || ferror(f2) || fclose(f2) != 0) {
+ diag("I/O error reading test data.");
+ return 1;
+ }
+
+ return exit_status();
+}
diff --git a/contrib/ccan/json/test/run-stringify.c b/contrib/ccan/json/test/run-stringify.c
new file mode 100644
index 0000000..3a4cb73
--- /dev/null
+++ b/contrib/ccan/json/test/run-stringify.c
@@ -0,0 +1,108 @@
+#include "common.h"
+
+static char buf1[256], buf2[256];
+
+/* Used for pass and fail messages */
+static char *quote_string(const char *str, char buf[256])
+{
+ char *out = buf;
+
+ *out++ = '"';
+ for (; *str != 0; str++) {
+ if (out - buf > 256 - 5) {
+ /* String is too long. End it with `...' */
+ out = buf + 256 - 5;
+ *out++ = '.';
+ *out++ = '.';
+ *out++ = '.';
+ break;
+ }
+ switch (*str) {
+ case '\t':
+ *out++ = '\\';
+ *out++ = 't';
+ break;
+ case '\n':
+ *out++ = '\\';
+ *out++ = 'n';
+ break;
+ case '"':
+ *out++ = '\\';
+ *out++ = '"';
+ break;
+ case '\\':
+ *out++ = '\\';
+ *out++ = '\\';
+ break;
+ default:
+ *out++ = *str;
+ break;
+ }
+ }
+ *out++ = '"';
+
+ *out = 0;
+ return buf;
+}
+
+static void test_stringify(const char *input, const char *expected)
+{
+ JsonNode *node = NULL;
+ char *enc = NULL;
+ char *strn = NULL;
+ char *str = NULL;
+
+ node = json_decode(input);
+ if (node == NULL) {
+ fail("Failed to decode %s", input);
+ goto end;
+ }
+
+ enc = json_encode(node);
+ if (strcmp(enc, input) != 0) {
+ fail("%s re-encodes to %s. Either encode/decode is broken, or the input string needs to be normalized", input, enc);
+ goto end;
+ }
+
+ strn = json_stringify(node, NULL);
+ if (strcmp(strn, enc) != 0) {
+ fail("json_stringify with NULL space produced a different string than json_encode");
+ goto end;
+ }
+
+ str = json_stringify(node, "\t");
+ if (strcmp(str, expected) != 0) {
+ fail("Expected %s, but json_stringify produced %s",
+ quote_string(expected, buf1), quote_string(str, buf2));
+ goto end;
+ }
+
+ pass("stringify %s", input);
+
+end:
+ json_delete(node);
+ free(enc);
+ free(strn);
+ free(str);
+}
+
+int main(void)
+{
+ (void) chomp;
+
+ plan_tests(9);
+
+ test_stringify("[]", "[]");
+ test_stringify("[1]", "[\n\t1\n]");
+ test_stringify("[1,2,3]", "[\n\t1,\n\t2,\n\t3\n]");
+ test_stringify("[[]]", "[\n\t[]\n]");
+ test_stringify("[[1,2],[3,4]]", "[\n\t[\n\t\t1,\n\t\t2\n\t],\n\t[\n\t\t3,\n\t\t4\n\t]\n]");
+
+ test_stringify("{}", "{}");
+ test_stringify("{\"one\":1}", "{\n\t\"one\": 1\n}");
+ test_stringify("{\"one\":1,\"t*\":[2,3,10]}", "{\n\t\"one\": 1,\n\t\"t*\": [\n\t\t2,\n\t\t3,\n\t\t10\n\t]\n}");
+ test_stringify("{\"a\":{\"1\":1,\"2\":2},\"b\":{\"3\":[null,false,true,\"\\f\"]}}",
+ "{\n\t\"a\": {\n\t\t\"1\": 1,\n\t\t\"2\": 2\n\t},\n\t\"b\": {\n\t\t\"3\": [\n\t\t\tnull,\n\t\t\tfalse,\n\t\t\ttrue,\n\t\t\t\"\\f\"\n\t\t]\n\t}\n}");
+
+ return exit_status();
+}
diff --git a/contrib/ccan/json/test/run-validate.c b/contrib/ccan/json/test/run-validate.c
new file mode 100644
index 0000000..f7bb3b0
--- /dev/null
+++ b/contrib/ccan/json/test/run-validate.c
@@ -0,0 +1,49 @@
+#include "common.h"
+
+int main(void)
+{
+ const char *strings_file = "test/test-strings";
+ FILE *f;
+ char buffer[1024];
+
+ plan_tests(224);
+
+ f = fopen(strings_file, "rb");
+ if (f == NULL) {
+ diag("Could not open %s: %s", strings_file, strerror(errno));
+ return 1;
+ }
+
+ while (fgets(buffer, sizeof(buffer), f)) {
+ const char *s = chomp(buffer);
+ bool valid;
+
+ if (expect_literal(&s, "valid ")) {
+ valid = true;
+ } else if (expect_literal(&s, "invalid ")) {
+ valid = false;
+ } else {
+ fail("Invalid line in test-strings: %s", buffer);
+ continue;
+ }
+
+ if (strcmp(s, "\"1\\u2\"") == 0)
+ puts("here");
+
+ if (json_validate(s) == valid) {
+ pass("%s %s", valid ? "valid" : "invalid", s);
+ } else {
+ fail("%s is %s, but json_validate returned %s",
+ s,
+ valid ? "valid" : "invalid",
+ valid ? "false" : "true");
+ }
+ }
+
+ if (ferror(f) || fclose(f) != 0) {
+ diag("I/O error reading test strings.");
+ return 1;
+ }
+
+ return exit_status();
+}
diff --git a/contrib/ccan/json/test/test-strings b/contrib/ccan/json/test/test-strings
new file mode 100644
index 0000000..439be7d
--- /dev/null
+++ b/contrib/ccan/json/test/test-strings
@@ -0,0 +1,224 @@
+invalid
+invalid
+invalid "
+invalid [,]
+invalid [)
+invalid []]
+invalid [}
+invalid {,}
+invalid {]
+invalid ["1":2]
+invalid [1,2,]
+invalid [1:2}
+invalid {"1":2,}
+invalid {1:2}
+invalid {"1":2, "2.5" : [3, 4, {}, {"5": ["6"], [7 ]}]}
+invalid {"1":2, "2.5" : [3, 4, {}, {"5": ["6"], [7]}]}
+invalid {"1":2, "2.5" : [3, 4, {}, {"5": ["6"], "7" :[8 ]}]
+invalid {"1":2, "2.5" : [3, 4, {}, {"5": ["6"], "7" :[8 ]}]]
+invalid {"1":2, "3":4
+invalid "1\u2"
+invalid [,2]
+invalid "3
+invalid "3" "4"
+invalid [3[4]
+invalid [3[4]]
+invalid [3, [4, [5], 6] 7, 8 9]
+invalid [3, [4, [5], 6] 7, 8, 9]
+invalid [3, [4, [5], 6], 7, 8 9]
+invalid {"hello":true, "bye":false, null}
+invalid {"hello":true, "bye":false, null:null}
+invalid "hi
+invalid "hi"""
+invalid {"hi": "bye"]
+invalid "\uD800\uD800"
+invalid "\uD800\uDBFF"
+invalid "\UD834\UDD1E"
+invalid "\uDB00"
+invalid "\uDB00\uDBFF"
+valid "\uFFFE"
+valid "\uFFFF"
+invalid .
+valid ""
+valid []
+valid {}
+invalid +.
+valid 0.5
+invalid 0.e1
+valid {"1":{}}
+valid {"1":2}
+valid {"1":2, "2.5" : [3, 4, {}, {"5": ["6"]}]}
+valid {"1":2, "2.5" : [3, 4, {}, {"5": ["6"], "7" :[8 ]}]}
+valid 1234
+valid -1234
+valid {"1":2, "3":4}
+invalid +1234
+invalid ++1234
+valid 123.456e142
+valid 123.456e-142
+valid 123.456e+142
+invalid 123.e-142
+valid "1\u2000"
+valid "1\u20001"
+valid 2
+invalid .246e-142
+invalid .2e-142
+valid 3
+invalid .3
+valid "3"
+valid [3]
+invalid +3.
+valid 3.2e+1
+valid [3, [4]]
+valid [3, [4, [5]]]
+valid [3, [4, [5], 6]]
+valid [3, [4, [5], 6], 7]
+valid [3, [4, [5], 6], 7, 8]
+valid [3, [4, [5], 6], 7, 8, 9]
+invalid +3.5
+invalid .3e
+invalid .3e1
+invalid .3e-1
+invalid .3e+1
+invalid 3.e1
+invalid 3.e+1
+valid 3e+1
+invalid .5
+invalid +.5
+invalid .5e+1
+valid [ 7]
+valid [7 ]
+valid [7]
+invalid .e-14234
+valid "hello"
+valid ["hello"]
+valid ["hello", "bye"]
+valid ["hello", "bye\n"]
+valid ["hello", "bye\n\r\t"]
+valid ["hello", "bye\n\r\t\b"]
+valid ["hello", "bye\n\r\t\b",true]
+valid ["hello", "bye\n\r\t\b",true , false]
+valid ["hello", "bye\n\r\t\b",true , false, null]
+invalid ["hello", "bye\n\r\t\v"]
+valid {"hello":true}
+valid {"hello":true, "bye":false}
+valid {"hello":true, "bye":false, "foo":["one","two","three"]}
+valid "hi"
+valid ["hi"]
+valid ["hi", "bye"]
+valid {"hi": "bye"}
+valid ["hi", "bye", 3]
+valid ["hi", "bye[", 3]
+valid "\u0007"
+valid "\u0008"
+valid "\u0009"
+valid "\u0010"
+valid "\u0020"
+valid "\u10000"
+valid "\u1234"
+valid "\u99999"
+valid "\ud800\udc00"
+valid "\uD800\uDC00"
+valid "\uD834\uDD1E"
+valid "\uDBFF\uDFFF"
+valid "\uFFFD"
+valid "\uFFFF"
+invalid hello
+valid [32, 1]
+invalid [32,
+valid "\uD800\uDC00"
+valid "\n"
+valid "hello"
+valid "hello\u0009world"
+valid "hello"
+valid "hello\n"
+valid "hello"
+valid 3
+invalid 3.
+invalid .3
+valid 0.3
+invalid 0.3e
+invalid 0.3e+
+valid 0.3e+5
+valid 0.3e-5
+valid 0.3e5
+valid "hello"
+invalid +3
+valid -3
+invalid -3.
+valid -3.1
+invalid .5
+invalid 5.
+invalid 5.e1
+valid 0.5
+invalid .3e1
+invalid .3e+1
+invalid .3e-1
+invalid .3e-1 .5
+invalid .3e-1.5
+invalid .3e+1.5
+invalid .3e+.
+invalid .3e+.5
+invalid .3e+1.5
+invalid 9.3e+1.5
+invalid 9.e+1.5
+invalid 9.e+
+invalid 9.e+1
+valid "\""
+valid "\"3.5"
+valid "\"."
+invalid "\".".
+valid "\"....."
+invalid "\"\"\"\"""
+invalid ["\"\"\"\"", .5]
+invalid [.5]
+valid ["\"\"\"\"", 0.5]
+invalid ["\"\"\"\"", .5]
+invalid ["\"\"\"\"",.5]
+invalid ["\"",.5]
+invalid ["\".5",.5]
+invalid ["\".5",".5\"".5]
+invalid ["\".5",".5\"", .5]
+invalid ["\".5",".5\"",.5]
+valid ["\".5",".5\"",0.5]
+invalid {"key":/*comment*/"value"}
+invalid {"key":/*comment"value"}
+invalid {"key":"value"}/*
+invalid {"key":"value"}/**/
+invalid {"key":"value"}/***/
+invalid {"key":"value"}/**//
+invalid {"key":"value"}/**///
+invalid {"key":"value"}/**///----
+invalid {"key":"value"}#
+invalid {"key":"value"}#{
+invalid {"key":"value"}#{}
+invalid {"key":"value"}#,
+invalid {"key":"value"/**/, "k2":"v2"}
+valid "\u0027"
+invalid "hello\'"
+invalid 'hello\''
+invalid 'hello'
+invalid 'hell\'o'
+invalid '\'hello'
+invalid '\'hello\''
+invalid \'hello\'
+invalid 'hello\'
+invalid ['hello\']
+invalid ['hello\'']
+invalid ['hello"']
+invalid ['hello\"']
+invalid ['hello"o']
+invalid ['"']
+invalid '"'
+invalid '"hello"'
+invalid '"hello'
+invalid '"hi"'
+valid [ 1 , 2 , 3 ]
+invalid nil
+invalid fals
+invalid falsify
+invalid falsetto
+invalid truism
+invalid {"key"
+invalid {"key","key2":value}
+invalid "\u0000"
diff --git a/contrib/ccan/json/test/test-strings-reencoded b/contrib/ccan/json/test/test-strings-reencoded
new file mode 100644
index 0000000..97890c1
--- /dev/null
+++ b/contrib/ccan/json/test/test-strings-reencoded
@@ -0,0 +1,90 @@
+"￾"
+"￿"
+""
+[]
+{}
+0.5
+{"1":{}}
+{"1":2}
+{"1":2,"2.5":[3,4,{},{"5":["6"]}]}
+{"1":2,"2.5":[3,4,{},{"5":["6"],"7":[8]}]}
+1234
+-1234
+{"1":2,"3":4}
+1.23456e+144
+1.23456e-140
+1.23456e+144
+"1 "
+"1 1"
+2
+3
+"3"
+[3]
+32
+[3,[4]]
+[3,[4,[5]]]
+[3,[4,[5],6]]
+[3,[4,[5],6],7]
+[3,[4,[5],6],7,8]
+[3,[4,[5],6],7,8,9]
+30
+[7]
+[7]
+[7]
+"hello"
+["hello"]
+["hello","bye"]
+["hello","bye\n"]
+["hello","bye\n\r\t"]
+["hello","bye\n\r\t\b"]
+["hello","bye\n\r\t\b",true]
+["hello","bye\n\r\t\b",true,false]
+["hello","bye\n\r\t\b",true,false,null]
+{"hello":true}
+{"hello":true,"bye":false}
+{"hello":true,"bye":false,"foo":["one","two","three"]}
+"hi"
+["hi"]
+["hi","bye"]
+{"hi":"bye"}
+["hi","bye",3]
+["hi","bye[",3]
+"\u0007"
+"\b"
+"\t"
+"\u0010"
+" "
+"က0"
+"ሴ"
+"香9"
+"𐀀"
+"𐀀"
+"𝄞"
+"􏿿"
+"�"
+"￿"
+[32,1]
+"𐀀"
+"\n"
+"hello"
+"hello\tworld"
+"hello"
+"hello\n"
+"hello"
+3
+0.3
+30000
+3e-06
+30000
+"hello"
+-3
+-3.1
+0.5
+"\""
+"\"3.5"
+"\"."
+"\"....."
+["\"\"\"\"",0.5]
+["\".5",".5\"",0.5]
+"'"
+[1,2,3]