From a8fd3825f3282f7e48f2d76b3e43825a4b996581 Mon Sep 17 00:00:00 2001 From: cpq Date: Tue, 19 May 2026 12:29:08 +0100 Subject: [PATCH] Add dash unit test --- mongoose.c | 13 ++++--- mongoose.h | 1 + src/dash.c | 13 ++++--- test/unit_test.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 111 insertions(+), 10 deletions(-) diff --git a/mongoose.c b/mongoose.c index 297ad03e..32e16615 100644 --- a/mongoose.c +++ b/mongoose.c @@ -288,18 +288,21 @@ static int mg_dash_parse_field(struct mg_str json, struct mg_field *f) { bool ok = false; mg_snprintf(json_path, sizeof(json_path), "$.%s", f->name); if (f->type == MG_VAL_BOOL) { - ok = mg_json_get_bool(json, json_path, (bool *) f->value); + ok = f->value_size == sizeof(bool) && + mg_json_get_bool(json, json_path, (bool *) f->value); } else if (f->type == MG_VAL_INT) { double d; - if (mg_json_get_num(json, json_path, &d) && d == (int) d) { + if (f->value_size == sizeof(int) && mg_json_get_num(json, json_path, &d) && + d == (int) d) { *(int *) f->value = (int) d; ok = true; } } else if (f->type == MG_VAL_DBL) { - ok = mg_json_get_num(json, json_path, (double *) f->value); - } else if (f->type == MG_VAL_STR) { + ok = f->value_size == sizeof(double) && + mg_json_get_num(json, json_path, (double *) f->value); + } else if (f->type == MG_VAL_STR && f->value_size > 0) { ok = mg_json_unescape(json, json_path, (char *) f->value, f->value_size); - } else if (f->type == MG_VAL_RAW) { + } else if (f->type == MG_VAL_RAW && f->value_size > 0) { ok = mg_snprintf((char *) f->value, f->value_size, "%.*s", json.len, json.buf) == json.len; } diff --git a/mongoose.h b/mongoose.h index aedd407b..d0b5cd3a 100644 --- a/mongoose.h +++ b/mongoose.h @@ -1112,6 +1112,7 @@ struct timeval { + // Macros to record timestamped events that happens with a connection. // They are saved into a c->prof IO buffer, each event is a name and a 32-bit // timestamp in milliseconds since connection init time. diff --git a/src/dash.c b/src/dash.c index b607c583..7538a717 100644 --- a/src/dash.c +++ b/src/dash.c @@ -167,18 +167,21 @@ static int mg_dash_parse_field(struct mg_str json, struct mg_field *f) { bool ok = false; mg_snprintf(json_path, sizeof(json_path), "$.%s", f->name); if (f->type == MG_VAL_BOOL) { - ok = mg_json_get_bool(json, json_path, (bool *) f->value); + ok = f->value_size == sizeof(bool) && + mg_json_get_bool(json, json_path, (bool *) f->value); } else if (f->type == MG_VAL_INT) { double d; - if (mg_json_get_num(json, json_path, &d) && d == (int) d) { + if (f->value_size == sizeof(int) && mg_json_get_num(json, json_path, &d) && + d == (int) d) { *(int *) f->value = (int) d; ok = true; } } else if (f->type == MG_VAL_DBL) { - ok = mg_json_get_num(json, json_path, (double *) f->value); - } else if (f->type == MG_VAL_STR) { + ok = f->value_size == sizeof(double) && + mg_json_get_num(json, json_path, (double *) f->value); + } else if (f->type == MG_VAL_STR && f->value_size > 0) { ok = mg_json_unescape(json, json_path, (char *) f->value, f->value_size); - } else if (f->type == MG_VAL_RAW) { + } else if (f->type == MG_VAL_RAW && f->value_size > 0) { ok = mg_snprintf((char *) f->value, f->value_size, "%.*s", json.len, json.buf) == json.len; } diff --git a/test/unit_test.c b/test/unit_test.c index 22a08677..b44dbfcf 100644 --- a/test/unit_test.c +++ b/test/unit_test.c @@ -4130,6 +4130,96 @@ static void test_crypto(void) { test_rsa(); } +static void dash_custom(struct mg_connection *c, int ev, void *ev_data) { + (void) c, (void) ev, (void) ev_data; +} + +char three[10] = "hi"; +int one = 1; +static void rfields1(void) { + mg_snprintf(three, sizeof(three), "t: %d", one); // Simulate array +} + +static void test_dash(void) { + char buf[FETCH_BUF_SIZE]; + const char *url = "http://localhost:26352"; + struct mg_mgr mgr; + struct mg_dash dash = {0}; + bool two = false; + struct mg_field fields1[] = { + {"one", MG_VAL_INT, &one, sizeof(one)}, + {"three", MG_VAL_STR, three, sizeof(three)}, + {NULL, MG_VAL_INT, NULL, 0}, + }; + struct mg_field fields2[] = { + {"two", MG_VAL_BOOL, &two, 0}, // Size set to 0 - readonly + {NULL, MG_VAL_INT, NULL, 0}, + }; + struct mg_field_set set1 = {"set1", fields1, rfields1, NULL, 0, 0, NULL}; + struct mg_field_set set2 = {"set2", fields2, NULL, NULL, 0, 0, NULL}; + char marker = 0; + + MG_DASH_ADD_FIELD_SET(&dash, &set1); + ASSERT(dash.sets == &set1); + ASSERT(set1.next == NULL); + + MG_DASH_ADD_FIELD_SET(&dash, &set2); + ASSERT(dash.sets == &set2); + ASSERT(set2.next == &set1); + + MG_DASH_REGISTER_CUSTOM_HANDLER(&dash, "/api/custom", dash_custom, &marker); + ASSERT(dash.custom_handlers != NULL); + ASSERT(mg_strcmp(dash.custom_handlers->uri_pattern, mg_str("/api/custom")) == + 0); + ASSERT(dash.custom_handlers->handler == dash_custom); + ASSERT(dash.custom_handlers->handler_data == &marker); + + while (mg_dash_files != NULL) mg_dash_file_del(mg_str(mg_dash_files->name)); + mg_dash_file_add(mg_str("one.txt"), 123); + ASSERT(mg_dash_files != NULL); + ASSERT(strcmp(mg_dash_files->name, "one.txt") == 0); + ASSERT(mg_dash_files->size == 123); + mg_dash_file_add(mg_str("two.bin"), 456); + ASSERT(mg_dash_files != NULL); + ASSERT(strcmp(mg_dash_files->name, "two.bin") == 0); + ASSERT(mg_dash_files->size == 456); + ASSERT(mg_dash_files->next != NULL); + ASSERT(strcmp(mg_dash_files->next->name, "one.txt") == 0); + mg_dash_file_del(mg_str("one.txt")); + ASSERT(mg_dash_files != NULL); + ASSERT(strcmp(mg_dash_files->name, "two.bin") == 0); + ASSERT(mg_dash_files->next == NULL); + mg_dash_file_del(mg_str("missing.txt")); + ASSERT(mg_dash_files != NULL); + mg_dash_file_del(mg_str("two.bin")); + ASSERT(mg_dash_files == NULL); + + mg_mgr_init(&mgr); + mg_mem_files = mg_packed_files; + ASSERT(mg_http_listen(&mgr, url, mg_dash_ev_handler, &dash) != NULL); + + ASSERT(fetch(&mgr, buf, url, "GET /api/get HTTP/1.0\n\n") == 200); + ASSERT(cmpbody(buf, + "{\"files\":{\"data\":[]},\"set2\":{\"two\":false}," + "\"set1\":{\"one\":1,\"three\":\"t: 1\"}}\n") == 0); + + ASSERT(fetch(&mgr, buf, url, + "POST /api/set HTTP/1.0\nContent-Length: 18\n\n" + "{\"set1\":{\"one\":2}}") == 200); + ASSERT(cmpbody(buf, "1\n") == 0); + ASSERT(fetch(&mgr, buf, url, "GET /api/get/set1 HTTP/1.0\n\n") == 200); + ASSERT(cmpbody(buf, "{\"one\":2,\"three\":\"t: 2\"}\n") == 0); + + ASSERT(fetch(&mgr, buf, url, + "POST /api/set HTTP/1.0\nContent-Length: 21\n\n" + "{\"set2\":{\"two\":true}}") == 200); + ASSERT(cmpbody(buf, "0\n") == 0); + ASSERT(two == false); + ASSERT(fetch(&mgr, buf, url, "GET /api/get/set2 HTTP/1.0\n\n") == 200); + ASSERT(cmpbody(buf, "{\"two\":false}\n") == 0); + mg_mgr_free(&mgr); +} + #define DASHBOARD(x) \ printf("HEALTH_DASHBOARD\t\"%s\": %s,\n", x, s_error ? "false" : "true"); @@ -4505,6 +4595,10 @@ int main(void) { test_rpc(); DASHBOARD("rpc"); + s_error = false; + test_dash(); + DASHBOARD("dash"); + s_error = false; test_check_ip_acl(); DASHBOARD("ip_acl");