Copy void DumpDict(const string &in label, dictionary &in d)
{
log(label);
array<string>@ keys = d.getKeys();
for (uint i = 0; i < keys.length(); i++)
{
string k = keys[i];
// Try double first
double dv;
string sv;
bool gotDouble = d.get(k, dv);
bool gotString = d.get(k, sv);
string vStr;
if (gotDouble)
vStr = "double " + k + " = " + dv;
else if (gotString)
vStr = "string " + k + " = \"" + sv + "\"";
else
vStr = "key " + k + " (unsupported type in dump)";
log(" " + vStr);
}
}
void TestBasicParse()
{
log("[1] Basic json_parse / json_decode");
const string jsonText = """
{
"number": 123,
"float": 3.14,
"bool_true": true,
"bool_false": false,
"text": "hello",
"object": { "x": 10, "y": 20 }
}
""";
dictionary d;
string err;
if (!json_parse(jsonText, d, err))
{
log_error(" [FAIL] json_parse failed: " + err);
return;
}
log(" [ OK ] json_parse succeeded");
DumpDict(" Dump of parsed dictionary:", d);
// Basic checks
double num = 0;
double flt = 0;
string txt;
if (d.get("number", num) && num == 123)
log(" [ OK ] number == 123");
else
log_error(" [FAIL] number != 123");
if (d.get("float", flt) && flt > 3.13 && flt < 3.15)
log(" [ OK ] float ~= 3.14");
else
log_error(" [FAIL] float ~= 3.14");
if (d.get("text", txt) && txt == "hello")
log(" [ OK ] text == \"hello\"");
else
log_error(" [FAIL] text != \"hello\"");
// bools are stored as doubles (1.0 / 0.0)
double bt = 0, bf = 1;
d.get("bool_true", bt);
d.get("bool_false", bf);
if (bt == 1.0 && bf == 0.0)
log(" [ OK ] bool_true/false mapped to 1.0/0.0");
else
log_error(" [FAIL] bool mapping incorrect");
// Test alias json_decode
dictionary d2;
string err2;
if (json_decode("{\"a\":1,\"b\":2}", d2, err2))
log(" [ OK ] json_decode succeeded");
else
log_error(" [FAIL] json_decode failed: " + err2);
}
void TestInvalidParse()
{
log("\n[2] Invalid JSON parse test");
dictionary d;
string err;
const string badJson = "{ invalid json !!! }";
bool ok = json_parse(badJson, d, err);
if (!ok)
{
log(" [ OK ] json_parse returned false for invalid JSON");
log(" error: " + err);
}
else
{
log_error(" [FAIL] json_parse unexpectedly succeeded on invalid JSON");
}
}
void TestStringifyRoundtrip()
{
log("\n[3] json_stringify / json_encode roundtrip");
dictionary d;
d.set("hello", "world");
d.set("num", 42.0); // numbers are stored as double
d.set("float", 1.5);
d.set("flag_bool", true); // bool (script side)
d.set("flag_num", 1.0); // numeric boolean
// nested object
dictionary nested;
nested.set("x", 10.0);
nested.set("y", 20.0);
d.set("nested", @nested);
DumpDict(" Original dictionary:", d);
string json;
string err;
if (!json_stringify(d, json, err))
{
log_error(" [FAIL] json_stringify failed: " + err);
return;
}
log(" [ OK ] json_stringify succeeded");
log(" JSON: " + json);
// Roundtrip: parse back
dictionary back;
string err2;
if (!json_parse(json, back, err2))
{
log_error(" [FAIL] parse(stringify(...)) failed: " + err2);
return;
}
log(" [ OK ] parse(stringify(...)) succeeded");
DumpDict(" Decoded dictionary:", back);
// Test alias json_encode
string json2, err3;
if (json_encode(d, json2, err3))
log(" [ OK ] json_encode succeeded: " + json2);
else
log_error(" [FAIL] json_encode failed: " + err3);
}
void TestNullAndArrays()
{
log("\n[4] Null and array handling note");
const string txt = """
{
"a": 1,
"b": null,
"c": [1,2,3]
}
""";
dictionary d;
string err;
if (!json_parse(txt, d, err))
{
log_error(" [FAIL] parse failed: " + err);
return;
}
DumpDict(" Parsed dictionary:", d);
// "b" is null -> omitted
double a = 0;
bool hasB = d.exists("b");
d.get("a", a);
if (a == 1.0 && !hasB)
log(" [ OK ] null field skipped, 'a' present");
else
log_error(" [FAIL] null or 'a' handling incorrect");
// "c" is an array -> currently skipped
if (!d.exists("c"))
log(" [ OK ] array key 'c' skipped as expected");
else
log_error(" [FAIL] array key 'c' unexpectedly present");
}
int main()
{
log("=== JSON API Test Begin (AngelScript) ===");
TestBasicParse();
TestInvalidParse();
TestStringifyRoundtrip();
TestNullAndArrays();
log("=== JSON API Test End ===");
return 0;
}