From 0d385c29a313130a79562ea21596b422d34977f5 Mon Sep 17 00:00:00 2001 From: cpq Date: Fri, 2 Sep 2022 16:23:29 +0100 Subject: [PATCH] More JSON tests --- mongoose.c | 40 ++++++++++++++++------------------------ src/json.c | 37 +++++++++++++++---------------------- test/unit_test.c | 8 ++++++++ 3 files changed, 39 insertions(+), 46 deletions(-) diff --git a/mongoose.c b/mongoose.c index 3bedce5d..d9a50c47 100644 --- a/mongoose.c +++ b/mongoose.c @@ -2494,12 +2494,12 @@ int mg_json_get(struct mg_str json, const char *path, int *toklen) { // In the ascii table, the distance between `[` and `]` is 2. // Ditto for `{` and `}`. Hence +2 in the code below. -#define MG_EOO(x) \ - do { \ - if (depth == ed && (ci != ei || ci < 0)) return MG_JSON_NOT_FOUND; \ - if (c != nesting[depth - 1] + 2) return MG_JSON_INVALID; \ - depth--; \ - MG_CHECKRET(x); \ +#define MG_EOO(x) \ + do { \ + if (depth == ed && ci != ei) return MG_JSON_NOT_FOUND; \ + if (c != nesting[depth - 1] + 2) return MG_JSON_INVALID; \ + depth--; \ + MG_CHECKRET(x); \ } while (0) for (i = 0; i < len; i++) { @@ -2507,14 +2507,11 @@ int mg_json_get(struct mg_str json, const char *path, int *toklen) { if (c == ' ' || c == '\t' || c == '\n' || c == '\r') continue; switch (expecting) { case S_VALUE: - if (depth == ed && ei == ci && c != '[' && path[pos] == '[') { - // Expecting array start, but got something else - return MG_JSON_NOT_FOUND; - } + // p("V %s [%.*s] %d %d %d %d\n", path, pos, path, depth, ed, ci, ei); if (depth == ed) j = i; if (c == '{') { if (depth >= (int) sizeof(nesting)) return MG_JSON_TOO_DEEP; - if (depth == ed && path[pos] == '.' && (ci == ei || ci < 0)) { + if (depth == ed && path[pos] == '.' && ci == ei) { // If we start the object, reset array indices ed++, pos++, ci = ei = -1; } @@ -2534,7 +2531,6 @@ int mg_json_get(struct mg_str json, const char *path, int *toklen) { nesting[depth++] = c; break; } else if (c == ']' && depth > 0) { // Empty array - if (depth == ed) ci = -1; // Array ends. Reset current index MG_EOO(']'); } else if (c == 't' && i + 3 < len && memcmp(&s[i], "true", 4) == 0) { i += 3; @@ -2554,24 +2550,21 @@ int mg_json_get(struct mg_str json, const char *path, int *toklen) { return MG_JSON_INVALID; } MG_CHECKRET('V'); - if (depth == ed && ei >= 0) { - ci++; - if (ci > ei) return MG_JSON_NOT_FOUND; - } + if (depth == ed && ei >= 0) ci++; expecting = S_COMMA_OR_EOO; break; case S_KEY: if (c == '"') { int n = mg_pass_string(&s[i + 1], len - i - 1); - // printf("K1 %s %d %d %d [%.*s]\n", path, pos, n, i, n + 2, s + i); if (n < 0) return n; if (i + 1 + n >= len) return MG_JSON_NOT_FOUND; - // printf("K2 %s [%.*s] %d %d %d\n", path, n, &s[i + 1], n, depth, - // ed); - // NOTE(cpq): in the check sequence below is important. - // strncmp() must go first: it fails fast if the remaining length of - // the path is smaller than `n`. + if (depth < ed) return MG_JSON_NOT_FOUND; + // printf("K %s [%.*s] [%.*s] %d %d %d\n", path, pos, path, n, + // &s[i + 1], n, depth, ed); + // NOTE(cpq): in the check sequence below is important. + // strncmp() must go first: it fails fast if the remaining length of + // the path is smaller than `n`. if (depth == ed && path[pos - 1] == '.' && strncmp(&s[i + 1], &path[pos], (size_t) n) == 0 && (path[pos + n] == '\0' || path[pos + n] == '.' || @@ -2602,7 +2595,6 @@ int mg_json_get(struct mg_str json, const char *path, int *toklen) { } else if (c == ',') { expecting = (nesting[depth - 1] == '{') ? S_KEY : S_VALUE; } else if (c == ']' || c == '}') { - if (depth == ed && ei >= 0) ci--; // Array ends, as ci is pre-added by 1, needs to be decremented before MG_EOO MG_EOO('O'); if (depth == ed && ei >= 0) ci++; } else { @@ -6934,7 +6926,7 @@ static void on_rx(void *buf, size_t len, void *userdata) { void mip_init(struct mg_mgr *mgr, struct mip_cfg *ipcfg, struct mip_driver *driver, void *driver_data) { if (driver->init && !driver->init(ipcfg->mac, driver_data)) { - MG_ERROR(("ERROR intialising driver")); + MG_ERROR(("driver init failed")); } else { size_t maxpktsize = 1500, qlen = driver->setrx ? 1024 * 16 : 0; struct mip_if *ifp = diff --git a/src/json.c b/src/json.c index 85b46b73..eab85750 100644 --- a/src/json.c +++ b/src/json.c @@ -98,12 +98,12 @@ int mg_json_get(struct mg_str json, const char *path, int *toklen) { // In the ascii table, the distance between `[` and `]` is 2. // Ditto for `{` and `}`. Hence +2 in the code below. -#define MG_EOO(x) \ - do { \ - if (depth == ed && (ci != ei || ci < 0)) return MG_JSON_NOT_FOUND; \ - if (c != nesting[depth - 1] + 2) return MG_JSON_INVALID; \ - depth--; \ - MG_CHECKRET(x); \ +#define MG_EOO(x) \ + do { \ + if (depth == ed && ci != ei) return MG_JSON_NOT_FOUND; \ + if (c != nesting[depth - 1] + 2) return MG_JSON_INVALID; \ + depth--; \ + MG_CHECKRET(x); \ } while (0) for (i = 0; i < len; i++) { @@ -111,14 +111,11 @@ int mg_json_get(struct mg_str json, const char *path, int *toklen) { if (c == ' ' || c == '\t' || c == '\n' || c == '\r') continue; switch (expecting) { case S_VALUE: - if (depth == ed && ei == ci && c != '[' && path[pos] == '[') { - // Expecting array start, but got something else - return MG_JSON_NOT_FOUND; - } + // p("V %s [%.*s] %d %d %d %d\n", path, pos, path, depth, ed, ci, ei); if (depth == ed) j = i; if (c == '{') { if (depth >= (int) sizeof(nesting)) return MG_JSON_TOO_DEEP; - if (depth == ed && path[pos] == '.' && (ci == ei || ci < 0)) { + if (depth == ed && path[pos] == '.' && ci == ei) { // If we start the object, reset array indices ed++, pos++, ci = ei = -1; } @@ -138,7 +135,6 @@ int mg_json_get(struct mg_str json, const char *path, int *toklen) { nesting[depth++] = c; break; } else if (c == ']' && depth > 0) { // Empty array - if (depth == ed) ci = -1; // Array ends. Reset current index MG_EOO(']'); } else if (c == 't' && i + 3 < len && memcmp(&s[i], "true", 4) == 0) { i += 3; @@ -158,24 +154,21 @@ int mg_json_get(struct mg_str json, const char *path, int *toklen) { return MG_JSON_INVALID; } MG_CHECKRET('V'); - if (depth == ed && ei >= 0) { - ci++; - if (ci > ei) return MG_JSON_NOT_FOUND; - } + if (depth == ed && ei >= 0) ci++; expecting = S_COMMA_OR_EOO; break; case S_KEY: if (c == '"') { int n = mg_pass_string(&s[i + 1], len - i - 1); - // printf("K1 %s %d %d %d [%.*s]\n", path, pos, n, i, n + 2, s + i); if (n < 0) return n; if (i + 1 + n >= len) return MG_JSON_NOT_FOUND; - // printf("K2 %s [%.*s] %d %d %d\n", path, n, &s[i + 1], n, depth, - // ed); - // NOTE(cpq): in the check sequence below is important. - // strncmp() must go first: it fails fast if the remaining length of - // the path is smaller than `n`. + if (depth < ed) return MG_JSON_NOT_FOUND; + // printf("K %s [%.*s] [%.*s] %d %d %d\n", path, pos, path, n, + // &s[i + 1], n, depth, ed); + // NOTE(cpq): in the check sequence below is important. + // strncmp() must go first: it fails fast if the remaining length of + // the path is smaller than `n`. if (depth == ed && path[pos - 1] == '.' && strncmp(&s[i + 1], &path[pos], (size_t) n) == 0 && (path[pos + n] == '\0' || path[pos + n] == '.' || diff --git a/test/unit_test.c b/test/unit_test.c index ee1eb505..52d70c4c 100644 --- a/test/unit_test.c +++ b/test/unit_test.c @@ -2482,6 +2482,7 @@ static void test_json(void) { ASSERT(mg_json_get_bool(json, "$.b[0]", &b) == false); ASSERT(mg_json_get_bool(json, "$.b[1]", &b) == true); ASSERT(b == true); + ASSERT(mg_json_get(json, "$.b[2]", &len) < 0); json = mg_str("[\"YWJj\", \"0100026869\"]"); ASSERT((str = mg_json_get_b64(json, "$[0]", &len)) != NULL); @@ -2512,6 +2513,13 @@ static void test_json(void) { ASSERT(mg_json_get_long(json, "$.a[0]", -42) == 1); ASSERT(mg_json_get_long(json, "$.a[1]", -42) == -42); + json = mg_str("{\"a\":[1,[2,3], 4]}"); + ASSERT(mg_json_get_long(json, "$.a[0]", -42) == 1); + ASSERT(mg_json_get_long(json, "$.a[1][0]", -42) == 2); + ASSERT(mg_json_get_long(json, "$.a[1][1]", -42) == 3); + ASSERT(mg_json_get_long(json, "$.a[1][2]", -42) == -42); + ASSERT(mg_json_get_long(json, "$.a[2]", -42) == 4); + ASSERT(mg_json_get_long(json, "$.a[3]", -42) == -42); } }