use fmt; fn roundtrip(input: str, expected: value) void = { const val = loadstr(input)!; defer finish(val); assert(equal(val, expected)); const s = dumpstr(val); defer free(s); const val = loadstr(s)!; defer finish(val); assert(equal(val, expected)); }; fn errassert(input: str, expected_loc: (uint, uint)) void = { const loc = loadstr(input) as invalid; if (loc.0 != expected_loc.0 || loc.1 != expected_loc.1) { fmt::errorfln("=== JSON:\n{}", input)!; fmt::errorfln("=== expected error location:\n({}, {})", expected_loc.0, expected_loc.1)!; fmt::errorfln("=== actual error location:\n({}, {})", loc.0, loc.1)!; abort(); }; }; @test fn load() void = { let obj = newobject(); defer finish(obj); let obj2 = newobject(); defer finish(obj2); roundtrip(`1234`, 1234.0); roundtrip(`[]`, []); roundtrip(`[1, 2, 3, null]`, [1.0, 2.0, 3.0, _null]); roundtrip(`{}`, obj); set(&obj, "hello", "world"); set(&obj, "answer", 42.0); roundtrip(`{ "hello": "world", "answer": 42 }`, obj); reset(&obj); roundtrip(`[[] ]`, [[]]); roundtrip(`[""]`, [""]); roundtrip(`["a"]`, ["a"]); roundtrip(`[false]`, [false]); roundtrip(`[null, 1, "1", {}]`, [_null, 1.0, "1", obj]); roundtrip(`[null]`, [_null]); roundtrip("[1\n]", [1.0]); roundtrip(`[1,null,null,null,2]`, [1.0, _null, _null, _null, 2.0]); set(&obj, "", 0.0); roundtrip(`{"":0}`, obj); reset(&obj); set(&obj, "foo\0bar", 42.0); roundtrip(`{"foo\u0000bar": 42}`, obj); reset(&obj); set(&obj, "min", -1.0e+28); set(&obj, "max", 1.0e+28); roundtrip(`{"min": -1.0e+28, "max": 1.0e+28}`, obj); reset(&obj); set(&obj, "id", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); set(&obj2, "id", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); set(&obj, "x", [obj2]); roundtrip(`{"x":[{"id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}], "id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}`, obj); reset(&obj); reset(&obj2); set(&obj, "a", []); roundtrip(`{"a":[]}`, obj); roundtrip("{\n" `"a": []` "\n}", obj); reset(&obj); roundtrip(`"\u0060\u012a\u12AB"`, "\u0060\u012a\u12AB"); roundtrip(`"\"\\\/\b\f\n\r\t"`, "\"\\/\b\f\n\r\t"); roundtrip(`"\\u0000"`, `\u0000`); roundtrip(`"\""`, `"`); roundtrip(`"a/*b*/c/*d//e"`, "a/*b*/c/*d//e"); roundtrip(`"\\a"`, `\a`); roundtrip(`"\\n"`, `\n`); roundtrip(`"\u0012"`, "\u0012"); roundtrip(`[ "asd"]`, ["asd"]); roundtrip(`"new\u000Aline"`, "new\nline"); roundtrip(`"\u0000"`, "\0"); roundtrip(`"\u002c"`, "\u002c"); roundtrip(`"asd "`, "asd "); roundtrip(`" "`, " "); roundtrip(`"\u0821"`, "\u0821"); roundtrip(`"\u0123"`, "\u0123"); roundtrip(`"\u0061\u30af\u30EA\u30b9"`, "\u0061\u30af\u30EA\u30b9"); roundtrip(`"\uA66D"`, "\uA66D"); roundtrip(`"\u005C"`, `\`); roundtrip(`"\u0022"`, `"`); roundtrip(`""`, ""); roundtrip(` [] `, []); errassert(`[1,,]`, (1, 4)); errassert(`[1 true]`, (1, 7)); errassert(`["": 1]`, (1, 4)); errassert(`[,1]`, (1, 2)); errassert(`[1,,2]`, (1, 4)); errassert(`["",]`, (1, 5)); errassert(`["x"`, (1, 5)); errassert(`[x`, (1, 2)); errassert(`[3[4]]`, (1, 3)); errassert(`[1:2]`, (1, 3)); errassert(`[,]`, (1, 2)); errassert(`[-]`, (1, 3)); errassert(`[ , ""]`, (1, 5)); errassert("[\"a\",\n4\n,1,", (3, 4)); errassert(`[1,]`, (1, 4)); errassert("[\"\va\"\\f", (1, 3)); errassert(`[*]`, (1, 2)); errassert(`[1,`, (1, 4)); errassert("[1,\n1\n,1", (3, 3)); errassert(`[{}`, (1, 4)); errassert(`["x", truth]`, (1, 11)); errassert(`{[: "x"}`, (1, 2)); errassert(`{"x", null}`, (1, 5)); errassert(`{"x"::"b"}`, (1, 6)); errassert(`{"a":"a" 123}`, (1, 12)); errassert(`{"a" b}`, (1, 6)); errassert(`{:"b"}`, (1, 2)); errassert(`{"a" "b"}`, (1, 8)); errassert(`{"a":`, (1, 6)); errassert(`{"a"`, (1, 5)); errassert(`{1:1}`, (1, 2)); errassert(`{9999E9999:1}`, (1, 10)); errassert(`{null:null,null:null}`, (1, 5)); errassert(`{"id":0,,,,,}`, (1, 9)); errassert(`{'a':0}`, (1, 2)); errassert(`{"id":0,}`, (1, 9)); errassert(`{"a":"b",,"c":"d"}`, (1, 10)); errassert(`{true: false}`, (1, 5)); errassert(`{"a":"a`, (1, 8)); errassert(`{ "foo" : "bar", "a" }`, (1, 22)); errassert(` `, (1, 2)); errassert(``, (1, 1)); errassert(`["asd]`, (1, 7)); errassert(`True`, (1, 4)); errassert(`]`, (1, 1)); errassert(`}`, (1, 1)); errassert(`{"x": true,`, (1, 12)); errassert(`[`, (1, 2)); errassert(`{`, (1, 2)); errassert(``, (1, 1)); errassert("\0", (1, 1)); errassert(`{"":`, (1, 5)); errassert(`['`, (1, 2)); errassert(`["`, (1, 3)); errassert(`[,`, (1, 2)); errassert(`[{`, (1, 3)); errassert(`{[`, (1, 2)); errassert(`{]`, (1, 2)); errassert(`[}`, (1, 2)); errassert(`{'`, (1, 2)); errassert(`{"`, (1, 3)); errassert(`{,`, (1, 2)); errassert(`["\{["\{["\{["\{`, (1, 4)); errassert(`*`, (1, 1)); errassert(`\u000A""`, (1, 1)); errassert("\f", (1, 1)); }; @test fn nestlimit() void = { const s = `{ "foo": [[[{"bar": ["baz"]}]]] }`; const val = loadstr(s, 6: nestlimit)!; finish(val); assert(loadstr(s, 5: nestlimit) is limitreached); };