media formats: re-architect handling of media for performance improvements
[asterisk/asterisk.git] / tests / test_config.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2010, Digium, Inc.
5  *
6  * Mark Michelson <mmichelson@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*!
20  * \file
21  * \brief Configuration unit tests
22  *
23  * \author Mark Michelson <mmichelson@digium.com>
24  *
25  */
26
27 /*** MODULEINFO
28         <depend>TEST_FRAMEWORK</depend>
29         <support_level>core</support_level>
30  ***/
31
32 #include "asterisk.h"
33
34 ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
35
36 #include <math.h> /* HUGE_VAL */
37
38 #include "asterisk/config.h"
39 #include "asterisk/module.h"
40 #include "asterisk/test.h"
41 #include "asterisk/paths.h"
42 #include "asterisk/config_options.h"
43 #include "asterisk/netsock2.h"
44 #include "asterisk/acl.h"
45 #include "asterisk/frame.h"
46 #include "asterisk/utils.h"
47 #include "asterisk/logger.h"
48 #include "asterisk/format_cap.h"
49
50 #define CONFIG_FILE "test_config.conf"
51
52 /*
53  * This builds the folowing config:
54  * [Capitals]
55  * Germany = Berlin
56  * China = Beijing
57  * Canada = Ottawa
58  *
59  * [Protagonists]
60  * 1984 = Winston Smith
61  * Green Eggs And Ham = Sam I Am
62  * The Kalevala = Vainamoinen
63  *
64  * This config is used for all tests below.
65  */
66 const char cat1[] = "Capitals";
67 const char cat1varname1[] = "Germany";
68 const char cat1varvalue1[] = "Berlin";
69 const char cat1varname2[] = "China";
70 const char cat1varvalue2[] = "Beijing";
71 const char cat1varname3[] = "Canada";
72 const char cat1varvalue3[] = "Ottawa";
73
74 const char cat2[] = "Protagonists";
75 const char cat2varname1[] = "1984";
76 const char cat2varvalue1[] = "Winston Smith";
77 const char cat2varname2[] = "Green Eggs And Ham";
78 const char cat2varvalue2[] = "Sam I Am";
79 const char cat2varname3[] = "The Kalevala";
80 const char cat2varvalue3[] = "Vainamoinen";
81
82 struct pair {
83         const char *name;
84         const char *val;
85 };
86
87 struct association {
88         const char *category;
89         struct pair vars[3];
90 } categories [] = {
91         { cat1,
92                 {
93                         { cat1varname1, cat1varvalue1 },
94                         { cat1varname2, cat1varvalue2 },
95                         { cat1varname3, cat1varvalue3 },
96                 }
97         },
98         { cat2,
99                 {
100                         { cat2varname1, cat2varvalue1 },
101                         { cat2varname2, cat2varvalue2 },
102                         { cat2varname3, cat2varvalue3 },
103                 }
104         },
105 };
106
107 /*!
108  * \brief Build ast_config struct from above definitions
109  *
110  * \retval NULL Failed to build the config
111  * \retval non-NULL An ast_config struct populated with data
112  */
113 static struct ast_config *build_cfg(void)
114 {
115         struct ast_config *cfg;
116         struct association *cat_iter;
117         struct pair *var_iter;
118         size_t i;
119         size_t j;
120
121         cfg = ast_config_new();
122         if (!cfg) {
123                 goto fail;
124         }
125
126         for (i = 0; i < ARRAY_LEN(categories); ++i) {
127                 struct ast_category *cat;
128                 cat_iter = &categories[i];
129
130                 cat = ast_category_new(cat_iter->category, "", 999999);
131                 if (!cat) {
132                         goto fail;
133                 }
134                 ast_category_append(cfg, cat);
135
136                 for (j = 0; j < ARRAY_LEN(cat_iter->vars); ++j) {
137                         struct ast_variable *var;
138                         var_iter = &cat_iter->vars[j];
139
140                         var = ast_variable_new(var_iter->name, var_iter->val, "");
141                         if (!var) {
142                                 goto fail;
143                         }
144                         ast_variable_append(cat, var);
145                 }
146         }
147
148         return cfg;
149
150 fail:
151         ast_config_destroy(cfg);
152         return NULL;
153 }
154
155 /*!
156  * \brief Tests that the contents of an ast_config is what is expected
157  *
158  * \param cfg Config to test
159  * \retval -1 Failed to pass a test
160  * \retval 0 Config passes checks
161  */
162 static int test_config_validity(struct ast_config *cfg)
163 {
164         int i;
165         const char *cat_iter = NULL;
166         /* Okay, let's see if the correct content is there */
167         for (i = 0; i < ARRAY_LEN(categories); ++i) {
168                 struct ast_variable *var = NULL;
169                 size_t j;
170                 cat_iter = ast_category_browse(cfg, cat_iter);
171                 if (strcmp(cat_iter, categories[i].category)) {
172                         ast_log(LOG_ERROR, "Category name mismatch, %s does not match %s\n", cat_iter, categories[i].category);
173                         return -1;
174                 }
175                 for (j = 0; j < ARRAY_LEN(categories[i].vars); ++j) {
176                         var = var ? var->next : ast_variable_browse(cfg, cat_iter);
177                         if (strcmp(var->name, categories[i].vars[j].name)) {
178                                 ast_log(LOG_ERROR, "Variable name mismatch, %s does not match %s\n", var->name, categories[i].vars[j].name);
179                                 return -1;
180                         }
181                         if (strcmp(var->value, categories[i].vars[j].val)) {
182                                 ast_log(LOG_ERROR, "Variable value mismatch, %s does not match %s\n", var->value, categories[i].vars[j].val);
183                                 return -1;
184                         }
185                 }
186         }
187         return 0;
188 }
189
190 AST_TEST_DEFINE(copy_config)
191 {
192         enum ast_test_result_state res = AST_TEST_FAIL;
193         struct ast_config *cfg = NULL;
194         struct ast_config *copy = NULL;
195
196         switch (cmd) {
197         case TEST_INIT:
198                 info->name = "copy_config";
199                 info->category = "/main/config/";
200                 info->summary = "Test copying configuration";
201                 info->description =
202                         "Ensure that variables and categories are copied correctly";
203                 return AST_TEST_NOT_RUN;
204         case TEST_EXECUTE:
205                 break;
206         }
207
208         cfg = build_cfg();
209         if (!cfg) {
210                 goto out;
211         }
212
213         copy = ast_config_copy(cfg);
214         if (!copy) {
215                 goto out;
216         }
217
218         if (test_config_validity(copy) != 0) {
219                 goto out;
220         }
221
222         res = AST_TEST_PASS;
223
224 out:
225         ast_config_destroy(cfg);
226         ast_config_destroy(copy);
227         return res;
228 }
229
230 /*!
231  * \brief Write the config file to disk
232  *
233  * This is necessary for testing config hooks since
234  * they are only triggered when a config is read from
235  * its intended storage medium
236  */
237 static int write_config_file(void)
238 {
239         int i;
240         FILE *config_file;
241         char filename[PATH_MAX];
242
243         snprintf(filename, sizeof(filename), "%s/%s",
244                         ast_config_AST_CONFIG_DIR, CONFIG_FILE);
245         config_file = fopen(filename, "w");
246
247         if (!config_file) {
248                 return -1;
249         }
250
251         for (i = 0; i < ARRAY_LEN(categories); ++i) {
252                 int j;
253                 fprintf(config_file, "[%s]\n", categories[i].category);
254                 for (j = 0; j < ARRAY_LEN(categories[i].vars); ++j) {
255                         fprintf(config_file, "%s = %s\n",
256                                         categories[i].vars[j].name,
257                                         categories[i].vars[j].val);
258                 }
259         }
260
261         fclose(config_file);
262         return 0;
263 }
264
265 /*!
266  * \brief Delete config file created by write_config_file
267  */
268 static void delete_config_file(void)
269 {
270         char filename[PATH_MAX];
271         snprintf(filename, sizeof(filename), "%s/%s",
272                         ast_config_AST_CONFIG_DIR, CONFIG_FILE);
273         unlink(filename);
274 }
275
276 /*
277  * Boolean to indicate if the config hook has run
278  */
279 static int hook_run;
280
281 /*
282  * Boolean to indicate if, when the hook runs, the
283  * data passed to it is what is expected
284  */
285 static int hook_config_sane;
286
287 static int hook_cb(struct ast_config *cfg)
288 {
289         hook_run = 1;
290         if (test_config_validity(cfg) == 0) {
291                 hook_config_sane = 1;
292         }
293         ast_config_destroy(cfg);
294         return 0;
295 }
296
297 AST_TEST_DEFINE(config_hook)
298 {
299         enum ast_test_result_state res = AST_TEST_FAIL;
300         enum config_hook_flags hook_flags = { 0, };
301         struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED };
302         struct ast_config *cfg;
303
304         switch (cmd) {
305         case TEST_INIT:
306                 info->name = "config_hook";
307                 info->category = "/main/config/";
308                 info->summary = "Test config hooks";
309                 info->description =
310                         "Ensure that config hooks are called at approriate times,"
311                         "not called at inappropriate times, and that all information"
312                         "that should be present is present.";
313                 return AST_TEST_NOT_RUN;
314         case TEST_EXECUTE:
315                 break;
316         }
317
318         write_config_file();
319
320         /*
321          * Register a config hook to run when CONFIG_FILE is loaded by this module
322          */
323         ast_config_hook_register("test_hook",
324                         CONFIG_FILE,
325                         AST_MODULE,
326                         hook_flags,
327                         hook_cb);
328
329         /*
330          * Try loading the config file. This should result in the hook
331          * being called
332          */
333         cfg = ast_config_load(CONFIG_FILE, config_flags);
334         ast_config_destroy(cfg);
335         if (!hook_run || !hook_config_sane) {
336                 ast_test_status_update(test, "Config hook either did not run or was given bad data!\n");
337                 goto out;
338         }
339
340         /*
341          * Now try loading the wrong config file but from the right module.
342          * Hook should not run
343          */
344         hook_run = 0;
345         cfg = ast_config_load("asterisk.conf", config_flags);
346         ast_config_destroy(cfg);
347         if (hook_run) {
348                 ast_test_status_update(test, "Config hook ran even though an incorrect file was specified.\n");
349                 goto out;
350         }
351
352         /*
353          * Now try loading the correct config file but from the wrong module.
354          * Hook should not run
355          */
356         hook_run = 0;
357         cfg = ast_config_load2(CONFIG_FILE, "fake_module.so", config_flags);
358         ast_config_destroy(cfg);
359         if (hook_run) {
360                 ast_test_status_update(test, "Config hook ran even though an incorrect module was specified.\n");
361                 goto out;
362         }
363
364         /*
365          * Now try loading the file correctly, but without any changes to the file.
366          * Hook should not run
367          */
368         hook_run = 0;
369         cfg = ast_config_load(CONFIG_FILE, config_flags);
370         /* Only destroy this cfg conditionally. Otherwise a crash happens. */
371         if (cfg != CONFIG_STATUS_FILEUNCHANGED) {
372                 ast_config_destroy(cfg);
373         }
374         if (hook_run) {
375                 ast_test_status_update(test, "Config hook ran even though file contents had not changed\n");
376                 goto out;
377         }
378
379         res = AST_TEST_PASS;
380
381 out:
382         delete_config_file();
383         return res;
384 }
385
386 enum {
387         EXPECT_FAIL = 0,
388         EXPECT_SUCCEED,
389 };
390
391 #define TOOBIG_I32 "2147483649"
392 #define TOOSMALL_I32 "-2147483649"
393 #define TOOBIG_U32 "4294967297"
394 #define TOOSMALL_U32 "-4294967297"
395 #define DEFAULTVAL 42
396 #define EPSILON 0.001
397
398 #define TEST_PARSE(input, should_succeed, expected_result, flags, result, ...) do {\
399         int __res = ast_parse_arg(input, (flags), result, ##__VA_ARGS__); \
400         if (!__res == !should_succeed) { \
401                 ast_test_status_update(test, "ast_parse_arg failed on '%s'. %d/%d\n", input, __res, should_succeed); \
402                 ret = AST_TEST_FAIL; \
403         } else { \
404                 if (((flags) & PARSE_TYPE) == PARSE_INT32) { \
405                         int32_t *r = (int32_t *) (void *) result; \
406                         int32_t e = (int32_t) expected_result; \
407                         if (*r != e) { \
408                                 ast_test_status_update(test, "ast_parse_arg int32_t failed with %d != %d\n", *r, e); \
409                                 ret = AST_TEST_FAIL; \
410                         } \
411                 } else if (((flags) & PARSE_TYPE) == PARSE_UINT32) { \
412                         uint32_t *r = (uint32_t *) (void *) result; \
413                         uint32_t e = (uint32_t) expected_result; \
414                         if (*r != e) { \
415                                 ast_test_status_update(test, "ast_parse_arg uint32_t failed with %u != %u\n", *r, e); \
416                                 ret = AST_TEST_FAIL; \
417                         } \
418                 } else if (((flags) & PARSE_TYPE) == PARSE_DOUBLE) { \
419                         double *r = (double *) (void *) result; \
420                         double e = (double) expected_result; \
421                         if (fabs(*r - e) > EPSILON) { \
422                                 ast_test_status_update(test, "ast_parse_arg double failed with %f != %f\n", *r, e); \
423                                 ret = AST_TEST_FAIL; \
424                         } \
425                 } \
426         } \
427         *(result) = DEFAULTVAL; \
428 } while (0)
429
430 AST_TEST_DEFINE(ast_parse_arg_test)
431 {
432         int ret = AST_TEST_PASS;
433         int32_t int32_t_val = DEFAULTVAL;
434         uint32_t uint32_t_val = DEFAULTVAL;
435         double double_val = DEFAULTVAL;
436
437         switch (cmd) {
438         case TEST_INIT:
439                 info->name = "ast_parse_arg";
440                 info->category = "/config/";
441                 info->summary = "Test the output of ast_parse_arg";
442                 info->description =
443                         "Ensures that ast_parse_arg behaves as expected";
444                 return AST_TEST_NOT_RUN;
445         case TEST_EXECUTE:
446                 break;
447         }
448
449         /* int32 testing */
450         TEST_PARSE("123", EXPECT_SUCCEED, 123, PARSE_INT32, &int32_t_val);
451         TEST_PARSE("-123", EXPECT_SUCCEED, -123, PARSE_INT32, &int32_t_val);
452         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_INT32, &int32_t_val);
453         TEST_PARSE(TOOBIG_I32, EXPECT_FAIL, DEFAULTVAL, PARSE_INT32, &int32_t_val);
454         TEST_PARSE(TOOSMALL_I32, EXPECT_FAIL, DEFAULTVAL, PARSE_INT32, &int32_t_val);
455         TEST_PARSE("not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_INT32, &int32_t_val);
456         TEST_PARSE("7not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_INT32, &int32_t_val);
457         TEST_PARSE("123", EXPECT_SUCCEED, 123, PARSE_INT32 | PARSE_DEFAULT, &int32_t_val, 7);
458         TEST_PARSE("-123", EXPECT_SUCCEED, -123, PARSE_INT32 | PARSE_DEFAULT, &int32_t_val, 7);
459         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_INT32 | PARSE_DEFAULT, &int32_t_val, 7);
460         TEST_PARSE(TOOBIG_I32, EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT, &int32_t_val, 7);
461         TEST_PARSE(TOOSMALL_I32, EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT, &int32_t_val, 7);
462         TEST_PARSE("not a number", EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT, &int32_t_val, 7);
463         TEST_PARSE("7not a number", EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT, &int32_t_val, 7);
464
465         TEST_PARSE("123", EXPECT_SUCCEED, 123, PARSE_INT32 | PARSE_IN_RANGE, &int32_t_val, 0, 200);
466         TEST_PARSE("-123", EXPECT_SUCCEED, -123, PARSE_INT32 | PARSE_IN_RANGE, &int32_t_val, -200, 100);
467         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_INT32 | PARSE_IN_RANGE, &int32_t_val, -1, 0);
468         TEST_PARSE("123", EXPECT_FAIL, DEFAULTVAL, PARSE_INT32 | PARSE_IN_RANGE, &int32_t_val, 0, 122);
469         TEST_PARSE("-123", EXPECT_FAIL, DEFAULTVAL, PARSE_INT32 | PARSE_IN_RANGE, &int32_t_val, -122, 100);
470         TEST_PARSE("0", EXPECT_FAIL, DEFAULTVAL, PARSE_INT32 | PARSE_IN_RANGE, &int32_t_val, 1, 100);
471         TEST_PARSE(TOOBIG_I32, EXPECT_FAIL, DEFAULTVAL, PARSE_INT32 | PARSE_IN_RANGE, &int32_t_val, INT_MIN, INT_MAX);
472         TEST_PARSE(TOOSMALL_I32, EXPECT_FAIL, DEFAULTVAL, PARSE_INT32 | PARSE_IN_RANGE, &int32_t_val, INT_MIN, INT_MAX);
473         TEST_PARSE("not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_INT32 | PARSE_IN_RANGE, &int32_t_val, INT_MIN, INT_MAX);
474         TEST_PARSE("7not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_INT32 | PARSE_IN_RANGE, &int32_t_val, INT_MIN, INT_MAX);
475         TEST_PARSE("123", EXPECT_FAIL, DEFAULTVAL, PARSE_INT32 | PARSE_OUT_RANGE, &int32_t_val, 0, 200);
476         TEST_PARSE("-123", EXPECT_FAIL, DEFAULTVAL, PARSE_INT32 | PARSE_OUT_RANGE, &int32_t_val, -200, 100);
477         TEST_PARSE("0", EXPECT_FAIL, DEFAULTVAL, PARSE_INT32 | PARSE_OUT_RANGE, &int32_t_val, -1, 0);
478         TEST_PARSE("123", EXPECT_SUCCEED, 123, PARSE_INT32 | PARSE_OUT_RANGE, &int32_t_val, 0, 122);
479         TEST_PARSE("-123", EXPECT_SUCCEED, -123, PARSE_INT32 | PARSE_OUT_RANGE, &int32_t_val, -122, 100);
480         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_INT32 | PARSE_OUT_RANGE, &int32_t_val, 1, 100);
481         TEST_PARSE(TOOBIG_I32, EXPECT_FAIL, DEFAULTVAL, PARSE_INT32 | PARSE_OUT_RANGE, &int32_t_val, INT_MIN, INT_MAX);
482         TEST_PARSE(TOOSMALL_I32, EXPECT_FAIL, DEFAULTVAL, PARSE_INT32 | PARSE_OUT_RANGE, &int32_t_val, INT_MIN, INT_MAX);
483         TEST_PARSE("not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_INT32 | PARSE_OUT_RANGE, &int32_t_val, INT_MIN, INT_MAX);
484         TEST_PARSE("7not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_INT32 | PARSE_OUT_RANGE, &int32_t_val, INT_MIN, INT_MAX);
485
486         TEST_PARSE("123", EXPECT_SUCCEED, 123, PARSE_INT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &int32_t_val, 7, 0, 200);
487         TEST_PARSE("-123", EXPECT_SUCCEED, -123, PARSE_INT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &int32_t_val, 7, -200, 100);
488         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_INT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &int32_t_val, 7, -1, 0);
489         TEST_PARSE("123", EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &int32_t_val, 7, 0, 122);
490         TEST_PARSE("-123", EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &int32_t_val, 7, -122, 100);
491         TEST_PARSE("0", EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &int32_t_val, 7, 1, 100);
492         TEST_PARSE(TOOBIG_I32, EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &int32_t_val, 7, INT_MIN, INT_MAX);
493         TEST_PARSE(TOOSMALL_I32, EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &int32_t_val, 7, INT_MIN, INT_MAX);
494         TEST_PARSE("not a number", EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &int32_t_val, 7, INT_MIN, INT_MAX);
495         TEST_PARSE("7not a number", EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &int32_t_val, 7, INT_MIN, INT_MAX);
496         TEST_PARSE("123", EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &int32_t_val, 7, 0, 200);
497         TEST_PARSE("-123", EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &int32_t_val, 7, -200, 100);
498         TEST_PARSE("0", EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &int32_t_val, 7, -1, 0);
499         TEST_PARSE("123", EXPECT_SUCCEED, 123, PARSE_INT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &int32_t_val, 7, 0, 122);
500         TEST_PARSE("-123", EXPECT_SUCCEED, -123, PARSE_INT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &int32_t_val, 7, -122, 100);
501         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_INT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &int32_t_val, 7, 1, 100);
502         TEST_PARSE(TOOBIG_I32, EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &int32_t_val, 7, INT_MIN, INT_MAX);
503         TEST_PARSE(TOOSMALL_I32, EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &int32_t_val, 7, INT_MIN, INT_MAX);
504         TEST_PARSE("not a number", EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &int32_t_val, 7, INT_MIN, INT_MAX);
505         TEST_PARSE("7not a number", EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &int32_t_val, 7, INT_MIN, INT_MAX);
506
507         /* uuint32 testing */
508         TEST_PARSE("123", EXPECT_SUCCEED, 123, PARSE_UINT32, &uint32_t_val);
509         TEST_PARSE("-123", EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32, &uint32_t_val);
510         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_UINT32, &uint32_t_val);
511         TEST_PARSE(TOOBIG_U32, EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32, &uint32_t_val);
512         TEST_PARSE(TOOSMALL_U32, EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32, &uint32_t_val);
513         TEST_PARSE("not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32, &uint32_t_val);
514         TEST_PARSE("7not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32, &uint32_t_val);
515
516         TEST_PARSE("123", EXPECT_SUCCEED, 123, PARSE_UINT32 | PARSE_DEFAULT, &uint32_t_val, 7);
517         TEST_PARSE("-123", EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT, &uint32_t_val, 7);
518         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_UINT32 | PARSE_DEFAULT, &uint32_t_val, 7);
519         TEST_PARSE(TOOBIG_U32, EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT, &uint32_t_val, 7);
520         TEST_PARSE(TOOSMALL_U32, EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT, &uint32_t_val, 7);
521         TEST_PARSE("not a number", EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT, &uint32_t_val, 7);
522         TEST_PARSE("7not a number", EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT, &uint32_t_val, 7);
523
524         TEST_PARSE("123", EXPECT_SUCCEED, 123, PARSE_UINT32 | PARSE_IN_RANGE, &uint32_t_val, 0, 200);
525         TEST_PARSE("-123", EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32 | PARSE_IN_RANGE, &uint32_t_val, 0, 200);
526         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_UINT32 | PARSE_IN_RANGE, &uint32_t_val, 0, 1);
527
528         TEST_PARSE("123", EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32 | PARSE_IN_RANGE, &uint32_t_val, 0, 122);
529         TEST_PARSE("0", EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32 | PARSE_IN_RANGE, &uint32_t_val, 1, 100);
530         TEST_PARSE(TOOBIG_U32, EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32 | PARSE_IN_RANGE, &uint32_t_val, INT_MIN, INT_MAX);
531         TEST_PARSE(TOOSMALL_U32, EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32 | PARSE_IN_RANGE, &uint32_t_val, INT_MIN, INT_MAX);
532         TEST_PARSE("not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32 | PARSE_IN_RANGE, &uint32_t_val, INT_MIN, INT_MAX);
533         TEST_PARSE("7not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32 | PARSE_IN_RANGE, &uint32_t_val, INT_MIN, INT_MAX);
534
535         TEST_PARSE("123", EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32 | PARSE_OUT_RANGE, &uint32_t_val, 0, 200);
536         TEST_PARSE("-123", EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32 | PARSE_OUT_RANGE, &uint32_t_val, 0, 200);
537         TEST_PARSE("0", EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32 | PARSE_OUT_RANGE, &uint32_t_val, 0, 1);
538
539         TEST_PARSE("123", EXPECT_SUCCEED, 123, PARSE_UINT32 | PARSE_OUT_RANGE, &uint32_t_val, 0, 122);
540         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_UINT32 | PARSE_OUT_RANGE, &uint32_t_val, 1, 100);
541         TEST_PARSE(TOOBIG_U32, EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32 | PARSE_OUT_RANGE, &uint32_t_val, INT_MIN, INT_MAX);
542         TEST_PARSE(TOOSMALL_U32, EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32 | PARSE_OUT_RANGE, &uint32_t_val, INT_MIN, INT_MAX);
543         TEST_PARSE("not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32 | PARSE_OUT_RANGE, &uint32_t_val, INT_MIN, INT_MAX);
544         TEST_PARSE("7not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32 | PARSE_OUT_RANGE, &uint32_t_val, INT_MIN, INT_MAX);
545
546         TEST_PARSE("123", EXPECT_SUCCEED, 123, PARSE_UINT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &uint32_t_val, 7, 0, 200);
547         TEST_PARSE("-123", EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &uint32_t_val, 7, 0, 200);
548         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_UINT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &uint32_t_val, 7, 0, 1);
549         TEST_PARSE("123", EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &uint32_t_val, 7, 0, 122);
550         TEST_PARSE("0", EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &uint32_t_val, 7, 1, 100);
551         TEST_PARSE(TOOBIG_U32, EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &uint32_t_val, 7, INT_MIN, INT_MAX);
552         TEST_PARSE(TOOSMALL_U32, EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &uint32_t_val, 7, INT_MIN, INT_MAX);
553         TEST_PARSE("not a number", EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &uint32_t_val, 7, INT_MIN, INT_MAX);
554         TEST_PARSE("7not a number", EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &uint32_t_val, 7, INT_MIN, INT_MAX);
555         TEST_PARSE("123", EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &uint32_t_val, 7, 0, 200);
556         TEST_PARSE("-123", EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &uint32_t_val, 7, 0, 100);
557         TEST_PARSE("0", EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &uint32_t_val, 7, 0, 1);
558         TEST_PARSE("123", EXPECT_SUCCEED, 123, PARSE_UINT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &uint32_t_val, 7, 0, 122);
559         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_UINT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &uint32_t_val, 7, 1, 100);
560         TEST_PARSE(TOOBIG_U32, EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &uint32_t_val, 7, INT_MIN, INT_MAX);
561         TEST_PARSE(TOOSMALL_U32, EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &uint32_t_val, 7, INT_MIN, INT_MAX);
562         TEST_PARSE("not a number", EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &uint32_t_val, 7, INT_MIN, INT_MAX);
563         TEST_PARSE("7not a number", EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &uint32_t_val, 7, INT_MIN, INT_MAX);
564
565         TEST_PARSE("   -123", EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32, &uint32_t_val);
566
567         /* double testing */
568         TEST_PARSE("123", EXPECT_SUCCEED, 123, PARSE_DOUBLE, &double_val);
569         TEST_PARSE("123.123", EXPECT_SUCCEED, 123.123, PARSE_DOUBLE, &double_val);
570         TEST_PARSE("-123", EXPECT_SUCCEED, -123, PARSE_DOUBLE, &double_val);
571         TEST_PARSE("-123.123", EXPECT_SUCCEED, -123.123, PARSE_DOUBLE, &double_val);
572         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_DOUBLE, &double_val);
573         TEST_PARSE("not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_DOUBLE, &double_val);
574         TEST_PARSE("7.0not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_DOUBLE, &double_val);
575         TEST_PARSE("123.123", EXPECT_SUCCEED, 123.123, PARSE_DOUBLE | PARSE_DEFAULT, &double_val, 7.0);
576         TEST_PARSE("-123.123", EXPECT_SUCCEED, -123.123, PARSE_DOUBLE | PARSE_DEFAULT, &double_val, 7.0);
577         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_DOUBLE | PARSE_DEFAULT, &double_val, 7.0);
578         TEST_PARSE("not a number", EXPECT_FAIL, 7.0, PARSE_DOUBLE | PARSE_DEFAULT, &double_val, 7.0);
579         TEST_PARSE("7.0not a number", EXPECT_FAIL, 7.0, PARSE_DOUBLE | PARSE_DEFAULT, &double_val, 7.0);
580
581         TEST_PARSE("123.123", EXPECT_SUCCEED, 123.123, PARSE_DOUBLE | PARSE_IN_RANGE, &double_val, 0.0, 200.0);
582         TEST_PARSE("-123.123", EXPECT_SUCCEED, -123.123, PARSE_DOUBLE | PARSE_IN_RANGE, &double_val, -200.0, 100.0);
583         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_DOUBLE | PARSE_IN_RANGE, &double_val, -1.0, 0.0);
584         TEST_PARSE("123.123", EXPECT_FAIL, DEFAULTVAL, PARSE_DOUBLE | PARSE_IN_RANGE, &double_val, 0.0, 122.0);
585         TEST_PARSE("-123.123", EXPECT_FAIL, DEFAULTVAL, PARSE_DOUBLE | PARSE_IN_RANGE, &double_val, -122.0, 100.0);
586         TEST_PARSE("0", EXPECT_FAIL, DEFAULTVAL, PARSE_DOUBLE | PARSE_IN_RANGE, &double_val, 1.0, 100.0);
587         TEST_PARSE("not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_DOUBLE | PARSE_IN_RANGE, &double_val, -HUGE_VAL, HUGE_VAL);
588         TEST_PARSE("7not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_DOUBLE | PARSE_IN_RANGE, &double_val, -HUGE_VAL, HUGE_VAL);
589         TEST_PARSE("123.123", EXPECT_FAIL, DEFAULTVAL, PARSE_DOUBLE | PARSE_OUT_RANGE, &double_val, 0.0, 200.0);
590         TEST_PARSE("-123.123", EXPECT_FAIL, DEFAULTVAL, PARSE_DOUBLE | PARSE_OUT_RANGE, &double_val, -200.0, 100.0);
591         TEST_PARSE("0", EXPECT_FAIL, DEFAULTVAL, PARSE_DOUBLE | PARSE_OUT_RANGE, &double_val, -1.0, 0.0);
592         TEST_PARSE("123.123", EXPECT_SUCCEED, 123.123, PARSE_DOUBLE | PARSE_OUT_RANGE, &double_val, 0.0, 122.0);
593         TEST_PARSE("-123.123", EXPECT_SUCCEED, -123.123, PARSE_DOUBLE | PARSE_OUT_RANGE, &double_val, -122.0, 100.0);
594         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_DOUBLE | PARSE_OUT_RANGE, &double_val, 1.0, 100.0);
595         TEST_PARSE("not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_DOUBLE | PARSE_OUT_RANGE, &double_val, -HUGE_VAL, HUGE_VAL);
596         TEST_PARSE("7not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_DOUBLE | PARSE_OUT_RANGE, &double_val, -HUGE_VAL, HUGE_VAL);
597
598         TEST_PARSE("123.123", EXPECT_SUCCEED, 123.123, PARSE_DOUBLE | PARSE_DEFAULT | PARSE_IN_RANGE, &double_val, 7.0, 0.0, 200.0);
599         TEST_PARSE("-123.123", EXPECT_SUCCEED, -123.123, PARSE_DOUBLE | PARSE_DEFAULT | PARSE_IN_RANGE, &double_val, 7.0, -200.0, 100.0);
600         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_DOUBLE | PARSE_DEFAULT | PARSE_IN_RANGE, &double_val, 7.0, -1.0, 0.0);
601         TEST_PARSE("123.123", EXPECT_FAIL, 7.0, PARSE_DOUBLE | PARSE_DEFAULT | PARSE_IN_RANGE, &double_val, 7.0, 0.0, 122.0);
602         TEST_PARSE("-123.123", EXPECT_FAIL, 7.0, PARSE_DOUBLE | PARSE_DEFAULT | PARSE_IN_RANGE, &double_val, 7.0, -122.0, 100.0);
603         TEST_PARSE("0", EXPECT_FAIL, 7.0, PARSE_DOUBLE | PARSE_DEFAULT | PARSE_IN_RANGE, &double_val, 7.0, 1.0, 100.0);
604         TEST_PARSE("not a number", EXPECT_FAIL, 7.0, PARSE_DOUBLE | PARSE_DEFAULT | PARSE_IN_RANGE, &double_val, 7.0, -HUGE_VAL, HUGE_VAL);
605         TEST_PARSE("7not a number", EXPECT_FAIL, 7.0, PARSE_DOUBLE | PARSE_DEFAULT | PARSE_IN_RANGE, &double_val, 7.0, -HUGE_VAL, HUGE_VAL);
606         TEST_PARSE("123.123", EXPECT_FAIL, 7.0, PARSE_DOUBLE | PARSE_DEFAULT | PARSE_OUT_RANGE, &double_val, 7.0, 0.0, 200.0);
607         TEST_PARSE("-123.123", EXPECT_FAIL, 7.0, PARSE_DOUBLE | PARSE_DEFAULT | PARSE_OUT_RANGE, &double_val, 7.0, -200.0, 100.0);
608         TEST_PARSE("0", EXPECT_FAIL, 7.0, PARSE_DOUBLE | PARSE_DEFAULT | PARSE_OUT_RANGE, &double_val, 7.0, -1.0, 0.0);
609         TEST_PARSE("123.123", EXPECT_SUCCEED, 123.123, PARSE_DOUBLE | PARSE_DEFAULT | PARSE_OUT_RANGE, &double_val, 7.0, 0.0, 122.0);
610         TEST_PARSE("-123.123", EXPECT_SUCCEED, -123.123, PARSE_DOUBLE | PARSE_DEFAULT | PARSE_OUT_RANGE, &double_val, 7.0, -122.0, 100.0);
611         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_DOUBLE | PARSE_DEFAULT | PARSE_OUT_RANGE, &double_val, 7.0, 1.0, 100.0);
612         TEST_PARSE("not a number", EXPECT_FAIL, 7.0, PARSE_DOUBLE | PARSE_DEFAULT | PARSE_OUT_RANGE, &double_val, 7.0, -HUGE_VAL, HUGE_VAL);
613         TEST_PARSE("7not a number", EXPECT_FAIL, 7.0, PARSE_DOUBLE | PARSE_DEFAULT | PARSE_OUT_RANGE, &double_val, 7.0, -HUGE_VAL, HUGE_VAL);
614
615         /* ast_sockaddr_parse is tested extensively in test_netsock2.c and PARSE_ADDR is a very simple wrapper */
616
617         return ret;
618 }
619 struct test_item {
620         AST_DECLARE_STRING_FIELDS(
621                 AST_STRING_FIELD(name);
622                 AST_STRING_FIELD(stropt);
623         );
624         int32_t intopt;
625         uint32_t uintopt;
626         unsigned int flags;
627         double doubleopt;
628         struct ast_sockaddr sockaddropt;
629         int boolopt;
630         struct ast_ha *aclopt;
631         struct ast_format_cap *codeccapopt;
632         unsigned int customopt:1;
633 };
634 struct test_config {
635         struct test_item *global;
636         struct test_item *global_defaults;
637         struct ao2_container *items;
638 };
639
640 static int test_item_hash(const void *obj, const int flags)
641 {
642         const struct test_item *item = obj;
643         const char *name = (flags & OBJ_KEY) ? obj : item->name;
644         return ast_str_case_hash(name);
645 }
646 static int test_item_cmp(void *obj, void *arg, int flags)
647 {
648         struct test_item *one = obj, *two = arg;
649         const char *match = (flags & OBJ_KEY) ? arg : two->name;
650         return strcasecmp(one->name, match) ? 0 : (CMP_MATCH | CMP_STOP);
651 }
652 static void test_item_destructor(void *obj)
653 {
654         struct test_item *item = obj;
655         ast_string_field_free_memory(item);
656         ao2_cleanup(item->codeccapopt);
657         if (item->aclopt) {
658                 ast_free_ha(item->aclopt);
659         }
660         return;
661 }
662 static void *test_item_alloc(const char *cat)
663 {
664         struct test_item *item;
665         if (!(item = ao2_alloc(sizeof(*item), test_item_destructor))) {
666                 return NULL;
667         }
668         if (ast_string_field_init(item, 128)) {
669                 ao2_ref(item, -1);
670                 return NULL;
671         }
672         if (!(item->codeccapopt = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
673                 ao2_ref(item, -1);
674                 return NULL;
675         }
676         ast_string_field_set(item, name, cat);
677         return item;
678 }
679 static void test_config_destructor(void *obj)
680 {
681         struct test_config *cfg = obj;
682         ao2_cleanup(cfg->global);
683         ao2_cleanup(cfg->global_defaults);
684         ao2_cleanup(cfg->items);
685 }
686 static void *test_config_alloc(void)
687 {
688         struct test_config *cfg;
689         if (!(cfg = ao2_alloc(sizeof(*cfg), test_config_destructor))) {
690                 goto error;
691         }
692         if (!(cfg->global = test_item_alloc("global"))) {
693                 goto error;
694         }
695         if (!(cfg->global_defaults = test_item_alloc("global_defaults"))) {
696                 goto error;
697         }
698         if (!(cfg->items = ao2_container_alloc(1, test_item_hash, test_item_cmp))) {
699                 goto error;
700         }
701         return cfg;
702 error:
703         ao2_cleanup(cfg);
704         return NULL;
705 }
706 static void *test_item_find(struct ao2_container *container, const char *cat)
707 {
708         return ao2_find(container, cat, OBJ_KEY);
709 }
710
711 static int customopt_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
712 {
713         struct test_item *item = obj;
714         if (!strcasecmp(var->name, "customopt")) {
715                 item->customopt = ast_true(var->value);
716         } else {
717                 return -1;
718         }
719
720         return 0;
721 }
722
723 static struct aco_type global = {
724         .type = ACO_GLOBAL,
725         .item_offset = offsetof(struct test_config, global),
726         .category_match = ACO_WHITELIST,
727         .category = "^global$",
728 };
729 static struct aco_type global_defaults = {
730         .type = ACO_GLOBAL,
731         .item_offset = offsetof(struct test_config, global_defaults),
732         .category_match = ACO_WHITELIST,
733         .category = "^global_defaults$",
734 };
735 static struct aco_type item = {
736         .type = ACO_ITEM,
737         .category_match = ACO_BLACKLIST,
738         .category = "^(global|global_defaults)$",
739         .item_alloc = test_item_alloc,
740         .item_find = test_item_find,
741         .item_offset = offsetof(struct test_config, items),
742 };
743
744 struct aco_file config_test_conf = {
745         .filename = "config_test.conf",
746         .types = ACO_TYPES(&global, &global_defaults, &item),
747 };
748
749 static AO2_GLOBAL_OBJ_STATIC(global_obj);
750 CONFIG_INFO_TEST(cfg_info, global_obj, test_config_alloc,
751         .files = ACO_FILES(&config_test_conf),
752 );
753
754 AST_TEST_DEFINE(config_options_test)
755 {
756         int res = AST_TEST_PASS, x, error;
757         struct test_item defaults = { 0, }, configs = { 0, };
758         struct test_item *arr[4];
759         struct ast_sockaddr acl_allow = {{ 0, }}, acl_fail = {{ 0, }};
760         RAII_VAR(struct test_config *, cfg, NULL, ao2_cleanup);
761         RAII_VAR(struct test_item *, item, NULL, ao2_cleanup);
762         RAII_VAR(struct test_item *, item_defaults, NULL, ao2_cleanup);
763
764         switch (cmd) {
765         case TEST_INIT:
766                 info->name = "config_options_test";
767                 info->category = "/config/";
768                 info->summary = "Config opptions unit test";
769                 info->description =
770                         "Tests the Config Options API";
771                 return AST_TEST_NOT_RUN;
772         case TEST_EXECUTE:
773                 break;
774         }
775
776 #define INT_DEFAULT "-2"
777 #define INT_CONFIG "-1"
778 #define UINT_DEFAULT "2"
779 #define UINT_CONFIG "1"
780 #define DOUBLE_DEFAULT "1.1"
781 #define DOUBLE_CONFIG "0.1"
782 #define SOCKADDR_DEFAULT "4.3.2.1:4321"
783 #define SOCKADDR_CONFIG "1.2.3.4:1234"
784 #define BOOL_DEFAULT "false"
785 #define BOOL_CONFIG "true"
786 #define BOOLFLAG1_DEFAULT "false"
787 #define BOOLFLAG1_CONFIG "true"
788 #define BOOLFLAG2_DEFAULT "false"
789 #define BOOLFLAG2_CONFIG "false"
790 #define BOOLFLAG3_DEFAULT "false"
791 #define BOOLFLAG3_CONFIG "true"
792 #define ACL_DEFAULT NULL
793 #define ACL_CONFIG_PERMIT "1.2.3.4/32"
794 #define ACL_CONFIG_DENY "0.0.0.0/0"
795 #define CODEC_DEFAULT "!all,alaw"
796 #define CODEC_CONFIG "!all,ulaw,g729"
797 #define STR_DEFAULT "default"
798 #define STR_CONFIG "test"
799 #define CUSTOM_DEFAULT "no"
800 #define CUSTOM_CONFIG "yes"
801
802 #define BOOLFLAG1 1 << 0
803 #define BOOLFLAG2 1 << 1
804 #define BOOLFLAG3 1 << 2
805
806         if (aco_info_init(&cfg_info)) {
807                 ast_test_status_update(test, "Could not init cfg info\n");
808                 return AST_TEST_FAIL;
809         }
810
811         /* Register all options */
812         aco_option_register(&cfg_info, "intopt", ACO_EXACT, config_test_conf.types, INT_DEFAULT, OPT_INT_T, 0, FLDSET(struct test_item, intopt));
813         aco_option_register(&cfg_info, "uintopt", ACO_EXACT, config_test_conf.types, UINT_DEFAULT, OPT_UINT_T, 0, FLDSET(struct test_item, uintopt));
814         aco_option_register(&cfg_info, "doubleopt", ACO_EXACT, config_test_conf.types, DOUBLE_DEFAULT, OPT_DOUBLE_T, 0, FLDSET(struct test_item, doubleopt));
815         aco_option_register(&cfg_info, "sockaddropt", ACO_EXACT, config_test_conf.types, SOCKADDR_DEFAULT, OPT_SOCKADDR_T, 0, FLDSET(struct test_item, sockaddropt));
816         aco_option_register(&cfg_info, "boolopt", ACO_EXACT, config_test_conf.types, BOOL_DEFAULT, OPT_BOOL_T, 1, FLDSET(struct test_item, boolopt));
817         aco_option_register(&cfg_info, "boolflag1", ACO_EXACT, config_test_conf.types, BOOLFLAG1_DEFAULT, OPT_BOOLFLAG_T, 1, FLDSET(struct test_item, flags), BOOLFLAG1);
818         aco_option_register(&cfg_info, "boolflag2", ACO_EXACT, config_test_conf.types, BOOLFLAG2_DEFAULT, OPT_BOOLFLAG_T, 1, FLDSET(struct test_item, flags), BOOLFLAG2);
819         aco_option_register(&cfg_info, "boolflag3", ACO_EXACT, config_test_conf.types, BOOLFLAG3_DEFAULT, OPT_BOOLFLAG_T, 1, FLDSET(struct test_item, flags), BOOLFLAG3);
820         aco_option_register(&cfg_info, "aclpermitopt", ACO_EXACT, config_test_conf.types, ACL_DEFAULT, OPT_ACL_T, 1, FLDSET(struct test_item, aclopt));
821         aco_option_register(&cfg_info, "acldenyopt", ACO_EXACT, config_test_conf.types, ACL_DEFAULT, OPT_ACL_T, 0, FLDSET(struct test_item, aclopt));
822         aco_option_register(&cfg_info, "codecopt", ACO_EXACT, config_test_conf.types, CODEC_DEFAULT, OPT_CODEC_T, 1, FLDSET(struct test_item, codeccapopt));
823         aco_option_register(&cfg_info, "stropt", ACO_EXACT, config_test_conf.types, STR_DEFAULT, OPT_STRINGFIELD_T, 0, STRFLDSET(struct test_item, stropt));
824         aco_option_register_custom(&cfg_info, "customopt", ACO_EXACT, config_test_conf.types, CUSTOM_DEFAULT, customopt_handler, 0);
825         aco_option_register_deprecated(&cfg_info, "permit", config_test_conf.types, "aclpermitopt");
826         aco_option_register_deprecated(&cfg_info, "deny", config_test_conf.types, "acldenyopt");
827
828         if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
829                 ast_test_status_update(test, "Could not parse config\n");
830                 return AST_TEST_FAIL;
831         }
832
833         ast_parse_arg(INT_DEFAULT, PARSE_INT32, &defaults.intopt);
834         ast_parse_arg(INT_CONFIG, PARSE_INT32, &configs.intopt);
835         ast_parse_arg(UINT_DEFAULT, PARSE_UINT32, &defaults.uintopt);
836         ast_parse_arg(UINT_CONFIG, PARSE_UINT32, &configs.uintopt);
837         ast_parse_arg(DOUBLE_DEFAULT, PARSE_DOUBLE, &defaults.doubleopt);
838         ast_parse_arg(DOUBLE_CONFIG, PARSE_DOUBLE, &configs.doubleopt);
839         ast_parse_arg(SOCKADDR_DEFAULT, PARSE_ADDR, &defaults.sockaddropt);
840         ast_parse_arg(SOCKADDR_CONFIG, PARSE_ADDR, &configs.sockaddropt);
841         defaults.boolopt = ast_true(BOOL_DEFAULT);
842         configs.boolopt = ast_true(BOOL_CONFIG);
843         ast_set2_flag(&defaults, ast_true(BOOLFLAG1_DEFAULT), BOOLFLAG1);
844         ast_set2_flag(&defaults, ast_true(BOOLFLAG2_DEFAULT), BOOLFLAG2);
845         ast_set2_flag(&defaults, ast_true(BOOLFLAG3_DEFAULT), BOOLFLAG3);
846         ast_set2_flag(&configs, ast_true(BOOLFLAG1_CONFIG), BOOLFLAG1);
847         ast_set2_flag(&configs, ast_true(BOOLFLAG2_CONFIG), BOOLFLAG2);
848         ast_set2_flag(&configs, ast_true(BOOLFLAG3_CONFIG), BOOLFLAG3);
849
850         defaults.aclopt = NULL;
851         configs.aclopt = ast_append_ha("deny", ACL_CONFIG_DENY, configs.aclopt, &error);
852         configs.aclopt = ast_append_ha("permit", ACL_CONFIG_PERMIT, configs.aclopt, &error);
853         ast_sockaddr_parse(&acl_allow, "1.2.3.4", PARSE_PORT_FORBID);
854         ast_sockaddr_parse(&acl_fail, "1.1.1.1", PARSE_PORT_FORBID);
855
856         defaults.codeccapopt = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
857         ast_format_cap_update_by_allow_disallow(defaults.codeccapopt, CODEC_DEFAULT, 1);
858
859         configs.codeccapopt = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
860         ast_format_cap_update_by_allow_disallow(configs.codeccapopt, CODEC_CONFIG, 1);
861
862         ast_string_field_init(&defaults, 128);
863         ast_string_field_init(&configs, 128);
864         ast_string_field_set(&defaults, stropt, STR_DEFAULT);
865         ast_string_field_set(&configs, stropt, STR_CONFIG);
866
867         defaults.customopt = ast_true(CUSTOM_DEFAULT);
868         configs.customopt = ast_true(CUSTOM_CONFIG);
869
870
871         cfg = ao2_global_obj_ref(global_obj);
872         if (!(item = ao2_find(cfg->items, "item", OBJ_KEY))) {
873                 ast_test_status_update(test, "could not look up 'item'\n");
874                 return AST_TEST_FAIL;
875         }
876         if (!(item_defaults = ao2_find(cfg->items, "item_defaults", OBJ_KEY))) {
877                 ast_test_status_update(test, "could not look up 'item_defaults'\n");
878                 return AST_TEST_FAIL;
879         }
880         arr[0] = cfg->global;
881         arr[1] = item;
882         arr[2] = cfg->global_defaults;
883         arr[3] = item_defaults;
884         /* Test global and item against configs, global_defaults and item_defaults against defaults */
885
886 #define NOT_EQUAL_FAIL(field)  \
887         if (arr[x]->field != control->field) { \
888                 ast_test_status_update(test, "%s did not match: %d != %d with x = %d\n", #field, arr[x]->field, control->field, x); \
889                 res = AST_TEST_FAIL; \
890         }
891         for (x = 0; x < 4; x++) {
892                 struct test_item *control = x < 2 ? &configs : &defaults;
893
894                 NOT_EQUAL_FAIL(intopt);
895                 NOT_EQUAL_FAIL(uintopt);
896                 NOT_EQUAL_FAIL(boolopt);
897                 NOT_EQUAL_FAIL(flags);
898                 NOT_EQUAL_FAIL(customopt);
899                 if (fabs(arr[x]->doubleopt - control->doubleopt) > 0.001) {
900                         ast_test_status_update(test, "doubleopt did not match: %f vs %f on loop %d\n", arr[x]->doubleopt, control->doubleopt, x);
901                         res = AST_TEST_FAIL;
902                 }
903                 if (ast_sockaddr_cmp(&arr[x]->sockaddropt, &control->sockaddropt)) {
904                         ast_test_status_update(test, "sockaddr did not match on loop %d\n", x);
905                         res = AST_TEST_FAIL;
906                 }
907                 if (!ast_format_cap_identical(arr[x]->codeccapopt, control->codeccapopt)) {
908                         struct ast_str *codec_buf1 = ast_str_alloca(64);
909                         struct ast_str *codec_buf2 = ast_str_alloca(64);
910
911                         ast_test_status_update(test, "format did not match: '%s' vs '%s' on loop %d\n",
912                                 ast_format_cap_get_names(arr[x]->codeccapopt, &codec_buf1),
913                                 ast_format_cap_get_names(control->codeccapopt, &codec_buf2),
914                                 x);
915                         res = AST_TEST_FAIL;
916                 }
917                 if (strcasecmp(arr[x]->stropt, control->stropt)) {
918                         ast_test_status_update(test, "stropt did not match: '%s' vs '%s' on loop %d\n", arr[x]->stropt, control->stropt, x);
919                         res = AST_TEST_FAIL;
920                 }
921                 if (arr[x]->aclopt != control->aclopt && (ast_apply_ha(arr[x]->aclopt, &acl_allow) != ast_apply_ha(control->aclopt, &acl_allow) ||
922                                 ast_apply_ha(arr[x]->aclopt, &acl_fail) != ast_apply_ha(control->aclopt, &acl_fail))) {
923                         ast_test_status_update(test, "acl not match: on loop %d\n", x);
924                         res = AST_TEST_FAIL;
925                 }
926         }
927
928         ast_free_ha(configs.aclopt);
929         ao2_cleanup(defaults.codeccapopt);
930         defaults.codeccapopt = NULL;
931         ao2_cleanup(configs.codeccapopt);
932         configs.codeccapopt = NULL;
933         ast_string_field_free_memory(&defaults);
934         ast_string_field_free_memory(&configs);
935         return res;
936 }
937
938 static int unload_module(void)
939 {
940         AST_TEST_UNREGISTER(copy_config);
941         AST_TEST_UNREGISTER(config_hook);
942         AST_TEST_UNREGISTER(ast_parse_arg_test);
943         AST_TEST_UNREGISTER(config_options_test);
944         return 0;
945 }
946
947 static int load_module(void)
948 {
949         AST_TEST_REGISTER(copy_config);
950         AST_TEST_REGISTER(config_hook);
951         AST_TEST_REGISTER(ast_parse_arg_test);
952         AST_TEST_REGISTER(config_options_test);
953         return AST_MODULE_LOAD_SUCCESS;
954 }
955
956 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Config test module");
957