diff options
Diffstat (limited to '')
-rw-r--r-- | contrib/ccan/json/test/common.h | 18 | ||||
-rw-r--r-- | contrib/ccan/json/test/run-construction.c | 191 | ||||
-rw-r--r-- | contrib/ccan/json/test/run-decode-encode.c | 77 | ||||
-rw-r--r-- | contrib/ccan/json/test/run-stringify.c | 108 | ||||
-rw-r--r-- | contrib/ccan/json/test/run-validate.c | 49 | ||||
-rw-r--r-- | contrib/ccan/json/test/test-strings | 224 | ||||
-rw-r--r-- | contrib/ccan/json/test/test-strings-reencoded | 90 |
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] |