struct CliHttpResponse { u64 status = 0; String raw; String headers; String body; }; u64 cli_tests_passed = 0; u64 cli_tests_failed = 0; u64 cli_tests_skipped = 0; StringList cli_tests_failures; bool cli_contains(String haystack, String needle) { return(haystack.find(needle) != String::npos); } String cli_truncate(String value, u64 max_len = 240) { if(value.length() <= max_len) return(value); return(value.substr(0, max_len) + "..."); } CliHttpResponse cli_http_request(String host, u16 port, String path, String extra_headers = "") { CliHttpResponse res; u64 fd = socket_connect(host, port); if(fd == 0) { res.raw = "socket_connect failed"; return(res); } String host_header = host; if(host == "127.0.0.1" && port == 80) host_header = "uce.openfu.com"; else if(host == "127.0.0.1" && port == 8080) host_header = "localhost"; String request = "GET " + path + " HTTP/1.0\r\nHost: " + host_header + "\r\nConnection: close\r\n" + extra_headers + "\r\n"; socket_write(fd, request); for(u64 i = 0; i < 16; i++) { String chunk = socket_read(fd, 65536, 30); if(chunk == "") break; res.raw += chunk; } socket_close(fd); u64 line_end = res.raw.find("\r\n"); if(line_end != String::npos) { StringList parts = split(res.raw.substr(0, line_end), " "); if(parts.size() >= 2) res.status = int_val(parts[1]); } u64 split_at = res.raw.find("\r\n\r\n"); if(split_at != String::npos) { res.headers = res.raw.substr(0, split_at + 4); res.body = res.raw.substr(split_at + 4); } else { res.headers = res.raw; res.body = ""; } return(res); } CliHttpResponse cli_frontend(String path, String extra_headers = "") { return(cli_http_request("127.0.0.1", 80, path, extra_headers)); } CliHttpResponse cli_direct_http(String path, String extra_headers = "") { return(cli_http_request("127.0.0.1", 8080, path, extra_headers)); } void cli_test_case(String name, bool ok, String summary) { if(ok) { cli_tests_passed++; print("[PASS] ", name, " - ", summary, "\n"); } else { cli_tests_failed++; cli_tests_failures.push_back(name + ": " + summary); print("[FAIL] ", name, " - ", summary, "\n"); } } void cli_test_skip(String name, String summary) { cli_tests_skipped++; print("[SKIP] ", name, " - ", summary, "\n"); } bool cli_expect_http_once(CliHttpResponse& res, String path, u64 expected_status, String marker, StringList error_markers, String& summary) { bool ok = res.status == expected_status; summary = "HTTP " + std::to_string(res.status) + " for " + path; if(marker != "" && !cli_contains(res.body, marker)) { ok = false; summary += "; missing marker " + marker; } String lower = to_lower(res.body); for(String marker_text : error_markers) { if(cli_contains(lower, marker_text)) { ok = false; summary += "; body contained " + marker_text; } } return(ok); } bool cli_expect_http(String name, String path, u64 expected_status, String marker, StringList error_markers = {}) { CliHttpResponse res = cli_frontend(path); String summary; bool ok = cli_expect_http_once(res, path, expected_status, marker, error_markers, summary); if(!ok && expected_status != 500) { usleep(500000); res = cli_frontend(path); ok = cli_expect_http_once(res, path, expected_status, marker, error_markers, summary); } cli_test_case(name, ok, ok ? summary : summary + "; body=" + cli_truncate(res.body)); return(ok); } StringList cli_demo_error_markers() { StringList markers; markers.push_back(String("uce compile ") + "error"); markers.push_back(String("fatal signal during ") + "request"); markers.push_back(String("uncaught exception during ") + "request"); return(markers); } void cli_run_demo_smoke() { StringList files = split("call_file.uce\ncall_file_funcs.uce\ncollections.uce\ncomponents.uce\ncookie.uce\ndvalue.uce\nempty.uce\nerror-reporting.uce\nfile_append.uce\nfileio.uce\nheader.uce\nhello.uce\nindex.uce\njson.uce\nmarkdown.uce\nmemcached.uce\nmysql.uce\nonce-init.uce\nparse_time.uce\npost-multipart.uce\npost.uce\npreprocessor-comments.uce\nrandom.uce\nregex.uce\nscript.uce\nsession.uce\nsharedunit.uce\nshell.uce\nsqlite.uce\nstr_replace.uce\nstring.uce\ntask-status.uce\ntask.uce\ntask_repeat.uce\nunit-browser.uce\nunit-info.uce\nuri.uce\nutf8.uce\nwebsockets.ws.uce\nworking-dir.uce\nxml.uce\nyaml.uce\nzip.uce", "\n"); for(String file : files) cli_expect_http("uce_demo_smoke:demo page " + file, "/demo/" + file, 200, "", file == "unit-browser.uce" ? StringList() : cli_demo_error_markers()); } bool cli_doc_source_has_example(String source) { for(String line : split(source, "\n")) if(trim(line) == ":example") return(true); return(false); } // A real example must exercise the documented API and print a derived result. // These placeholder shapes (auto-generated stubs) are forbidden by the gate. bool cli_doc_example_is_placeholder(String source) { bool in_example = false; StringList body; for(String line : split(source, "\n")) { String t = trim(line); if(!in_example) { if(t == ":example") in_example = true; continue; } if(t.length() > 0 && t.substr(0, 1) == ":") break; body.push_back(line); } String joined = join(body, "\n"); if(cli_contains(joined, " example\\n\");")) return(true); if(cli_contains(joined, "is resource-bound; configure")) return(true); if(cli_contains(joined, "documents a UCE concept")) return(true); return(false); } void cli_run_doc_pages_gate() { StringList error_markers; error_markers.push_back("doc example error"); error_markers.push_back(String("uce compile ") + "error"); error_markers.push_back(String("wasm runtime error during ") + "request"); error_markers.push_back(String("fatal signal during ") + "request"); error_markers.push_back(String("uncaught exception during ") + "request"); error_markers.push_back("timed out acquiring compile lock"); for(String file_name : ls("../doc/pages/")) { String source = file_get_contents("../doc/pages/" + file_name); String page = nibble(file_name, "."); if(page == "") continue; bool has_example = cli_doc_source_has_example(source); String path = "/doc/index.uce?p=" + uri_encode(page); CliHttpResponse res = cli_frontend(path); String summary; bool ok = cli_expect_http_once(res, path, 200, "doc-detail", error_markers, summary); String lower = to_lower(res.body); if(has_example) { if(!cli_contains(res.body, "class=\"example-output\"") || !cli_contains(res.body, "example-output-label\">Output")) { ok = false; summary += "; missing example Output block"; } if(cli_contains(lower, "doc example error")) { ok = false; summary += "; example reported an error"; } if(cli_doc_example_is_placeholder(source)) { ok = false; summary += "; placeholder example (must exercise the API)"; } } cli_test_case("uce_doc_gate:doc page " + page, ok, ok ? summary : summary + "; body=" + cli_truncate(res.body)); } } void cli_run_http_smoke() { cli_expect_http("uce_http_smoke:doc index", "/doc/index.uce", 200, ""); // Regression guard: the index enumerates pages via ls("pages/"). When that // returned empty (wasm ls() was a stub), the page still rendered but // listed nothing — so assert the function grid is actually populated. cli_expect_http("uce_http_smoke:doc index lists functions", "/doc/index.uce", 200, "func-item"); cli_expect_http("uce_http_smoke:doc singlepage", "/doc/singlepage.uce", 200, ""); cli_expect_http("uce_http_smoke:doc component page", "/doc/index.uce?p=component", 200, "component()"); cli_expect_http("uce_http_smoke:doc regex page", "/doc/index.uce?p=regex_search", 200, "regex_search"); cli_expect_http("uce_http_smoke:doc xml page", "/doc/index.uce?p=xml_encode", 200, "xml_encode"); cli_expect_http("uce_http_smoke:doc yaml page", "/doc/index.uce?p=yaml_encode", 200, "yaml_encode"); cli_expect_http("uce_http_smoke:doc relative time page", "/doc/index.uce?p=time_format_relative", 200, "time_format_relative"); cli_expect_http("uce_http_smoke:starter home", "/examples/uce-starter/", 200, "Stunning Apps"); cli_expect_http("uce_http_smoke:starter dashboard", "/examples/uce-starter/?dashboard", 200, "Dashboard"); cli_expect_http("uce_http_smoke:starter dashboard ONCE assets reach head", "/examples/uce-starter/?dashboard", 200, "views/dashboard.css"); cli_expect_http("uce_http_smoke:starter workspace nested route", "/examples/uce-starter/?workspace/projects", 200, "Workspace"); cli_expect_http("uce_http_smoke:starter workspace ONCE assets reach head", "/examples/uce-starter/?workspace/projects", 200, "css/workspace.css"); cli_expect_http("uce_http_smoke:starter ajax section", "/examples/uce-starter/?page2-section1", 200, "UCE starter AJAX fragment response"); cli_expect_http("uce_http_smoke:starter route traversal blocked", "/examples/uce-starter/?../../../demo/index", 404, "The requested page does not exist."); // Configurable error page (page_runtime_error): a runtime fault must render the // developer-defined error-page unit with the real error info marshalled across // the membrane, at the error status. Asserts HTTP 500 AND that error["request_uri"] // reached the page (the "mode=trap" query is only shown if error_info crossed). cli_expect_http("uce_http_smoke:configurable error page 500 + error info", "/demo/error-reporting.uce?mode=trap", 500, "mode=trap"); } bool cli_site_body_reports_failure(String lower) { for(String digit : split("1 2 3 4 5 6 7 8 9", " ")) if(cli_contains(lower, String(">failed ") + digit)) return(true); return(false); } void cli_run_site_suite() { DValue manifest; for(String line : split(file_get_contents("manifest.txt"), "\n")) { line = trim(line); if(line == "" || line[0] == '#') continue; StringList parts = split(line, "|"); if(parts.size() < 7 || trim(parts[5]) != "1") continue; String file = trim(parts[0]); String title = trim(parts[1]); String expected = first(trim(parts[4]), title); CliHttpResponse res; String lower; bool ok = false; for(u64 attempt = 0; attempt < 3; attempt++) { if(attempt > 0) usleep(1000000); res = cli_frontend("/tests/" + file); lower = to_lower(res.body); ok = res.status == 200 && cli_contains(res.body, expected); for(String marker : { "compile error", "runtime error", "timed out acquiring compile lock", "near line" }) if(cli_contains(lower, marker)) ok = false; if(cli_contains(lower, "