refactor: rename DTree to DValue
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
EXPORT DTree* emit_marker(DTree* call_param)
|
||||
EXPORT DValue* emit_marker(DValue* call_param)
|
||||
{
|
||||
print("UNIT_CALL_EXPORT_OK");
|
||||
return(0);
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
CLI(Request& context)
|
||||
{
|
||||
context.header["Content-Type"] = "text/plain; charset=utf-8";
|
||||
DTree input = cli_input(context);
|
||||
DValue input = cli_input(context);
|
||||
String action = first(input["action"].to_string(), "ping");
|
||||
if(action == "ping")
|
||||
{
|
||||
|
||||
@@ -15,7 +15,7 @@ RENDER(Request& context)
|
||||
failed++;
|
||||
};
|
||||
|
||||
DTree props;
|
||||
DValue props;
|
||||
props["title"] = "Component Output";
|
||||
props["body"] = "This body comes from component()";
|
||||
props["footer"] = "Named footer render";
|
||||
|
||||
+35
-35
@@ -15,7 +15,7 @@ RENDER(Request& context)
|
||||
failed++;
|
||||
};
|
||||
|
||||
site_tests_page_start("Core APIs", "Pure helper coverage for strings, UTF-8 splitting, DTree, and JSON encoding/decoding.");
|
||||
site_tests_page_start("Core APIs", "Pure helper coverage for strings, UTF-8 splitting, DValue, and JSON encoding/decoding.");
|
||||
|
||||
auto comma_parts = split("alpha,beta,gamma", ",");
|
||||
auto empty_delim_parts = split("alpha", "");
|
||||
@@ -35,10 +35,10 @@ RENDER(Request& context)
|
||||
check("html_escape() attribute-safe quotes", html_escape("<&>\"Don't") == "<&>"Don't", html_escape("<&>\"Don't"));
|
||||
check("regex_match()", regex_match("[A-Z][a-z]+", "Alice") && !regex_match("[A-Z][a-z]+", "Alice!"), "full-string validation");
|
||||
|
||||
DTree regex_email = regex_search("(?<user>[A-Za-z0-9._%+-]+)@(?<host>[A-Za-z0-9.-]+)", "Contact ops@example.test");
|
||||
DValue regex_email = regex_search("(?<user>[A-Za-z0-9._%+-]+)@(?<host>[A-Za-z0-9.-]+)", "Contact ops@example.test");
|
||||
check("regex_search()", regex_email["matched"].to_bool() && regex_email["named"]["user"].to_string() == "ops" && regex_email["named"]["host"].to_string() == "example.test", json_encode(regex_email));
|
||||
|
||||
DTree regex_tags = regex_search_all("#(?<tag>[A-Za-z0-9_]+)", "#uce #docs");
|
||||
DValue regex_tags = regex_search_all("#(?<tag>[A-Za-z0-9_]+)", "#uce #docs");
|
||||
check("regex_search_all()", regex_tags["count"].to_s64() == 2 && regex_tags["matches"]["1"]["named"]["tag"].to_string() == "docs", json_encode(regex_tags));
|
||||
|
||||
check("regex_replace()", regex_replace("#([A-Za-z0-9_]+)", "<tag>$1</tag>", "#uce") == "<tag>uce</tag>", regex_replace("#([A-Za-z0-9_]+)", "<tag>$1</tag>", "#uce"));
|
||||
@@ -64,50 +64,50 @@ RENDER(Request& context)
|
||||
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, ","));
|
||||
|
||||
DTree nav;
|
||||
DTree nav_home;
|
||||
DValue nav;
|
||||
DValue nav_home;
|
||||
nav_home["title"] = "Home";
|
||||
nav_home["section"] = "main";
|
||||
nav.push(nav_home);
|
||||
DTree nav_dash;
|
||||
DValue nav_dash;
|
||||
nav_dash["title"] = "Dashboard";
|
||||
nav_dash["section"] = "app";
|
||||
nav.push(nav_dash);
|
||||
DTree nav_themes;
|
||||
DValue nav_themes;
|
||||
nav_themes["title"] = "Themes";
|
||||
nav_themes["section"] = "app";
|
||||
nav.push(nav_themes);
|
||||
DTree empty_tree;
|
||||
DTree empty_pop = empty_tree.pop();
|
||||
DTree app_nav = dtree_filter(nav, [](DTree item, String key) { return(item["section"].to_string() == "app"); });
|
||||
DTree nav_titles = dtree_map(app_nav, [](DTree item, String key) { DTree title; title = item["title"].to_string(); return(title); });
|
||||
DTree grouped_nav = dtree_group_by(nav, [](DTree item, String key) { return(item["section"].to_string()); });
|
||||
DTree nav_dash_summary = dtree_pick(nav_dash, {"title"});
|
||||
DTree nav_dash_public = dtree_omit(nav_dash, {"section"});
|
||||
check("DTree 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(dtree_keys(nav_dash_summary), ",") == "title" && dtree_values(nav_dash_public)["0"].to_string() == "Dashboard", json_encode(grouped_nav));
|
||||
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));
|
||||
|
||||
DTree conv;
|
||||
DValue conv;
|
||||
conv["name"] = "ada";
|
||||
conv["count"] = "12";
|
||||
conv["junk"] = "not-a-number";
|
||||
conv["flag"] = "off";
|
||||
check("DTree to_* defaults", conv.get_by_path("missing/key").to_string("fallback") == "fallback" && conv["name"].to_string("fallback") == "ada" && conv["junk"].to_s64(-7) == -7 && conv["count"].to_s64(-7) == 12 && conv["junk"].to_f64(2.5) == 2.5 && conv["junk"].to_u64(9) == 9 && conv.get_by_path("nope").to_bool(true) && !conv["flag"].to_bool(true), json_encode(conv));
|
||||
check("DValue to_* defaults", conv.get_by_path("missing/key").to_string("fallback") == "fallback" && conv["name"].to_string("fallback") == "ada" && conv["junk"].to_s64(-7) == -7 && conv["count"].to_s64(-7) == 12 && conv["junk"].to_f64(2.5) == 2.5 && conv["junk"].to_u64(9) == 9 && conv.get_by_path("nope").to_bool(true) && !conv["flag"].to_bool(true), json_encode(conv));
|
||||
|
||||
const DTree& conv_read = conv;
|
||||
const DValue& conv_read = conv;
|
||||
String const_each_keys = "";
|
||||
conv_read.each([&](const DTree& item, String key) { const_each_keys += key + ":" + item.to_string("-") + " "; });
|
||||
check("DTree const read accessors", conv_read.has("name") && conv_read.get_by_path("name").to_string() == "ada" && conv_read.is_array() && !conv_read.is_list() && conv_read.to_stringmap()["count"] == "12" && conv_read.get_type_name() == "array" && contains(const_each_keys, "count:12"), const_each_keys);
|
||||
conv_read.each([&](const DValue& item, String key) { const_each_keys += key + ":" + item.to_string("-") + " "; });
|
||||
check("DValue const read accessors", conv_read.has("name") && conv_read.get_by_path("name").to_string() == "ada" && conv_read.is_array() && !conv_read.is_list() && conv_read.to_stringmap()["count"] == "12" && conv_read.get_type_name() == "array" && contains(const_each_keys, "count:12"), const_each_keys);
|
||||
|
||||
DTree ordered;
|
||||
DValue ordered;
|
||||
for(u32 i = 0; i < 12; i++)
|
||||
{
|
||||
DTree ordered_entry;
|
||||
DValue ordered_entry;
|
||||
ordered_entry = "v" + std::to_string(i);
|
||||
ordered.push(ordered_entry);
|
||||
}
|
||||
String ordered_keys = "";
|
||||
ordered.each([&](const DTree& item, String key) { ordered_keys += key + ","; });
|
||||
check("DTree list iteration is numeric", ordered_keys == "0,1,2,3,4,5,6,7,8,9,10,11," && dtree_values(ordered)["10"].to_string() == "v10" && dtree_map(ordered, [](const DTree& item, String key) { return(item); })["11"].to_string() == "v11", 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);
|
||||
|
||||
String binary_payload = "core";
|
||||
binary_payload.push_back((char)0x00);
|
||||
@@ -124,44 +124,44 @@ RENDER(Request& context)
|
||||
auto utf8_parts = split_utf8(utf8_sample);
|
||||
check("split_utf8()", utf8_parts.size() == 2, "count=" + std::to_string(utf8_parts.size()));
|
||||
|
||||
DTree payload;
|
||||
DValue payload;
|
||||
payload["name"] = "uce";
|
||||
payload["count"] = (f64)3;
|
||||
payload["kind"] = "core";
|
||||
String payload_json = json_encode(payload);
|
||||
DTree decoded = json_decode(payload_json);
|
||||
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);
|
||||
|
||||
DTree xml_doc;
|
||||
DValue xml_doc;
|
||||
xml_doc["name"] = "book";
|
||||
xml_doc["attrs"]["id"] = "b1";
|
||||
DTree xml_title;
|
||||
DValue xml_title;
|
||||
xml_title["name"] = "title";
|
||||
xml_title["text"] = "UCE & XML";
|
||||
xml_doc["children"].push(xml_title);
|
||||
String encoded_xml = xml_encode(xml_doc);
|
||||
DTree decoded_xml = xml_decode(encoded_xml);
|
||||
DValue decoded_xml = xml_decode(encoded_xml);
|
||||
check("xml_encode() / xml_decode()", contains(encoded_xml, "id=\"b1\"") && contains(encoded_xml, "UCE & XML") && decoded_xml["children"]["0"]["text"].to_string() == "UCE & XML", encoded_xml);
|
||||
|
||||
DTree xml_payload;
|
||||
DValue xml_payload;
|
||||
xml_payload["title"] = "Hello";
|
||||
xml_payload["count"] = "3";
|
||||
check("xml_encode() simple map", xml_encode(xml_payload, "payload") == "<payload><count>3</count><title>Hello</title></payload>", xml_encode(xml_payload, "payload"));
|
||||
check("xml_decode() numeric entities", xml_decode("<x>AB</x>")["text"].to_string() == "AB", xml_decode("<x>AB</x>")["text"].to_string());
|
||||
|
||||
String yaml_config = "app:\n name: UCE Starter\n debug: true\n port: 8080\n paths:\n - site\n - cache\nmessage: |\n hello\n world\n";
|
||||
DTree decoded_yaml = yaml_decode(yaml_config);
|
||||
DValue decoded_yaml = yaml_decode(yaml_config);
|
||||
check("yaml_decode() config", decoded_yaml["app"]["name"].to_string() == "UCE Starter" && decoded_yaml["app"]["debug"].to_bool() && decoded_yaml["app"]["port"].to_s64() == 8080 && decoded_yaml["app"]["paths"]["1"].to_string() == "cache" && decoded_yaml["message"].to_string() == "hello\nworld", json_encode(decoded_yaml));
|
||||
|
||||
String encoded_yaml = yaml_encode(decoded_yaml);
|
||||
DTree yaml_roundtrip = yaml_decode(encoded_yaml);
|
||||
DValue yaml_roundtrip = yaml_decode(encoded_yaml);
|
||||
check("yaml_encode() / yaml_decode()", contains(encoded_yaml, "app:") && contains(encoded_yaml, "paths:") && yaml_roundtrip["app"]["debug"].to_bool() && yaml_roundtrip["message"].to_string() == "hello\nworld", encoded_yaml);
|
||||
|
||||
DTree tree;
|
||||
DValue tree;
|
||||
tree["suite"] = "core";
|
||||
tree["nested"]["api"] = "dtree";
|
||||
tree["nested"]["api"] = "dvalue";
|
||||
tree["nested"]["ok"].set_bool(true);
|
||||
check("DTree map access", tree["suite"].to_string() == "core" && tree["nested"]["api"].to_string() == "dtree", json_encode(tree));
|
||||
check("DValue map access", tree["suite"].to_string() == "core" && tree["nested"]["api"].to_string() == "dvalue", json_encode(tree));
|
||||
|
||||
site_tests_summary(passed, failed, skipped, "These assertions intentionally stay pure and side-effect free so they remain safe on the public site.");
|
||||
site_tests_page_end();
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
RENDER(Request& context)
|
||||
{
|
||||
String tests_dir = dirname(context.params["SCRIPT_FILENAME"]);
|
||||
DTree manifest = site_tests_manifest(tests_dir + "/manifest.txt");
|
||||
DValue manifest = site_tests_manifest(tests_dir + "/manifest.txt");
|
||||
StringList entries = list_sort(ls(tests_dir));
|
||||
|
||||
site_tests_page_start("Coverage Index", "Public and local-only UCE regression coverage pages.");
|
||||
@@ -12,7 +12,7 @@ RENDER(Request& context)
|
||||
{
|
||||
if(!str_ends_with(entry, ".uce"))
|
||||
continue;
|
||||
DTree meta = manifest[entry];
|
||||
DValue meta = manifest[entry];
|
||||
String title = meta["title"].to_string();
|
||||
String description = meta["description"].to_string();
|
||||
String tags = meta["tags"].to_string();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# file|title|description|tags|expected|suite|index
|
||||
index.uce|Coverage Index|Public and local-only UCE regression coverage pages.|http suite uce public|Coverage Index|1|1
|
||||
core.uce|Core APIs|Pure helper coverage for strings, regex, UTF-8, DTree, and JSON.|http suite uce public|Core APIs|1|1
|
||||
core.uce|Core APIs|Pure helper coverage for strings, regex, UTF-8, DValue, and JSON.|http suite uce public|Core APIs|1|1
|
||||
preprocessor.uce|Preprocessor|Literal-output parser regression coverage.|http suite uce public|top-level )" marker|1|1
|
||||
http.uce|HTTP And Session|Request, response, cookie, and session helpers.|http suite uce public|HTTP And Session|1|1
|
||||
components.uce|Components|component(), props, and component rendering.|http suite uce public|Components|1|1
|
||||
@@ -8,7 +8,7 @@ markdown.uce|Markdown|Markdown parsing, rendering, and component hooks.|http sui
|
||||
units.uce|Units|unit_call(), lifecycle hooks, and unit metadata.|http suite uce public|Units|1|1
|
||||
websockets.ws.uce|WebSockets|Browser-driven WebSocket helper checks.|http suite uce public websocket|WebSockets|1|1
|
||||
io.uce|Filesystem|Filesystem helpers that are restricted outside trusted networks.|http suite uce internal|Filesystem|1|1
|
||||
sqlite.uce|SQLite|SQLite connector with prepared named parameters and DTree rows.|http suite uce internal sqlite|SQLite|1|1
|
||||
sqlite.uce|SQLite|SQLite connector with prepared named parameters and DValue rows.|http suite uce internal sqlite|SQLite|1|1
|
||||
zip.uce|ZIP|Archive helpers that create and extract temporary server-side files.|http suite uce internal|ZIP|1|1
|
||||
services.uce|Sockets And Services|Network/service helpers that are restricted outside trusted networks.|http suite uce internal|Sockets And Services|1|1
|
||||
tasks.uce|Tasks|Background task helper coverage.|http suite uce internal|Tasks|1|1
|
||||
|
||||
@@ -16,11 +16,11 @@ RENDER(Request& context)
|
||||
};
|
||||
|
||||
String markdown_src = "# Site Test Heading\n\nParagraph with **bold** content.\n\n:::warning\nWatch the component hook\n:::\n\n```txt\ncode block\n```\n";
|
||||
DTree options;
|
||||
DValue options;
|
||||
options["components"][":::warning"] = "components/markdown/warning";
|
||||
options["components"]["node.code_block"] = "components/markdown/code_block";
|
||||
|
||||
DTree ast = markdown_to_ast(markdown_src, options);
|
||||
DValue ast = markdown_to_ast(markdown_src, options);
|
||||
String ast_json = json_encode(ast);
|
||||
String html = markdown_to_html(markdown_src, options);
|
||||
String ast_excerpt = ast_json.substr(0, ast_json.length() > 220 ? 220 : ast_json.length());
|
||||
|
||||
@@ -32,7 +32,7 @@ RENDER(Request& context)
|
||||
String multi_statement_error = sqlite_error(db);
|
||||
StringMap dropped_params;
|
||||
dropped_params["name"] = "dropped";
|
||||
DTree dropped_tables = sqlite_query(db, "select name from sqlite_master where type = 'table' and name = :name", dropped_params);
|
||||
DValue dropped_tables = sqlite_query(db, "select name from sqlite_master where type = 'table' and name = :name", dropped_params);
|
||||
check("sqlite_query() rejects multi-statement SQL", multi_statement_error.find("exactly one SQL statement") != String::npos && dropped_tables["0"]["name"].to_string() == "", multi_statement_error + " tables=" + json_encode(dropped_tables));
|
||||
|
||||
StringMap ada;
|
||||
@@ -52,7 +52,7 @@ RENDER(Request& context)
|
||||
|
||||
StringMap query_params;
|
||||
query_params["min_visits"] = "4";
|
||||
DTree rows = sqlite_query(db, "select id, email, visits, rating from users where visits >= :min_visits order by id", query_params);
|
||||
DValue rows = sqlite_query(db, "select id, email, visits, rating from users where visits >= :min_visits order by id", query_params);
|
||||
check("sqlite_query() rows", rows.is_array() && rows["0"]["email"].to_string() == "ada@example.test" && rows["0"]["visits"].to_s64() == 7 && rows["0"]["rating"].to_f64() > 4.49, json_encode(rows));
|
||||
|
||||
sqlite_query(db, "select id from users where id = ?", query_params);
|
||||
|
||||
@@ -64,9 +64,9 @@ void site_tests_card(String href, String title, String description, String tags
|
||||
print("</a>");
|
||||
}
|
||||
|
||||
DTree site_tests_manifest(String manifest_path = "manifest.txt")
|
||||
DValue site_tests_manifest(String manifest_path = "manifest.txt")
|
||||
{
|
||||
DTree manifest;
|
||||
DValue manifest;
|
||||
for(String line : split(file_get_contents(manifest_path), "\n"))
|
||||
{
|
||||
line = trim(line);
|
||||
|
||||
@@ -16,7 +16,7 @@ RENDER(Request& context)
|
||||
};
|
||||
|
||||
auto unit_paths = units_list();
|
||||
DTree info = unit_info("call_helpers.uce");
|
||||
DValue info = unit_info("call_helpers.uce");
|
||||
|
||||
ob_start();
|
||||
unit_call("call_helpers.uce", "emit_marker");
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "testlib.h"
|
||||
|
||||
DTree websocket_suite_event(Request& context, String type, String nonce)
|
||||
DValue websocket_suite_event(Request& context, String type, String nonce)
|
||||
{
|
||||
DTree event;
|
||||
DValue event;
|
||||
event["type"] = type;
|
||||
event["nonce"] = nonce;
|
||||
event["connection_id"] = ws_connection_id();
|
||||
@@ -106,7 +106,7 @@ WS(Request& context)
|
||||
return;
|
||||
}
|
||||
|
||||
DTree payload = json_decode(ws_message());
|
||||
DValue payload = json_decode(ws_message());
|
||||
String type = trim(payload["type"].to_string());
|
||||
String nonce = trim(payload["nonce"].to_string());
|
||||
|
||||
|
||||
+6
-6
@@ -29,16 +29,16 @@ RENDER(Request& context)
|
||||
mkdir(base);
|
||||
mkdir(extract_dir);
|
||||
|
||||
DTree entries;
|
||||
DValue entries;
|
||||
entries["hello.txt"] = "Hello ZIP";
|
||||
entries["nested/readme.txt"] = "Nested file";
|
||||
DTree explicit_entry;
|
||||
DValue explicit_entry;
|
||||
explicit_entry["name"] = "data/value.txt";
|
||||
explicit_entry["content"] = "42";
|
||||
entries["ignored-map-key"] = explicit_entry;
|
||||
|
||||
bool created = zip_create(archive, entries);
|
||||
DTree listed = zip_list(archive);
|
||||
DValue listed = zip_list(archive);
|
||||
String hello = zip_read(archive, "hello.txt");
|
||||
bool extracted = zip_extract(archive, extract_dir);
|
||||
String nested = file_get_contents(path_join(extract_dir, "nested/readme.txt"));
|
||||
@@ -52,7 +52,7 @@ RENDER(Request& context)
|
||||
bool unsafe_rejected = false;
|
||||
try
|
||||
{
|
||||
DTree unsafe_entries;
|
||||
DValue unsafe_entries;
|
||||
unsafe_entries["/absolute.txt"] = "bad";
|
||||
zip_create(path_join(base, "unsafe.zip"), unsafe_entries);
|
||||
}
|
||||
@@ -65,7 +65,7 @@ RENDER(Request& context)
|
||||
bool nul_name_rejected = false;
|
||||
try
|
||||
{
|
||||
DTree unsafe_entries;
|
||||
DValue unsafe_entries;
|
||||
String nul_name = "prefix";
|
||||
nul_name.push_back((char)0x00);
|
||||
nul_name += "suffix.txt";
|
||||
@@ -83,7 +83,7 @@ RENDER(Request& context)
|
||||
binary_source += "binary";
|
||||
binary_source.push_back((char)0xff);
|
||||
binary_source += "payload";
|
||||
DTree binary_entries;
|
||||
DValue binary_entries;
|
||||
binary_entries["binary.dat"] = binary_source;
|
||||
String binary_archive = path_join(base, "binary.zip");
|
||||
bool binary_created = zip_create(binary_archive, binary_entries);
|
||||
|
||||
Reference in New Issue
Block a user