diff --git a/src/app/config/confparse.c b/src/app/config/confparse.c index 5c994c0a6a..71ba39ef52 100644 --- a/src/app/config/confparse.c +++ b/src/app/config/confparse.c @@ -234,7 +234,7 @@ config_mgr_get_suite_ptr(const config_mgr_t *mgr, void *toplevel) * to configuration objects for other modules. This function gets * the sub-object for a particular modules. */ -static void * +STATIC void * config_mgr_get_obj_mutable(const config_mgr_t *mgr, void *toplevel, int idx) { tor_assert(mgr); @@ -253,7 +253,7 @@ config_mgr_get_obj_mutable(const config_mgr_t *mgr, void *toplevel, int idx) } /** As config_mgr_get_obj_mutable(), but return a const pointer. */ -static const void * +STATIC const void * config_mgr_get_obj(const config_mgr_t *mgr, const void *toplevel, int idx) { return config_mgr_get_obj_mutable(mgr, (void*)toplevel, idx); diff --git a/src/app/config/confparse.h b/src/app/config/confparse.h index 74ecb11a36..b7923bb82b 100644 --- a/src/app/config/confparse.h +++ b/src/app/config/confparse.h @@ -146,6 +146,10 @@ bool config_var_is_contained(const config_var_t *var); #ifdef CONFPARSE_PRIVATE STATIC void config_reset_line(const config_mgr_t *mgr, void *options, const char *key, int use_defaults); +STATIC void *config_mgr_get_obj_mutable(const config_mgr_t *mgr, + void *toplevel, int idx); +STATIC const void *config_mgr_get_obj(const config_mgr_t *mgr, + const void *toplevel, int idx); #endif #endif /* !defined(TOR_CONFPARSE_H) */ diff --git a/src/test/test_confmgr.c b/src/test/test_confmgr.c index 9801108e97..547fd5f423 100644 --- a/src/test/test_confmgr.c +++ b/src/test/test_confmgr.c @@ -8,6 +8,7 @@ * formats and configuration objects. */ +#define CONFPARSE_PRIVATE #include "orconfig.h" #include "core/or/or.h" @@ -128,12 +129,15 @@ static const config_format_t alpaca_fmt = { .deprecations = alpaca_deprecations, }; +#define LLAMA_IDX 0 +#define ALPACA_IDX 1 + static config_mgr_t * get_mgr(bool freeze) { config_mgr_t *mgr = config_mgr_new(&pasture_fmt); - tt_int_op(0, OP_EQ, config_mgr_add_format(mgr, &llama_fmt)); - tt_int_op(1, OP_EQ, config_mgr_add_format(mgr, &alpaca_fmt)); + tt_int_op(LLAMA_IDX, OP_EQ, config_mgr_add_format(mgr, &llama_fmt)); + tt_int_op(ALPACA_IDX, OP_EQ, config_mgr_add_format(mgr, &alpaca_fmt)); if (freeze) config_mgr_freeze(mgr); return mgr; @@ -173,10 +177,92 @@ test_confmgr_init(void *arg) config_mgr_free(mgr); } +static void +test_confmgr_magic(void *args) +{ + (void)args; + // Every time we build a manager, it is supposed to get a different magic + // number. Let's test that. + config_mgr_t *mgr1 = get_mgr(true); + config_mgr_t *mgr2 = get_mgr(true); + config_mgr_t *mgr3 = get_mgr(true); + + pasture_cfg_t *p1 = NULL, *p2 = NULL, *p3 = NULL; + + tt_assert(mgr1); + tt_assert(mgr2); + tt_assert(mgr3); + + p1 = config_new(mgr1); + p2 = config_new(mgr2); + p3 = config_new(mgr3); + + tt_assert(p1); + tt_assert(p2); + tt_assert(p3); + + // By chance, two managers get the same magic with P=2^-32. Let's + // make sure that at least two of them are different, so that our + // odds of a false positive are 1/2^-64. + tt_assert((p1->magic != p2->magic) || (p2->magic != p3->magic)); + + done: + config_free(mgr1, p1); + config_free(mgr2, p2); + config_free(mgr3, p3); + + config_mgr_free(mgr1); + config_mgr_free(mgr2); + config_mgr_free(mgr3); +} + +static const char *simple_pasture = + "LLamaname hugo\n" + "Alpacaname daphne\n" + "gentillesse 42\n" + "address 123 Camelid ave\n"; + +static void +test_confmgr_parse(void *arg) +{ + (void)arg; + config_mgr_t *mgr = get_mgr(true); + pasture_cfg_t *p = config_new(mgr); + config_line_t *lines = NULL; + char *msg = NULL; + + config_init(mgr, p); // set defaults. + + int r = config_get_lines(simple_pasture, &lines, 0); + tt_int_op(r, OP_EQ, 0); + r = config_assign(mgr, p, lines, 0, &msg); + tt_int_op(r, OP_EQ, 0); + + tt_int_op(p->opentopublic, OP_EQ, 1); + tt_str_op(p->address, OP_EQ, "123 Camelid ave"); + + // We are using this API directly; modules outside confparse will, in the + // future, not. + const alpaca_cfg_t *ac = config_mgr_get_obj(mgr, p, ALPACA_IDX); + const llama_cfg_t *lc = config_mgr_get_obj(mgr, p, LLAMA_IDX); + tt_str_op(lc->llamaname, OP_EQ, "hugo"); + tt_str_op(ac->alpacaname, OP_EQ, "daphne"); + tt_int_op(lc->cuteness, OP_EQ, 42); + tt_int_op(ac->fuzziness, OP_EQ, 50); + + done: + config_free_lines(lines); + config_free(mgr, p); + config_mgr_free(mgr); + tor_free(msg); +} + #define CONFMGR_TEST(name, flags) \ { #name, test_confmgr_ ## name, flags, NULL, NULL } struct testcase_t confmgr_tests[] = { CONFMGR_TEST(init, 0), + CONFMGR_TEST(magic, 0), + CONFMGR_TEST(parse, 0), END_OF_TESTCASES };