This commit is contained in:
root
2026-06-15 21:42:50 +00:00
parent 34a97e2577
commit 99cd92fb4a
126 changed files with 1615 additions and 1057 deletions
+29 -15
View File
@@ -60,9 +60,11 @@ RENDER(Request& context)
StringList route_parts = {"dashboard", "index", "dashboard", "themes"};
auto unique_routes = list_unique(route_parts);
auto sorted_routes = list_sort(unique_routes);
auto upper_routes = map(sorted_routes, [](String item) { return(to_upper(item)); });
auto dashboard_routes = filter(route_parts, [](String item) { return(item == "dashboard"); });
check("map/filter/list_unique/sort/find/some/every", unique_routes.size() == 3 && sorted_routes[0] == "dashboard" && upper_routes[2] == "THEMES" && dashboard_routes.size() == 2 && list_find(route_parts, [](String item) { return(str_starts_with(item, "them")); }, "missing") == "themes" && list_some(route_parts, [](String item) { return(item == "index"); }) && list_every(unique_routes, [](String item) { return(item != ""); }), join(upper_routes, ","));
auto upper_routes = sorted_routes.map([](String item) { return(to_upper(item)); });
auto dashboard_routes = route_parts.filter([](String item) { return(item == "dashboard"); });
String route_each = "";
route_parts.each([&](String item) { route_each += item + ","; });
check("StringList map/filter/keys/each/list_unique/sort/find/some/every", unique_routes.size() == 3 && sorted_routes[0] == "dashboard" && upper_routes[2] == "THEMES" && dashboard_routes.size() == 2 && join(route_parts.keys(), ",") == "0,1,2,3" && route_each == "dashboard,index,dashboard,themes," && list_find(route_parts, [](String item) { return(str_starts_with(item, "them")); }, "missing") == "themes" && list_some(route_parts, [](String item) { return(item == "index"); }) && list_every(unique_routes, [](String item) { return(item != ""); }), join(upper_routes, ","));
DValue nav;
DValue nav_home;
@@ -79,12 +81,10 @@ RENDER(Request& context)
nav.push(nav_themes);
DValue empty_tree;
DValue empty_pop = empty_tree.pop();
DValue app_nav = dv_filter(nav, [](DValue item, String key) { return(item["section"].to_string() == "app"); });
DValue nav_titles = dv_map(app_nav, [](DValue item, String key) { DValue title; title = item["title"].to_string(); return(title); });
DValue grouped_nav = dv_group_by(nav, [](DValue item, String key) { return(item["section"].to_string()); });
DValue nav_dash_summary = dv_pick(nav_dash, {"title"});
DValue nav_dash_public = dv_omit(nav_dash, {"section"});
check("DValue collection helpers", empty_pop.to_string() == "" && app_nav.is_list() && nav_titles["0"].to_string() == "Dashboard" && grouped_nav["app"]["1"]["title"].to_string() == "Themes" && join(dv_keys(nav_dash_summary), ",") == "title" && dv_values(nav_dash_public)["0"].to_string() == "Dashboard", json_encode(grouped_nav));
DValue app_nav = nav.filter([](DValue item, String key) { return(item["section"].to_string() == "app"); });
DValue nav_titles = app_nav.map([](DValue item, String key) { DValue title; title = item["title"].to_string(); return(title); });
DValue nav_dash_summary = nav_dash.filter({"title"});
check("DValue collection helpers", empty_pop.to_string() == "" && app_nav.is_list() && nav_titles["0"].to_string() == "Dashboard" && join(nav_dash_summary.keys(), ",") == "title" && nav_dash.values()["0"].to_string() == "app" && nav_dash.values()["1"].to_string() == "Dashboard", json_encode(nav_titles));
DValue conv;
conv["name"] = "ada";
@@ -107,7 +107,7 @@ RENDER(Request& context)
}
String ordered_keys = "";
ordered.each([&](const DValue& item, String key) { ordered_keys += key + ","; });
check("DValue list iteration is numeric", ordered_keys == "0,1,2,3,4,5,6,7,8,9,10,11," && dv_values(ordered)["10"].to_string() == "v10" && dv_map(ordered, [](const DValue& item, String key) { return(item); })["11"].to_string() == "v11", ordered_keys);
check("DValue list iteration is numeric", ordered_keys == "0,1,2,3,4,5,6,7,8,9,10,11," && ordered.values()["10"].to_string() == "v10" && ordered.map([](const DValue& item, String key) { return(item); })["11"].to_string() == "v11", ordered_keys);
DValue uceb_source;
uceb_source["name"] = "phase1";
@@ -129,27 +129,31 @@ RENDER(Request& context)
String uceb_error = "";
DValue uceb_decoded;
bool uceb_ok = ucb_decode(uceb_encoded, uceb_decoded, &uceb_error);
check("UCEB1 DValue codec round-trip", uceb_ok && uceb_decoded["name"].to_string() == "phase1" && uceb_decoded["nested"]["answer"].to_string() == "42" && uceb_decoded["float"].to_f64() > 0.00000009 && uceb_decoded["float"].to_f64() < 0.00000011 && uceb_decoded["bool"].to_bool() && uceb_decoded["items"].is_list() && uceb_decoded["items"]["1"].to_string() == "second" && uceb_decoded["empty_list"].is_list() && uceb_decoded["binary"].to_string().size() == uceb_binary.size() && uceb_decoded["binary"].to_string() == uceb_binary && uceb_decoded["pointer"].to_string() == "", "bytes=" + std::to_string((u64)uceb_encoded.size()) + " error=" + uceb_error + " float=" + uceb_decoded["float"].to_string());
check("UCEB2 DValue codec round-trip preserves scalar types", uceb_ok && uceb_decoded["name"].to_string() == "phase1" && uceb_decoded["name"].get_type_name() == "String" && uceb_decoded["nested"]["answer"].to_string() == "42" && uceb_decoded["float"].get_type_name() == "f64" && uceb_decoded["float"].to_f64() > 0.00000009 && uceb_decoded["float"].to_f64() < 0.00000011 && uceb_decoded["bool"].get_type_name() == "bool" && uceb_decoded["bool"].to_bool() && uceb_decoded["items"].is_list() && uceb_decoded["items"]["1"].to_string() == "second" && uceb_decoded["empty_list"].is_list() && uceb_decoded["binary"].to_string().size() == uceb_binary.size() && uceb_decoded["binary"].to_string() == uceb_binary && uceb_decoded["pointer"].to_string() == "", "bytes=" + std::to_string((u64)uceb_encoded.size()) + " error=" + uceb_error + " float=" + uceb_decoded["float"].to_string() + " types=" + uceb_decoded["name"].get_type_name() + "/" + uceb_decoded["float"].get_type_name() + "/" + uceb_decoded["bool"].get_type_name());
DValue uceb_invalid;
String uceb_bad_magic = "NOPE";
uceb_bad_magic.push_back((char)1);
String uceb_wrong_version = "UCEB";
uceb_wrong_version.push_back((char)2);
uceb_wrong_version.push_back((char)3);
String uceb_truncated = "UCEB";
uceb_truncated.push_back((char)1);
uceb_truncated.push_back((char)2);
uceb_truncated.push_back((char)0);
uceb_truncated.push_back('S');
uceb_truncated.push_back((char)0x80);
String uceb_depth_bomb = "UCEB";
uceb_depth_bomb.push_back((char)1);
uceb_depth_bomb.push_back((char)2);
for(u32 i = 0; i < 1030; i++)
{
uceb_depth_bomb.push_back((char)0); // flags
uceb_depth_bomb.push_back('M'); // node type
uceb_depth_bomb.push_back((char)0); // scalar length
uceb_depth_bomb.push_back((char)1); // child count
uceb_depth_bomb.push_back((char)1); // key length
uceb_depth_bomb += "x";
}
uceb_depth_bomb.push_back((char)0);
uceb_depth_bomb.push_back('M');
uceb_depth_bomb.push_back((char)0);
uceb_depth_bomb.push_back((char)0);
String uceb_negative_error = "";
@@ -163,7 +167,7 @@ RENDER(Request& context)
bool uceb_trailing_ok = ucb_decode(uceb_trailing, uceb_invalid, &uceb_negative_error);
String uceb_trailing_error = uceb_negative_error;
bool uceb_depth_ok = ucb_decode(uceb_depth_bomb, uceb_invalid, &uceb_negative_error);
check("UCEB1 rejects invalid input", !uceb_bad_magic_ok && contains(uceb_magic_error, "magic") && !uceb_wrong_version_ok && contains(uceb_version_error, "version") && !uceb_truncated_ok && contains(uceb_truncated_error, "length") && !uceb_trailing_ok && contains(uceb_trailing_error, "trailing") && !uceb_depth_ok && contains(uceb_negative_error, "nesting"), uceb_magic_error + " / " + uceb_version_error + " / " + uceb_truncated_error + " / " + uceb_trailing_error + " / " + uceb_negative_error);
check("UCEB2 rejects invalid input", !uceb_bad_magic_ok && contains(uceb_magic_error, "magic") && !uceb_wrong_version_ok && contains(uceb_version_error, "version") && !uceb_truncated_ok && contains(uceb_truncated_error, "length") && !uceb_trailing_ok && contains(uceb_trailing_error, "trailing") && !uceb_depth_ok && contains(uceb_negative_error, "nesting"), uceb_magic_error + " / " + uceb_version_error + " / " + uceb_truncated_error + " / " + uceb_trailing_error + " / " + uceb_negative_error);
size_t abi_len = 0;
uce_dvalue* abi_root = reinterpret_cast<uce_dvalue*>(&uceb_source);
@@ -205,6 +209,16 @@ RENDER(Request& context)
DValue decoded = json_decode(payload_json);
check("json_encode() / json_decode()", decoded["name"].to_string() == "uce" && int_val(decoded["count"].to_string()) == 3, payload_json);
DValue decoded_unicode = json_decode("\"\\u00A9\"");
DValue decoded_negative = json_decode("-12.5");
DValue decoded_exponent = json_decode("-1.25e+3");
DValue decoded_surrogate = json_decode("\"\\uD83D\\uDE0A\"");
DValue malformed_unicode = json_decode("\"\\u\"");
DValue malformed_number = json_decode("[1e]");
DValue malformed_map = json_decode("{\"a\":");
check("json_decode() unicode / negatives / exponent", decoded_unicode.to_string() == "©" && decoded_surrogate.to_string() == "\xF0\x9F\x98\x8A" && decoded_negative.to_string() == "-12.5" && decoded_exponent.to_string() == "-1.25e+3", "unicode=" + decoded_unicode.to_string() + " surrogate=" + decoded_surrogate.to_string() + " negative=" + decoded_negative.to_string() + " exponent=" + decoded_exponent.to_string());
check("json_decode() malformed input is safe", malformed_unicode.to_string() == "" && malformed_number["0"].to_string() == "1" && malformed_map.has("a"), malformed_unicode.to_string() + " / " + malformed_number.to_string() + " / " + malformed_map["a"].to_string());
DValue xml_doc;
xml_doc["name"] = "book";
xml_doc["attrs"]["id"] = "b1";