diff --git a/include/mgos_config_util.h b/include/mgos_config_util.h index 88c65231a..f5b9e9d25 100644 --- a/include/mgos_config_util.h +++ b/include/mgos_config_util.h @@ -84,7 +84,7 @@ struct mgos_config; * checking keys against `acl`. */ bool mgos_conf_parse(const struct mg_str json, const char *acl, - const struct mgos_conf_entry *schema, void *cfg); + struct mgos_config *cfg); /* * Identical to `mgos_conf_parse()` but allows the caller to get an error @@ -94,8 +94,7 @@ bool mgos_conf_parse(const struct mg_str json, const char *acl, * is owned by the caller and has to be free()d. */ bool mgos_conf_parse_msg(const struct mg_str json, const char *acl, - const struct mgos_conf_entry *schema, void *cfg, - char **msg); + struct mgos_config *cfg, char **msg); /* * Parse a sub-section of the config. @@ -107,6 +106,10 @@ bool mgos_conf_parse_sub_f(const char *fname, const struct mgos_conf_entry *sub_schema, const void *cfg); +bool mgos_conf_parse_sub_msg(const struct mg_str json, + const struct mgos_conf_entry *sub_schema, + const char *acl, void *cfg, char **msg); + /* * Callback for `mgos_conf_emit_cb` (see below); `data` is the emitted data and * `param` is user-defined param given to `mgos_conf_emit_cb`. diff --git a/src/mgos_config_util.c b/src/mgos_config_util.c index f16830377..f6d8eceae 100644 --- a/src/mgos_config_util.c +++ b/src/mgos_config_util.c @@ -55,11 +55,11 @@ bool mgos_conf_check_access_n(const struct mg_str key, struct mg_str acl) { struct parse_ctx { const struct mgos_conf_entry *schema; - const char *acl; + char *acl; void *cfg; - bool result; int offset_adj; char **msg; + bool result; }; const struct mgos_conf_entry *mgos_conf_find_schema_entry_s( @@ -92,27 +92,24 @@ void mgos_conf_parse_cb(void *data, const char *name, size_t name_len, const char *path, const struct json_token *tok) { struct parse_ctx *ctx = (struct parse_ctx *) data; char *endptr = NULL; - - (void) name; - (void) name_len; - - if (!ctx->result) return; - if (path[0] != '.') { - if (path[0] == '\0') return; /* Last entry, the entire object */ - mg_asprintf(ctx->msg, 0, "Not an object"); - ctx->result = false; + if (tok->type == JSON_TYPE_OBJECT_START || + tok->type == JSON_TYPE_OBJECT_END) { return; } - path++; - const struct mgos_conf_entry *e = - mgos_conf_find_schema_entry(path, ctx->schema); - if (e == NULL) { - LOG(LL_DEBUG, ("Unknown key [%s]", path)); - return; + if (!ctx->result) return; + const struct mgos_conf_entry *e; + if (path[0] == '.') { + path++; + e = mgos_conf_find_schema_entry(path, ctx->schema); + if (e == NULL) { + LOG(LL_DEBUG, ("Unknown key [%s]", path)); + return; + } + } else { + e = ctx->schema; } #ifndef MGOS_BOOT_BUILD - if (e->type != CONF_TYPE_OBJECT && - !mgos_conf_check_access(mg_mk_str(path), ctx->acl)) { + if (!mgos_conf_check_access(mg_mk_str(path), ctx->acl)) { LOG(LL_ERROR, ("Not allowed to set [%s]", path)); return; } @@ -208,6 +205,8 @@ void mgos_conf_parse_cb(void *data, const char *name, size_t name_len, } } LOG(LL_DEBUG, ("Set [%s] = [%.*s]", path, (int) tok->len, tok->ptr)); + (void) name_len; + (void) name; } static bool mgos_conf_parse_off(const struct mg_str json, const char *acl, @@ -215,33 +214,35 @@ static bool mgos_conf_parse_off(const struct mg_str json, const char *acl, int offset_adj, void *cfg, char **msg) { char *err_msg = NULL; struct parse_ctx ctx = {.schema = schema, - .acl = acl, .cfg = cfg, .result = true, .offset_adj = offset_adj, .msg = msg}; - if (!msg) { - ctx.msg = &err_msg; - } + if (msg == NULL) ctx.msg = &err_msg; + /* Make a temporary copy, in case it gets overridden while loading. */ + if (acl != NULL) ctx.acl = strdup(acl); int ret = json_walk(json.p, json.len, mgos_conf_parse_cb, &ctx); - if (*ctx.msg) { + if ((!ctx.result || ret <= 0) && *ctx.msg == NULL) { + mg_asprintf(ctx.msg, 0, "Invalid JSON"); + } + if (*ctx.msg != NULL) { LOG(LL_ERROR, ("%s", *ctx.msg)); if (ctx.msg == &err_msg) { - free((void *) err_msg); + free(err_msg); } } - return ret > 0 && ctx.result == true; + free(ctx.acl); + return (ret > 0 && ctx.result == true); } bool mgos_conf_parse(const struct mg_str json, const char *acl, - const struct mgos_conf_entry *schema, void *cfg) { - return mgos_conf_parse_off(json, acl, schema, 0, cfg, NULL); + struct mgos_config *cfg) { + return mgos_conf_parse_off(json, acl, mgos_config_schema(), 0, cfg, NULL); } bool mgos_conf_parse_msg(const struct mg_str json, const char *acl, - const struct mgos_conf_entry *schema, void *cfg, - char **msg) { - return mgos_conf_parse_off(json, acl, schema, 0, cfg, msg); + struct mgos_config *cfg, char **msg) { + return mgos_conf_parse_off(json, acl, mgos_config_schema(), 0, cfg, msg); } bool mgos_conf_parse_sub(const struct mg_str json, @@ -250,6 +251,13 @@ bool mgos_conf_parse_sub(const struct mg_str json, NULL); } +bool mgos_conf_parse_sub_msg(const struct mg_str json, + const struct mgos_conf_entry *sub_schema, + const char *acl, void *sub_cfg, char **msg) { + return mgos_conf_parse_off(json, acl, sub_schema, sub_schema->offset, sub_cfg, + msg); +} + struct emit_ctx { const void *cfg; const void *base; @@ -696,7 +704,7 @@ bool mgos_config_set(const struct mg_str key, const struct mg_str value, break; } case CONF_TYPE_OBJECT: { - ret = mgos_conf_parse(value, "*", e, cfg); + ret = mgos_conf_parse_sub(value, e, cfg); break; } } diff --git a/src/mgos_sys_config.c b/src/mgos_sys_config.c index d40312b09..1bbee23f0 100644 --- a/src/mgos_sys_config.c +++ b/src/mgos_sys_config.c @@ -95,13 +95,10 @@ static bool load_config(const char *name, struct mg_str cfg_data, const char *acl, const struct mgos_conf_entry *schema, void *cfg) { bool result = true; - /* Make a temporary copy, in case it gets overridden while loading. */ - char *acl_copy = (acl != NULL ? strdup(acl) : NULL); - if (!mgos_conf_parse(cfg_data, acl_copy, schema, cfg)) { + if (!mgos_conf_parse_sub_msg(cfg_data, schema, acl, cfg, NULL)) { LOG(LL_ERROR, ("Failed to parse %s", name)); result = false; } - free(acl_copy); (void) name; return result; } @@ -498,13 +495,8 @@ void mgos_sys_config_register_validator(mgos_config_validator_fn fn) { } bool mgos_config_apply_s(const struct mg_str json, bool save) { - /* Make a temporary copy, in case it gets overridden while loading. */ - char *acl_copy = (mgos_sys_config_get_conf_acl() != NULL - ? strdup(mgos_sys_config_get_conf_acl()) - : NULL); bool res = - mgos_conf_parse(json, acl_copy, mgos_config_schema(), &mgos_sys_config); - free(acl_copy); + mgos_conf_parse(json, mgos_sys_config_get_conf_acl(), &mgos_sys_config); if (save) save_cfg(&mgos_sys_config, NULL); return res; } diff --git a/src/test/data/golden/mgos_config.c b/src/test/data/golden/mgos_config.c index 7d037b891..f9c4f64e1 100644 --- a/src/test/data/golden/mgos_config.c +++ b/src/test/data/golden/mgos_config.c @@ -15,12 +15,13 @@ /* struct mgos_config */ static const struct mgos_conf_entry mgos_config_schema_[] = { - {.type = CONF_TYPE_OBJECT, .key = "", .offset = 0, .num_desc = 42}, - {.type = CONF_TYPE_OBJECT, .key = "wifi", .offset = offsetof(struct mgos_config, wifi), .num_desc = 8}, + {.type = CONF_TYPE_OBJECT, .key = "", .offset = 0, .num_desc = 43}, + {.type = CONF_TYPE_OBJECT, .key = "wifi", .offset = offsetof(struct mgos_config, wifi), .num_desc = 9}, {.type = CONF_TYPE_OBJECT, .key = "sta", .offset = offsetof(struct mgos_config, wifi.sta), .num_desc = 2}, {.type = CONF_TYPE_STRING, .key = "ssid", .offset = offsetof(struct mgos_config, wifi.sta.ssid)}, {.type = CONF_TYPE_STRING, .key = "pass", .offset = offsetof(struct mgos_config, wifi.sta.pass)}, - {.type = CONF_TYPE_OBJECT, .key = "ap", .offset = offsetof(struct mgos_config, wifi.ap), .num_desc = 4}, + {.type = CONF_TYPE_OBJECT, .key = "ap", .offset = offsetof(struct mgos_config, wifi.ap), .num_desc = 5}, + {.type = CONF_TYPE_BOOL, .key = "enable", .offset = offsetof(struct mgos_config, wifi.ap.enable)}, {.type = CONF_TYPE_STRING, .key = "ssid", .offset = offsetof(struct mgos_config, wifi.ap.ssid)}, {.type = CONF_TYPE_STRING, .key = "pass", .offset = offsetof(struct mgos_config, wifi.ap.pass)}, {.type = CONF_TYPE_INT, .key = "channel", .offset = offsetof(struct mgos_config, wifi.ap.channel)}, @@ -93,6 +94,7 @@ const struct mgos_conf_entry *mgos_config_wifi_ap_get_schema(void) { } void mgos_config_wifi_ap_set_defaults(struct mgos_config_wifi_ap *cfg) { + cfg->enable = false; cfg->ssid = "Quote \" me \\\\ please"; cfg->pass = "\u043c\u0430\u043b\u043e\u0432\u0430\u0442\u043e \u0431\u0443\u0434\u0435\u0442"; cfg->channel = 6; @@ -127,7 +129,7 @@ bool mgos_config_wifi_parse_f(const char *fname, struct mgos_config_wifi *cfg) { /* struct mgos_config_http */ const struct mgos_conf_entry *mgos_config_http_get_schema(void) { - return &mgos_config_schema_[11]; + return &mgos_config_schema_[12]; } void mgos_config_http_set_defaults(struct mgos_config_http *cfg) { @@ -145,7 +147,7 @@ bool mgos_config_http_parse_f(const char *fname, struct mgos_config_http *cfg) { /* struct mgos_config_debug_empty */ const struct mgos_conf_entry *mgos_config_debug_empty_get_schema(void) { - return &mgos_config_schema_[25]; + return &mgos_config_schema_[26]; } void mgos_config_debug_empty_set_defaults(struct mgos_config_debug_empty *cfg) { @@ -162,7 +164,7 @@ bool mgos_config_debug_empty_parse_f(const char *fname, struct mgos_config_debug /* struct mgos_config_debug */ const struct mgos_conf_entry *mgos_config_debug_get_schema(void) { - return &mgos_config_schema_[14]; + return &mgos_config_schema_[15]; } void mgos_config_debug_set_defaults(struct mgos_config_debug *cfg) { @@ -189,7 +191,7 @@ bool mgos_config_debug_parse_f(const char *fname, struct mgos_config_debug *cfg) /* struct mgos_config_baz */ const struct mgos_conf_entry *mgos_config_baz_get_schema(void) { - return &mgos_config_schema_[41]; + return &mgos_config_schema_[42]; } void mgos_config_baz_set_defaults(struct mgos_config_baz *cfg) { @@ -206,7 +208,7 @@ bool mgos_config_baz_parse_f(const char *fname, struct mgos_config_baz *cfg) { /* struct mgos_config_bar_inner */ const struct mgos_conf_entry *mgos_config_bar_inner_get_schema(void) { - return &mgos_config_schema_[38]; + return &mgos_config_schema_[39]; } void mgos_config_bar_inner_set_defaults(struct mgos_config_bar_inner *cfg) { @@ -224,7 +226,7 @@ bool mgos_config_bar_inner_parse_f(const char *fname, struct mgos_config_bar_inn /* struct mgos_config_baz */ const struct mgos_conf_entry *mgos_config_bar_baz_get_schema(void) { - return &mgos_config_schema_[41]; + return &mgos_config_schema_[42]; } void mgos_config_bar_baz_set_defaults(struct mgos_config_baz *cfg) { @@ -241,7 +243,7 @@ bool mgos_config_bar_baz_parse_f(const char *fname, struct mgos_config_baz *cfg) /* struct mgos_config_bar */ const struct mgos_conf_entry *mgos_config_bar_get_schema(void) { - return &mgos_config_schema_[35]; + return &mgos_config_schema_[36]; } void mgos_config_bar_set_defaults(struct mgos_config_bar *cfg) { @@ -261,7 +263,7 @@ bool mgos_config_bar_parse_f(const char *fname, struct mgos_config_bar *cfg) { /* struct mgos_config_bar_inner */ const struct mgos_conf_entry *mgos_config_test_bar1_inner_get_schema(void) { - return &mgos_config_schema_[38]; + return &mgos_config_schema_[39]; } void mgos_config_test_bar1_inner_set_defaults(struct mgos_config_bar_inner *cfg) { @@ -279,7 +281,7 @@ bool mgos_config_test_bar1_inner_parse_f(const char *fname, struct mgos_config_b /* struct mgos_config_baz */ const struct mgos_conf_entry *mgos_config_test_bar1_baz_get_schema(void) { - return &mgos_config_schema_[41]; + return &mgos_config_schema_[42]; } void mgos_config_test_bar1_baz_set_defaults(struct mgos_config_baz *cfg) { @@ -296,7 +298,7 @@ bool mgos_config_test_bar1_baz_parse_f(const char *fname, struct mgos_config_baz /* struct mgos_config_bar */ const struct mgos_conf_entry *mgos_config_test_bar1_get_schema(void) { - return &mgos_config_schema_[35]; + return &mgos_config_schema_[36]; } void mgos_config_test_bar1_set_defaults(struct mgos_config_bar *cfg) { @@ -316,7 +318,7 @@ bool mgos_config_test_bar1_parse_f(const char *fname, struct mgos_config_bar *cf /* struct mgos_config_bar_inner */ const struct mgos_conf_entry *mgos_config_test_bar2_inner_get_schema(void) { - return &mgos_config_schema_[38]; + return &mgos_config_schema_[39]; } void mgos_config_test_bar2_inner_set_defaults(struct mgos_config_bar_inner *cfg) { @@ -334,7 +336,7 @@ bool mgos_config_test_bar2_inner_parse_f(const char *fname, struct mgos_config_b /* struct mgos_config_baz */ const struct mgos_conf_entry *mgos_config_test_bar2_baz_get_schema(void) { - return &mgos_config_schema_[41]; + return &mgos_config_schema_[42]; } void mgos_config_test_bar2_baz_set_defaults(struct mgos_config_baz *cfg) { @@ -351,7 +353,7 @@ bool mgos_config_test_bar2_baz_parse_f(const char *fname, struct mgos_config_baz /* struct mgos_config_bar */ const struct mgos_conf_entry *mgos_config_test_bar2_get_schema(void) { - return &mgos_config_schema_[35]; + return &mgos_config_schema_[36]; } void mgos_config_test_bar2_set_defaults(struct mgos_config_bar *cfg) { @@ -371,7 +373,7 @@ bool mgos_config_test_bar2_parse_f(const char *fname, struct mgos_config_bar *cf /* struct mgos_config_test */ const struct mgos_conf_entry *mgos_config_test_get_schema(void) { - return &mgos_config_schema_[26]; + return &mgos_config_schema_[27]; } void mgos_config_test_set_defaults(struct mgos_config_test *cfg) { @@ -468,6 +470,11 @@ void mgos_config_set_wifi_sta_pass(struct mgos_config *cfg, const char * v) { mg /* wifi.ap */ const struct mgos_config_wifi_ap *mgos_config_get_wifi_ap(const struct mgos_config *cfg) { return &cfg->wifi.ap; } +/* wifi.ap.enable */ +int mgos_config_get_wifi_ap_enable(const struct mgos_config *cfg) { return cfg->wifi.ap.enable; } +int mgos_config_get_default_wifi_ap_enable(void) { return false; } +void mgos_config_set_wifi_ap_enable(struct mgos_config *cfg, int v) { cfg->wifi.ap.enable = v; } + /* wifi.ap.ssid */ const char * mgos_config_get_wifi_ap_ssid(const struct mgos_config *cfg) { return cfg->wifi.ap.ssid; } const char * mgos_config_get_default_wifi_ap_ssid(void) { return "Quote \" me \\\\ please"; } diff --git a/src/test/data/golden/mgos_config.h b/src/test/data/golden/mgos_config.h index bd96e3969..53f2b2610 100644 --- a/src/test/data/golden/mgos_config.h +++ b/src/test/data/golden/mgos_config.h @@ -44,6 +44,7 @@ static inline void mgos_config_wifi_sta_free(struct mgos_config_wifi_sta *cfg) { /* wifi.ap type struct mgos_config_wifi_ap */ struct mgos_config_wifi_ap { + int enable; const char * ssid; const char * pass; int channel; @@ -542,6 +543,16 @@ static inline void mgos_sys_config_set_wifi_sta_pass(const char * v) { mgos_conf const struct mgos_config_wifi_ap *mgos_config_get_wifi_ap(const struct mgos_config *cfg); static inline const struct mgos_config_wifi_ap *mgos_sys_config_get_wifi_ap(void) { return mgos_config_get_wifi_ap(&mgos_sys_config); } +/* wifi.ap.enable */ +#define MGOS_CONFIG_HAVE_WIFI_AP_ENABLE +#define MGOS_SYS_CONFIG_HAVE_WIFI_AP_ENABLE +int mgos_config_get_wifi_ap_enable(const struct mgos_config *cfg); +int mgos_config_get_default_wifi_ap_enable(void); +static inline int mgos_sys_config_get_wifi_ap_enable(void) { return mgos_config_get_wifi_ap_enable(&mgos_sys_config); } +static inline int mgos_sys_config_get_default_wifi_ap_enable(void) { return mgos_config_get_default_wifi_ap_enable(); } +void mgos_config_set_wifi_ap_enable(struct mgos_config *cfg, int v); +static inline void mgos_sys_config_set_wifi_ap_enable(int v) { mgos_config_set_wifi_ap_enable(&mgos_sys_config, v); } + /* wifi.ap.ssid */ #define MGOS_CONFIG_HAVE_WIFI_AP_SSID #define MGOS_SYS_CONFIG_HAVE_WIFI_AP_SSID diff --git a/src/test/data/golden/mgos_config.json b/src/test/data/golden/mgos_config.json index 3cf8367e9..db5c7670c 100644 --- a/src/test/data/golden/mgos_config.json +++ b/src/test/data/golden/mgos_config.json @@ -1 +1 @@ -{"wifi":{"sta":{"ssid":"cookadoodadoo","pass":"try less cork"},"ap":{"ssid":"Quote \" me \\\\ please","pass":"","channel":6,"dhcp_end":"192.168.4.200"}},"foo":123,"http":{"enable":false,"port":80},"debug":{"level":1,"dest":"uart1","file_level":"mgos_bar=1","test_d1":2.000000,"test_d2":111.000000,"test_d3":0.000100,"test_f1":0.123000,"test_f2":11.500000,"test_f3":0.000010,"test_ui":4294967295,"empty":{}},"test":{"bar1":{"enable":false,"param1":1111,"inner":{"param2":"p2","param3":3333},"baz":{"bazaar":false}},"bar2":{"enable":false,"param1":2222,"inner":{"param2":"p2","param3":3333},"baz":{"bazaar":true}}}} \ No newline at end of file +{"wifi":{"sta":{"ssid":"cookadoodadoo","pass":"try less cork"},"ap":{"enable":false,"ssid":"Quote \" me \\\\ please","pass":"","channel":6,"dhcp_end":"192.168.4.200"}},"foo":123,"http":{"enable":false,"port":80},"debug":{"level":1,"dest":"uart1","file_level":"mgos_bar=1","test_d1":2.000000,"test_d2":111.000000,"test_d3":0.000100,"test_f1":0.123000,"test_f2":11.500000,"test_f3":0.000010,"test_ui":4294967295,"empty":{}},"test":{"bar1":{"enable":false,"param1":1111,"inner":{"param2":"p2","param3":3333},"baz":{"bazaar":false}},"bar2":{"enable":false,"param1":2222,"inner":{"param2":"p2","param3":3333},"baz":{"bazaar":true}}}} \ No newline at end of file diff --git a/src/test/data/golden/mgos_config_pretty.json b/src/test/data/golden/mgos_config_pretty.json index 039aa8c4d..50f459b51 100644 --- a/src/test/data/golden/mgos_config_pretty.json +++ b/src/test/data/golden/mgos_config_pretty.json @@ -5,6 +5,7 @@ "pass": "try less cork" }, "ap": { + "enable": false, "ssid": "Quote \" me \\\\ please", "pass": "", "channel": 6, diff --git a/src/test/data/golden/mgos_config_schema.json b/src/test/data/golden/mgos_config_schema.json index 3a5100f81..d9fb91024 100644 --- a/src/test/data/golden/mgos_config_schema.json +++ b/src/test/data/golden/mgos_config_schema.json @@ -4,6 +4,7 @@ ["wifi.sta.ssid", "s", {"title": "SSID"}], ["wifi.sta.pass", "s", {"title": "Password", "type": "password"}], ["wifi.ap", "o", {"title": "WiFi Access Point"}], + ["wifi.ap.enable", "b", {"title": "Enable"}], ["wifi.ap.ssid", "s", {"title": "SSID"}], ["wifi.ap.pass", "s", {"title": "Password", "type": "password"}], ["wifi.ap.channel", "i", {"title": "Channel"}], diff --git a/src/test/data/sys_conf_wifi.yaml b/src/test/data/sys_conf_wifi.yaml index 25f30f83d..31a24c270 100644 --- a/src/test/data/sys_conf_wifi.yaml +++ b/src/test/data/sys_conf_wifi.yaml @@ -12,6 +12,7 @@ - {title: "Password", type: "password"} - ["wifi.ap", "o", {title: "WiFi Access Point"}] +- ["wifi.ap.enable", "b", false, {title: "Enable"}] - ["wifi.ap.ssid", "s", 'Quote " me \\ please', {title: "SSID"}] - ["wifi.ap.pass", "s", "маловато будет", {title: "Password", type: "password"}] - ["wifi.ap.channel", "i", 6, {title: "Channel"}] diff --git a/src/test/unit_test.c b/src/test/unit_test.c index 721c3e1e4..ed9bd91f5 100644 --- a/src/test/unit_test.c +++ b/src/test/unit_test.c @@ -19,7 +19,6 @@ static const char *test_config(void) { size_t size; char *json2 = cs_read_file("data/overrides.json", &size); - const struct mgos_conf_entry *schema = mgos_config_schema(); struct mgos_config conf; struct mgos_config_debug conf_debug; @@ -38,7 +37,7 @@ static const char *test_config(void) { ASSERT_STREQ(conf.wifi.ap.dhcp_end, "192.168.4.200"); /* Apply overrides */ - ASSERT_EQ(mgos_conf_parse(mg_mk_str(json2), "*", schema, &conf), true); + ASSERT_EQ(mgos_conf_parse(mg_mk_str(json2), "*", &conf), true); ASSERT_STREQ(conf.wifi.sta.ssid, "cookadoodadoo"); /* Set string */ ASSERT_STREQ(conf.wifi.sta.pass, "try less cork"); ASSERT_EQ(conf.debug.level, 1); /* Override integer */ @@ -94,9 +93,9 @@ static const char *test_config(void) { } { // Test parsing of a sub-struct. + struct mg_str json = MG_MK_STR("{\"ssid\": \"test\", \"channel\": 9}"); struct mgos_config_wifi_ap wifi_ap; - ASSERT(mgos_config_wifi_ap_parse( - mg_mk_str("{\"ssid\": \"test\", \"channel\": 9}"), &wifi_ap)); + ASSERT(mgos_config_wifi_ap_parse(json, &wifi_ap)); ASSERT_STREQ(wifi_ap.ssid, "test"); ASSERT_EQ(wifi_ap.channel, 9); ASSERT_STREQ(wifi_ap.dhcp_end, "192.168.4.200"); // Default value. @@ -104,6 +103,33 @@ static const char *test_config(void) { conf.wifi.ap.dhcp_end); // Shared const pointer. mgos_config_wifi_ap_free(&wifi_ap); } + { // Test parsing of a single field. + const struct mgos_conf_entry *ap_sch = + mgos_conf_find_schema_entry("wifi.ap", mgos_config_schema()); + ASSERT_PTREQ(ap_sch, mgos_config_wifi_ap_get_schema()); + struct mg_str json = MG_MK_STR("{\"ssid\": \"test\", \"channel\": 9}"); + struct mgos_config_wifi_ap wifi_ap = {0}; + ASSERT(mgos_conf_parse_sub(json, ap_sch, &wifi_ap)); + ASSERT_STREQ(wifi_ap.ssid, "test"); + ASSERT_EQ(wifi_ap.channel, 9); + ASSERT_PTREQ(wifi_ap.dhcp_end, NULL); // Default values not set. + ASSERT(mgos_conf_parse_sub( + mg_mk_str("\"x\""), + mgos_conf_find_schema_entry("wifi.ap.pass", mgos_config_schema()), + &wifi_ap.pass)); + ASSERT(mgos_conf_parse_sub( + mg_mk_str("123"), + mgos_conf_find_schema_entry("wifi.ap.channel", mgos_config_schema()), + &wifi_ap.channel)); + ASSERT(mgos_conf_parse_sub( + mg_mk_str("true"), + mgos_conf_find_schema_entry("wifi.ap.enable", mgos_config_schema()), + &wifi_ap.enable)); + ASSERT_STREQ(wifi_ap.pass, "x"); + ASSERT_EQ(wifi_ap.channel, 123); + ASSERT(wifi_ap.enable); + mgos_config_wifi_ap_free(&wifi_ap); + } mgos_config_free(&conf);