diff --git a/common.c b/common.c index da937a1..cf950c8 100644 --- a/common.c +++ b/common.c @@ -2074,6 +2074,7 @@ static void config_load (struct config *self, struct config_item *root) { hard_assert (root->type == CONFIG_ITEM_OBJECT); + if (self->root) config_item_destroy (self->root); self->root = root; struct str_map_iter iter; diff --git a/degesch.c b/degesch.c index 96d0dc1..f2a23c9 100644 --- a/degesch.c +++ b/degesch.c @@ -2017,7 +2017,7 @@ error: } static void -serialize_configuration (struct app_context *ctx, struct str *output) +serialize_configuration (struct config_item *root, struct str *output) { str_append (output, "# " PROGRAM_NAME " " PROGRAM_VERSION " configuration file\n" @@ -2028,7 +2028,7 @@ serialize_configuration (struct app_context *ctx, struct str *output) "# Everything is in UTF-8. Any custom comments will be overwritten.\n" "\n"); - config_item_write (ctx->config.root, true, output); + config_item_write (root, true, output); } // --- Terminal output --------------------------------------------------------- @@ -7110,9 +7110,9 @@ str_vector_sort (struct str_vector *self) static void dump_matching_options - (struct app_context *ctx, const char *mask, struct str_vector *output) + (struct config_item *root, const char *mask, struct str_vector *output) { - config_dump (ctx->config.root, output); + config_dump (root, output); str_vector_sort (output); // Filter out results by wildcard matching @@ -7133,7 +7133,7 @@ save_configuration (struct app_context *ctx) { struct str data; str_init (&data); - serialize_configuration (ctx, &data); + serialize_configuration (ctx->config.root, &data); struct error *e = NULL; char *filename = write_configuration_file (&data, &e); @@ -8379,7 +8379,7 @@ handle_command_set_assign_item (struct app_context *ctx, { struct str_vector tmp; str_vector_init (&tmp); - dump_matching_options (ctx, key, &tmp); + dump_matching_options (ctx->config.root, key, &tmp); log_global_status (ctx, "Option changed: #s", tmp.vector[0]); str_vector_free (&tmp); } @@ -8436,7 +8436,7 @@ handle_command_set (struct handler_args *a) struct str_vector all; str_vector_init (&all); - dump_matching_options (ctx, option, &all); + dump_matching_options (ctx->config.root, option, &all); bool result = true; if (!all.len) @@ -10781,8 +10781,6 @@ load_configuration (struct app_context *ctx) if (root) { - config_item_destroy (ctx->config.root); - ctx->config.root = NULL; config_load (&ctx->config, root); log_global_status (ctx, "Configuration loaded"); } @@ -11206,6 +11204,71 @@ init_poller_events (struct app_context *ctx) #ifdef TESTING +static void +on_test_config_foo_change (struct config_item *item) +{ + *(bool *) item->user_data = item->value.boolean; +} + +static struct config_schema g_config_test[] = +{ + { .name = "foo", + .comment = "baz", + .type = CONFIG_ITEM_BOOLEAN, + .default_ = "off", + .on_change = on_test_config_foo_change }, + { .name = "bar", + .type = CONFIG_ITEM_INTEGER, + .validate = config_validate_nonnegative, + .default_ = "1" }, + { .name = "foobar", + .type = CONFIG_ITEM_STRING, + .default_ = "\"qux\"" }, + {} +}; + +static void +test_config_load (struct config_item *subtree, void *user_data) +{ + config_schema_apply_to_object (g_config_test, subtree, user_data); +} + +static void +test_config (void) +{ + struct config config; + config_init (&config); + + bool b = true; + config_register_module (&config, "top", test_config_load, &b); + config_load (&config, config_item_object ()); + config_schema_call_changed (config.root); + hard_assert (b == false); + + struct config_item *invalid = config_item_integer (-1); + hard_assert (!config_item_set_from (config_item_get (config.root, + "top.bar", NULL), invalid, NULL)); + config_item_destroy (invalid); + + struct str s; + str_init (&s); + serialize_configuration (config.root, &s); + config_load (&config, config_item_parse (s.str, s.len, false, NULL)); + str_free (&s); + + struct str_vector v; + str_vector_init (&v); + dump_matching_options (config.root, "*foo*", &v); + hard_assert (v.len == 2); + hard_assert (!strcmp (v.vector[0], "top.foo = off")); + hard_assert (!strcmp (v.vector[1], "top.foobar = \"qux\"")); + str_vector_free (&v); + + config_free (&config); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + static void test_aliases (void) { @@ -11223,18 +11286,16 @@ test_aliases (void) static void test_wrapping (void) { - struct str_vector v; - str_vector_init (&v); - static const char *message = " foo bar foobar fóóbárbáz"; static const char *split[] = { " foo", "bar", "foob", "ar", "fó", "ób", "árb", "áz" }; + struct str_vector v; + str_vector_init (&v); hard_assert (wrap_message (message, 4, &v, NULL)); hard_assert (v.len == N_ELEMENTS (split)); for (size_t i = 0; i < N_ELEMENTS (split); i++) hard_assert (!strcmp (v.vector[i], split[i])); - str_vector_free (&v); } @@ -11250,6 +11311,7 @@ main (int argc, char *argv[]) { struct test test; test_init (&test, argc, argv); + test_add_simple (&test, "/config", NULL, test_config); test_add_simple (&test, "/aliases", NULL, test_aliases); test_add_simple (&test, "/wrapping", NULL, test_wrapping); test_add_simple (&test, "/utf8-prefix", NULL, test_utf8_prefix);