unittests: Add a unit test that causes a SEGV and...
[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 #include <math.h> /* HUGE_VAL */
35 #include <sys/stat.h>
36
37 #include "asterisk/config.h"
38 #include "asterisk/module.h"
39 #include "asterisk/test.h"
40 #include "asterisk/paths.h"
41 #include "asterisk/config_options.h"
42 #include "asterisk/netsock2.h"
43 #include "asterisk/acl.h"
44 #include "asterisk/pbx.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 #define CONFIG_INCLUDE_FILE "test_config_include.conf"
52
53 /*
54  * This builds the folowing config:
55  * [Capitals]
56  * Germany = Berlin
57  * China = Beijing
58  * Canada = Ottawa
59  *
60  * [Protagonists]
61  * 1984 = Winston Smith
62  * Green Eggs And Ham = Sam I Am
63  * The Kalevala = Vainamoinen
64  *
65  * This config is used for all tests below.
66  */
67 const char cat1[] = "Capitals";
68 const char cat1varname1[] = "Germany";
69 const char cat1varvalue1[] = "Berlin";
70 const char cat1varname2[] = "China";
71 const char cat1varvalue2[] = "Beijing";
72 const char cat1varname3[] = "Canada";
73 const char cat1varvalue3[] = "Ottawa";
74
75 const char cat2[] = "Protagonists";
76 const char cat2varname1[] = "1984";
77 const char cat2varvalue1[] = "Winston Smith";
78 const char cat2varname2[] = "Green Eggs And Ham";
79 const char cat2varvalue2[] = "Sam I Am";
80 const char cat2varname3[] = "The Kalevala";
81 const char cat2varvalue3[] = "Vainamoinen";
82
83 struct pair {
84         const char *name;
85         const char *val;
86 };
87
88 struct association {
89         const char *category;
90         struct pair vars[3];
91 } categories [] = {
92         { cat1,
93                 {
94                         { cat1varname1, cat1varvalue1 },
95                         { cat1varname2, cat1varvalue2 },
96                         { cat1varname3, cat1varvalue3 },
97                 }
98         },
99         { cat2,
100                 {
101                         { cat2varname1, cat2varvalue1 },
102                         { cat2varname2, cat2varvalue2 },
103                         { cat2varname3, cat2varvalue3 },
104                 }
105         },
106 };
107
108 /*!
109  * \brief Build ast_config struct from above definitions
110  *
111  * \retval NULL Failed to build the config
112  * \retval non-NULL An ast_config struct populated with data
113  */
114 static struct ast_config *build_cfg(void)
115 {
116         struct ast_config *cfg;
117         struct association *cat_iter;
118         struct pair *var_iter;
119         size_t i;
120         size_t j;
121
122         cfg = ast_config_new();
123         if (!cfg) {
124                 goto fail;
125         }
126
127         for (i = 0; i < ARRAY_LEN(categories); ++i) {
128                 struct ast_category *cat;
129                 cat_iter = &categories[i];
130
131                 cat = ast_category_new(cat_iter->category, "", 999999);
132                 if (!cat) {
133                         goto fail;
134                 }
135                 ast_category_append(cfg, cat);
136
137                 for (j = 0; j < ARRAY_LEN(cat_iter->vars); ++j) {
138                         struct ast_variable *var;
139                         var_iter = &cat_iter->vars[j];
140
141                         var = ast_variable_new(var_iter->name, var_iter->val, "");
142                         if (!var) {
143                                 goto fail;
144                         }
145                         ast_variable_append(cat, var);
146                 }
147         }
148
149         return cfg;
150
151 fail:
152         ast_config_destroy(cfg);
153         return NULL;
154 }
155
156 /*!
157  * \brief Tests that the contents of an ast_config is what is expected
158  *
159  * \param cfg Config to test
160  * \retval -1 Failed to pass a test
161  * \retval 0 Config passes checks
162  */
163 static int test_config_validity(struct ast_config *cfg)
164 {
165         int i;
166         const char *cat_iter = NULL;
167         /* Okay, let's see if the correct content is there */
168         for (i = 0; i < ARRAY_LEN(categories); ++i) {
169                 struct ast_variable *var = NULL;
170                 size_t j;
171                 cat_iter = ast_category_browse(cfg, cat_iter);
172                 if (strcmp(cat_iter, categories[i].category)) {
173                         ast_log(LOG_ERROR, "Category name mismatch, %s does not match %s\n", cat_iter, categories[i].category);
174                         return -1;
175                 }
176                 for (j = 0; j < ARRAY_LEN(categories[i].vars); ++j) {
177                         var = var ? var->next : ast_variable_browse(cfg, cat_iter);
178                         if (strcmp(var->name, categories[i].vars[j].name)) {
179                                 ast_log(LOG_ERROR, "Variable name mismatch, %s does not match %s\n", var->name, categories[i].vars[j].name);
180                                 return -1;
181                         }
182                         if (strcmp(var->value, categories[i].vars[j].val)) {
183                                 ast_log(LOG_ERROR, "Variable value mismatch, %s does not match %s\n", var->value, categories[i].vars[j].val);
184                                 return -1;
185                         }
186                 }
187         }
188         return 0;
189 }
190
191 AST_TEST_DEFINE(copy_config)
192 {
193         enum ast_test_result_state res = AST_TEST_FAIL;
194         struct ast_config *cfg = NULL;
195         struct ast_config *copy = NULL;
196
197         switch (cmd) {
198         case TEST_INIT:
199                 info->name = "copy_config";
200                 info->category = "/main/config/";
201                 info->summary = "Test copying configuration";
202                 info->description =
203                         "Ensure that variables and categories are copied correctly";
204                 return AST_TEST_NOT_RUN;
205         case TEST_EXECUTE:
206                 break;
207         }
208
209         cfg = build_cfg();
210         if (!cfg) {
211                 goto out;
212         }
213
214         copy = ast_config_copy(cfg);
215         if (!copy) {
216                 goto out;
217         }
218
219         if (test_config_validity(copy) != 0) {
220                 goto out;
221         }
222
223         res = AST_TEST_PASS;
224
225 out:
226         ast_config_destroy(cfg);
227         ast_config_destroy(copy);
228         return res;
229 }
230
231 AST_TEST_DEFINE(config_basic_ops)
232 {
233         enum ast_test_result_state res = AST_TEST_FAIL;
234         struct ast_config *cfg = NULL;
235         struct ast_category *cat = NULL;
236         struct ast_variable *var;
237         struct ast_variable *varlist;
238         char temp[32];
239         const char *cat_name;
240         const char *var_value;
241         int i;
242
243         switch (cmd) {
244         case TEST_INIT:
245                 info->name = "config_basic_ops";
246                 info->category = "/main/config/";
247                 info->summary = "Test basic config ops";
248                 info->description =     "Test basic config ops";
249                 return AST_TEST_NOT_RUN;
250         case TEST_EXECUTE:
251                 break;
252         }
253
254         cfg = ast_config_new();
255         if (!cfg) {
256                 return res;
257         }
258
259         /* load the config */
260         for(i = 0; i < 5; i++) {
261                 snprintf(temp, sizeof(temp), "test%d", i);
262                 ast_category_append(cfg, ast_category_new(temp, "dummy", -1));
263         }
264
265         /* test0 test1 test2 test3 test4 */
266         /* check the config has 5 elements */
267         i = 0;
268         cat = NULL;
269         while ((cat = ast_category_browse_filtered(cfg, NULL, cat, NULL))) {
270                 snprintf(temp, sizeof(temp), "test%d", i);
271                 if (strcmp(ast_category_get_name(cat), temp)) {
272                         ast_test_status_update(test, "%s != %s\n", ast_category_get_name(cat), temp);
273                         goto out;
274                 }
275                 i++;
276         }
277         if (i != 5) {
278                 ast_test_status_update(test, "There were %d matches instead of 5.\n", i);
279                 goto out;
280         }
281
282         /* search for test2 */
283         cat = ast_category_get(cfg, "test2", NULL);
284         if (!cat || strcmp(ast_category_get_name(cat), "test2")) {
285                 ast_test_status_update(test, "Get failed %s != %s\n", ast_category_get_name(cat), "test2");
286                 goto out;
287         }
288
289         /* delete test2 */
290         cat = ast_category_delete(cfg, cat);
291
292         /* Now: test0 test1 test3 test4 */
293         /* make sure the curr category is test1 */
294         if (!cat || strcmp(ast_category_get_name(cat), "test1")) {
295                 ast_test_status_update(test, "Delete failed %s != %s\n", ast_category_get_name(cat), "test1");
296                 goto out;
297         }
298
299         /* Now: test0 test1 test3 test4 */
300         /* make sure the test2 is not found */
301         cat = ast_category_get(cfg, "test2", NULL);
302         if (cat) {
303                 ast_test_status_update(test, "Should not have found test2\n");
304                 goto out;
305         }
306
307         /* Now: test0 test1 test3 test4 */
308         /* make sure the sequence is correctly missing test2 */
309         i = 0;
310         cat = NULL;
311         while ((cat = ast_category_browse_filtered(cfg, NULL, cat, NULL))) {
312                 snprintf(temp, sizeof(temp), "test%d", i);
313                 if (strcmp(ast_category_get_name(cat), temp)) {
314                         ast_test_status_update(test, "%s != %s\n", ast_category_get_name(cat), temp);
315                         goto out;
316                 }
317                 i++;
318                 if (i == 2) {
319                         i++;
320                 }
321         }
322         if (i != 5) {
323                 ast_test_status_update(test, "There were %d matches instead of 5.\n", i);
324                 goto out;
325         }
326
327         /* insert test2 back in before test3 */
328         ast_category_insert(cfg, ast_category_new("test2", "dummy", -1), "test3");
329
330         /* Now: test0 test1 test2 test3 test4 */
331         /* make sure the sequence is correct again */
332         i = 0;
333         cat = NULL;
334         while ((cat = ast_category_browse_filtered(cfg, NULL, cat, NULL))) {
335                 snprintf(temp, sizeof(temp), "test%d", i);
336                 if (strcmp(ast_category_get_name(cat), temp)) {
337                         ast_test_status_update(test, "%s != %s\n", ast_category_get_name(cat), temp);
338                         goto out;
339                 }
340                 i++;
341         }
342         if (i != 5) {
343                 ast_test_status_update(test, "There were %d matches instead of 5.\n", i);
344                 goto out;
345         }
346
347         /* Now: test0 test1 test2 test3 test4 */
348         /* make sure non filtered browse still works */
349         i = 0;
350         cat_name = NULL;
351         while ((cat_name = ast_category_browse(cfg, cat_name))) {
352                 snprintf(temp, sizeof(temp), "test%d", i);
353                 if (strcmp(cat_name, temp)) {
354                         ast_test_status_update(test, "%s != %s\n", cat_name, temp);
355                         goto out;
356                 }
357                 i++;
358         }
359         if (i != 5) {
360                 ast_test_status_update(test, "There were %d matches instead of 5.\n", i);
361                 goto out;
362         }
363
364         /* append another test2 */
365         ast_category_append(cfg, ast_category_new("test2", "dummy", -1));
366         /* Now: test0 test1 test2 test3 test4 test2*/
367         /* make sure only test2's are returned */
368         i = 0;
369         cat = NULL;
370         while ((cat = ast_category_browse_filtered(cfg, "test2", cat, NULL))) {
371                 if (strcmp(ast_category_get_name(cat), "test2")) {
372                         ast_test_status_update(test, "Should have returned test2 instead of %s\n", ast_category_get_name(cat));
373                         goto out;
374                 }
375                 i++;
376         }
377         /* make sure 2 test2's were found */
378         if (i != 2) {
379                 ast_test_status_update(test, "Should have found 2 test2's %d\n", i);
380                 goto out;
381         }
382
383         /* Test in-flight deletion using ast_category_browse_filtered */
384         /* Now: test0 test1 test2 test3 test4 test2 */
385         /* Delete the middle test2 and continue */
386         cat = NULL;
387         for(i = 0; i < 5; i++) {
388                 snprintf(temp, sizeof(temp), "test%d", i);
389                 cat = ast_category_browse_filtered(cfg, NULL, cat, NULL);
390                 cat_name = ast_category_get_name(cat);
391                 if (strcmp(cat_name, temp)) {
392                         ast_test_status_update(test, "Should have returned %s instead of %s: %d\n", temp, cat_name, i);
393                         goto out;
394                 }
395                 if (i == 2) {
396                         cat = ast_category_delete(cfg, cat);
397                 }
398         }
399
400         /* Now: test0 test3 test4 test2 */
401         /* delete the head item */
402         cat = ast_category_browse_filtered(cfg, NULL, NULL, NULL);
403         cat_name = ast_category_get_name(cat);
404         if (strcmp(cat_name, "test0")) {
405                 ast_test_status_update(test, "Should have returned test0 instead of %s\n", cat_name);
406                 goto out;
407         }
408         ast_category_delete(cfg, cat);
409         /* Now: test3 test4 test2 */
410
411         /* make sure head got updated to the new first element */
412         cat = ast_category_browse_filtered(cfg, NULL, NULL, NULL);
413         cat_name = ast_category_get_name(cat);
414         if (strcmp(cat_name, "test1")) {
415                 ast_test_status_update(test, "Should have returned test3 instead of %s\n", cat_name);
416                 goto out;
417         }
418
419         /* delete the tail item */
420         cat = ast_category_get(cfg, "test2", NULL);
421         cat_name = ast_category_get_name(cat);
422         if (strcmp(cat_name, "test2")) {
423                 ast_test_status_update(test, "Should have returned test2 instead of %s\n", cat_name);
424                 goto out;
425         }
426         ast_category_delete(cfg, cat);
427         /* Now: test3 test4 */
428
429         /* There should now only be 2 elements in the list */
430         cat = NULL;
431         cat = ast_category_browse_filtered(cfg, NULL, cat, NULL);
432         cat_name = ast_category_get_name(cat);
433         if (strcmp(cat_name, "test1")) {
434                 ast_test_status_update(test, "Should have returned test1 instead of %s\n", cat_name);
435                 goto out;
436         }
437
438         cat = ast_category_browse_filtered(cfg, NULL, cat, NULL);
439         cat_name = ast_category_get_name(cat);
440         if (strcmp(cat_name, "test3")) {
441                 ast_test_status_update(test, "Should have returned test3 instead of %s\n", cat_name);
442                 goto out;
443         }
444
445         cat = ast_category_browse_filtered(cfg, NULL, cat, NULL);
446         cat_name = ast_category_get_name(cat);
447         if (strcmp(cat_name, "test4")) {
448                 ast_test_status_update(test, "Should have returned test4 instead of %s\n", cat_name);
449                 goto out;
450         }
451
452         /* There should be nothing more */
453         cat = ast_category_browse_filtered(cfg, NULL, cat, NULL);
454         if (cat) {
455                 ast_test_status_update(test, "Should not have returned anything\n");
456                 goto out;
457         }
458
459         /* Test ast_variable retrieve.
460          * Get the second category.
461          */
462         cat = ast_category_browse_filtered(cfg, NULL, NULL, NULL);
463         cat = ast_category_browse_filtered(cfg, NULL, cat, NULL);
464         cat_name = ast_category_get_name(cat);
465         var = ast_variable_new("aaa", "bbb0", "dummy");
466         if (!var) {
467                 ast_test_status_update(test, "Couldn't allocate variable.\n");
468                 goto out;
469         }
470         ast_variable_append(cat, var);
471
472         /* Make sure we can retrieve with specific category name */
473         var_value = ast_variable_retrieve(cfg, cat_name, "aaa");
474         if (!var_value || strcmp(var_value, "bbb0")) {
475                 ast_test_status_update(test, "Variable not found or wrong value.\n");
476                 goto out;
477         }
478
479         /* Make sure we can retrieve with NULL category name */
480         var_value = ast_variable_retrieve(cfg, NULL, "aaa");
481         if (!var_value || strcmp(var_value, "bbb0")) {
482                 ast_test_status_update(test, "Variable not found or wrong value.\n");
483                 goto out;
484         }
485
486         /* Now test variable retrieve inside a browse loop
487          * with multiple categories of the same name
488          */
489         cat = ast_category_new("test3", "dummy", -1);
490         if (!cat) {
491                 ast_test_status_update(test, "Couldn't allocate category.\n");
492                 goto out;
493         }
494         var = ast_variable_new("aaa", "bbb1", "dummy");
495         if (!var) {
496                 ast_test_status_update(test, "Couldn't allocate variable.\n");
497                 goto out;
498         }
499         ast_variable_append(cat, var);
500         ast_category_append(cfg, cat);
501
502         cat = ast_category_new("test3", "dummy", -1);
503         if (!cat) {
504                 ast_test_status_update(test, "Couldn't allocate category.\n");
505                 goto out;
506         }
507         var = ast_variable_new("aaa", "bbb2", "dummy");
508         if (!var) {
509                 ast_test_status_update(test, "Couldn't allocate variable.\n");
510                 goto out;
511         }
512         ast_variable_append(cat, var);
513         ast_category_append(cfg, cat);
514
515         cat_name = NULL;
516         i = 0;
517         while ((cat_name = ast_category_browse(cfg, cat_name))) {
518                 if (!strcmp(cat_name, "test3")) {
519                         snprintf(temp, sizeof(temp), "bbb%d", i);
520
521                         var_value = ast_variable_retrieve(cfg, cat_name, "aaa");
522                         if (!var_value || strcmp(var_value, temp)) {
523                                 ast_test_status_update(test, "Variable not found or wrong value %s.\n", var_value);
524                                 goto out;
525                         }
526
527                         var = ast_variable_browse(cfg, cat_name);
528                         if (!var->value || strcmp(var->value, temp)) {
529                                 ast_test_status_update(test, "Variable not found or wrong value %s.\n", var->value);
530                                 goto out;
531                         }
532
533                         i++;
534                 }
535         }
536         if (i != 3) {
537                 ast_test_status_update(test, "There should have been 3 matches instead of %d.\n", i);
538                 goto out;
539         }
540
541         varlist = ast_variable_new("name1", "value1", "");
542         ast_variable_list_append_hint(&varlist, NULL, ast_variable_new("name1", "value2", ""));
543         ast_variable_list_append_hint(&varlist, NULL, ast_variable_new("name1", "value3", ""));
544
545         var_value = ast_variable_find_in_list(varlist, "name1");
546         if (strcmp(var_value, "value1") != 0) {
547                 ast_test_status_update(test, "Wrong variable retrieved %s.\n", var_value);
548                 goto out;
549         }
550
551         var_value = ast_variable_find_last_in_list(varlist, "name1");
552         if (strcmp(var_value, "value3") != 0) {
553                 ast_test_status_update(test, "Wrong variable retrieved %s.\n", var_value);
554                 goto out;
555         }
556
557         res = AST_TEST_PASS;
558
559 out:
560         ast_config_destroy(cfg);
561         return res;
562 }
563
564 AST_TEST_DEFINE(config_filtered_ops)
565 {
566         enum ast_test_result_state res = AST_TEST_FAIL;
567         struct ast_config *cfg = NULL;
568         struct ast_category *cat = NULL;
569         char temp[32];
570         const char *value;
571         int i;
572
573         switch (cmd) {
574         case TEST_INIT:
575                 info->name = "config_filtered_ops";
576                 info->category = "/main/config/";
577                 info->summary = "Test filtered config ops";
578                 info->description =     "Test filtered config ops";
579                 return AST_TEST_NOT_RUN;
580         case TEST_EXECUTE:
581                 break;
582         }
583
584         cfg = ast_config_new();
585         if (!cfg) {
586                 return res;
587         }
588
589         /* load the config */
590         for(i = 0; i < 5; i++) {
591                 snprintf(temp, sizeof(temp), "test%d", i);
592                 cat = ast_category_new(temp, "dummy", -1);
593                 ast_variable_insert(cat, ast_variable_new("type", "a", "dummy"), "0");
594                 ast_category_append(cfg, cat);
595         }
596
597         for(i = 0; i < 5; i++) {
598                 snprintf(temp, sizeof(temp), "test%d", i);
599                 cat = ast_category_new(temp, "dummy", -1);
600                 ast_variable_insert(cat, ast_variable_new("type", "b", "dummy"), "0");
601                 ast_category_append(cfg, cat);
602         }
603
604         /* check the config has 5 elements for each type*/
605         i = 0;
606         cat = NULL;
607         while ((cat = ast_category_browse_filtered(cfg, NULL, cat, "type=a"))) {
608                 snprintf(temp, sizeof(temp), "test%d", i);
609                 if (strcmp(ast_category_get_name(cat), temp)) {
610                         ast_test_status_update(test, "%s != %s\n", ast_category_get_name(cat), temp);
611                         goto out;
612                 }
613                 value = ast_variable_find(cat, "type");
614                 if (!value || strcmp(value, "a")) {
615                         ast_test_status_update(test, "Type %s != %s\n", "a", value);
616                         goto out;
617                 }
618                 i++;
619         }
620         if (i != 5) {
621                 ast_test_status_update(test, "There were %d matches instead of 5.\n", i);
622                 goto out;
623         }
624
625         i = 0;
626         cat = NULL;
627         while ((cat = ast_category_browse_filtered(cfg, NULL, cat, "type=b"))) {
628                 snprintf(temp, sizeof(temp), "test%d", i);
629                 if (!cat || strcmp(ast_category_get_name(cat), temp)) {
630                         ast_test_status_update(test, "%s != %s\n", ast_category_get_name(cat), temp);
631                         goto out;
632                 }
633                 value = ast_variable_find(cat, "type");
634                 if (!value || strcmp(value, "b")) {
635                         ast_test_status_update(test, "Type %s != %s\n", "b", value);
636                         goto out;
637                 }
638                 i++;
639         }
640         if (i != 5) {
641                 ast_test_status_update(test, "There were %d matches instead of 5.\n", i);
642                 goto out;
643         }
644
645         /* Delete b3 and make sure it's gone and a3 is still there.
646          * Really this is a test of get since delete takes a specific category structure.
647          */
648         cat = ast_category_get(cfg, "test3", "type=b");
649         value = ast_variable_find(cat, "type");
650         if (strcmp(value, "b")) {
651                 ast_test_status_update(test, "Type %s != %s\n", "b", value);
652                 goto out;
653         }
654         ast_category_delete(cfg, cat);
655
656         cat = ast_category_get(cfg, "test3", "type=b");
657         if (cat) {
658                 ast_test_status_update(test, "Category b was not deleted.\n");
659                 goto out;
660         }
661
662         cat = ast_category_get(cfg, "test3", "type=a");
663         if (!cat) {
664                 ast_test_status_update(test, "Category a was deleted.\n");
665                 goto out;
666         }
667
668         value = ast_variable_find(cat, "type");
669         if (strcmp(value, "a")) {
670                 ast_test_status_update(test, "Type %s != %s\n", value, "a");
671                 goto out;
672         }
673
674         /* Basic regex stuff is handled by regcomp/regexec so not testing here.
675          * Still need to test multiple name/value pairs though.
676          */
677         ast_category_empty(cat);
678         ast_variable_insert(cat, ast_variable_new("type", "bx", "dummy"), "0");
679         ast_variable_insert(cat, ast_variable_new("e", "z", "dummy"), "0");
680
681         cat = ast_category_get(cfg, "test3", "type=.,e=z");
682         if (!cat) {
683                 ast_test_status_update(test, "Category not found.\n");
684                 goto out;
685         }
686
687         cat = ast_category_get(cfg, "test3", "type=.,e=zX");
688         if (cat) {
689                 ast_test_status_update(test, "Category found.\n");
690                 goto out;
691         }
692
693         cat = ast_category_get(cfg, "test3", "TEMPLATE=restrict,type=.,e=z");
694         if (cat) {
695                 ast_test_status_update(test, "Category found.\n");
696                 goto out;
697         }
698
699         res = AST_TEST_PASS;
700
701 out:
702         ast_config_destroy(cfg);
703         return res;
704 }
705
706 AST_TEST_DEFINE(config_template_ops)
707 {
708         enum ast_test_result_state res = AST_TEST_FAIL;
709         struct ast_config *cfg = NULL;
710         struct ast_category *cat = NULL;
711         char temp[32];
712         const char *value;
713         int i;
714
715         switch (cmd) {
716         case TEST_INIT:
717                 info->name = "config_template_ops";
718                 info->category = "/main/config/";
719                 info->summary = "Test template config ops";
720                 info->description =     "Test template config ops";
721                 return AST_TEST_NOT_RUN;
722         case TEST_EXECUTE:
723                 break;
724         }
725
726         cfg = ast_config_new();
727         if (!cfg) {
728                 return res;
729         }
730
731         /* load the config with 5 templates and 5 regular */
732         for(i = 0; i < 5; i++) {
733                 snprintf(temp, sizeof(temp), "test%d", i);
734                 cat = ast_category_new_template(temp, "dummy", -1);
735                 ast_variable_insert(cat, ast_variable_new("type", "a", "dummy"), "0");
736                 ast_category_append(cfg, cat);
737         }
738
739         for(i = 0; i < 5; i++) {
740                 snprintf(temp, sizeof(temp), "test%d", i);
741                 cat = ast_category_new(temp, "dummy", -1);
742                 ast_variable_insert(cat, ast_variable_new("type", "b", "dummy"), "0");
743                 ast_category_append(cfg, cat);
744         }
745
746         /* check the config has 5 template elements of type a */
747         i = 0;
748         cat = NULL;
749         while ((cat = ast_category_browse_filtered(cfg, NULL, cat, "TEMPLATES=restrict,type=a"))) {
750                 snprintf(temp, sizeof(temp), "test%d", i);
751                 if (strcmp(ast_category_get_name(cat), temp)) {
752                         ast_test_status_update(test, "%s != %s\n", ast_category_get_name(cat), temp);
753                         goto out;
754                 }
755                 value = ast_variable_find(cat, "type");
756                 if (!value || strcmp(value, "a")) {
757                         ast_test_status_update(test, "Type %s != %s\n", value, "a");
758                         goto out;
759                 }
760                 i++;
761         }
762         if (i != 5) {
763                 ast_test_status_update(test, "There were %d matches instead of 5.\n", i);
764                 goto out;
765         }
766
767         /* Test again with 'include'.  There should still only be 5 (type a) */
768         i = 0;
769         cat = NULL;
770         while ((cat = ast_category_browse_filtered(cfg, NULL, cat, "TEMPLATES=include,type=a"))) {
771                 snprintf(temp, sizeof(temp), "test%d", i);
772                 if (strcmp(ast_category_get_name(cat), temp)) {
773                         ast_test_status_update(test, "%s != %s\n", ast_category_get_name(cat), temp);
774                         goto out;
775                 }
776                 value = ast_variable_find(cat, "type");
777                 if (!value || strcmp(value, "a")) {
778                         ast_test_status_update(test, "Type %s != %s\n", value, "a");
779                         goto out;
780                 }
781                 i++;
782         }
783         if (i != 5) {
784                 ast_test_status_update(test, "There were %d matches instead of 5.\n", i);
785                 goto out;
786         }
787
788         /* Test again with 'include' but no type.  There should now be 10 (type a and type b) */
789         i = 0;
790         cat = NULL;
791         while ((cat = ast_category_browse_filtered(cfg, NULL, cat, "TEMPLATES=include"))) {
792                 i++;
793         }
794         if (i != 10) {
795                 ast_test_status_update(test, "There were %d matches instead of 10.\n", i);
796                 goto out;
797         }
798
799         /* Test again with 'restrict' and type b.  There should 0 */
800         i = 0;
801         cat = NULL;
802         while ((cat = ast_category_browse_filtered(cfg, NULL, cat, "TEMPLATES=restrict,type=b"))) {
803                 i++;
804         }
805         if (i != 0) {
806                 ast_test_status_update(test, "There were %d matches instead of 0.\n", i);
807                 goto out;
808         }
809
810         res = AST_TEST_PASS;
811
812 out:
813         ast_config_destroy(cfg);
814         return res;
815 }
816
817 /*!
818  * \brief Write the config file to disk
819  *
820  * This is necessary for testing config hooks since
821  * they are only triggered when a config is read from
822  * its intended storage medium
823  */
824 static int write_config_file(void)
825 {
826         int i;
827         FILE *config_file;
828         char filename[PATH_MAX];
829
830         snprintf(filename, sizeof(filename), "%s/%s",
831                         ast_config_AST_CONFIG_DIR, CONFIG_FILE);
832         config_file = fopen(filename, "w");
833
834         if (!config_file) {
835                 return -1;
836         }
837
838         for (i = 0; i < ARRAY_LEN(categories); ++i) {
839                 int j;
840                 fprintf(config_file, "[%s]\n", categories[i].category);
841                 for (j = 0; j < ARRAY_LEN(categories[i].vars); ++j) {
842                         fprintf(config_file, "%s = %s\n",
843                                         categories[i].vars[j].name,
844                                         categories[i].vars[j].val);
845                 }
846         }
847
848         fclose(config_file);
849         return 0;
850 }
851
852 /*!
853  * \brief Delete config file created by write_config_file
854  */
855 static void delete_config_file(void)
856 {
857         char filename[PATH_MAX];
858         snprintf(filename, sizeof(filename), "%s/%s",
859                         ast_config_AST_CONFIG_DIR, CONFIG_FILE);
860         unlink(filename);
861 }
862
863 /*
864  * Boolean to indicate if the config hook has run
865  */
866 static int hook_run;
867
868 /*
869  * Boolean to indicate if, when the hook runs, the
870  * data passed to it is what is expected
871  */
872 static int hook_config_sane;
873
874 static int hook_cb(struct ast_config *cfg)
875 {
876         hook_run = 1;
877         if (test_config_validity(cfg) == 0) {
878                 hook_config_sane = 1;
879         }
880         ast_config_destroy(cfg);
881         return 0;
882 }
883
884 AST_TEST_DEFINE(config_save)
885 {
886         enum ast_test_result_state res = AST_TEST_FAIL;
887         struct ast_flags config_flags = { 0 };
888         struct ast_config *cfg;
889         char config_filename[PATH_MAX];
890         char include_filename[PATH_MAX];
891         struct stat config_stat;
892         off_t before_save;
893
894         switch (cmd) {
895         case TEST_INIT:
896                 info->name = "config_save";
897                 info->category = "/main/config/";
898                 info->summary = "Test config save";
899                 info->description =
900                         "Test configuration save.";
901                 return AST_TEST_NOT_RUN;
902         case TEST_EXECUTE:
903                 break;
904         }
905
906         if (write_config_file()) {
907                 ast_test_status_update(test, "Could not write initial config files\n");
908                 return res;
909         }
910
911         snprintf(config_filename, PATH_MAX, "%s/%s", ast_config_AST_CONFIG_DIR, CONFIG_FILE);
912         snprintf(include_filename, PATH_MAX, "%s/%s", ast_config_AST_CONFIG_DIR, CONFIG_INCLUDE_FILE);
913
914         cfg = ast_config_load(CONFIG_FILE, config_flags);
915         if (!cfg) {
916                 ast_test_status_update(test, "Could not load config\n");
917                 goto out;
918         }
919
920         /* We need to re-save to get the generator header */
921         if (ast_config_text_file_save(CONFIG_FILE, cfg, "TEST")) {
922                 ast_test_status_update(test, "Unable to write files\n");
923                 goto out;
924         }
925
926         stat(config_filename, &config_stat);
927         before_save = config_stat.st_size;
928
929         if (!ast_include_new(cfg, CONFIG_FILE, CONFIG_INCLUDE_FILE, 0, NULL, 4, include_filename, PATH_MAX)) {
930                 ast_test_status_update(test, "Could not create include\n");
931                 goto out;
932         }
933
934         if (ast_config_text_file_save(CONFIG_FILE, cfg, "TEST")) {
935                 ast_test_status_update(test, "Unable to write files\n");
936                 goto out;
937         }
938
939         stat(config_filename, &config_stat);
940         if (config_stat.st_size <= before_save) {
941                 ast_test_status_update(test, "Did not save config file with #include\n");
942                 goto out;
943         }
944
945         res = AST_TEST_PASS;
946
947 out:
948         ast_config_destroy(cfg);
949         unlink(config_filename);
950         unlink(include_filename);
951
952         return res;
953 }
954
955 AST_TEST_DEFINE(config_hook)
956 {
957         enum ast_test_result_state res = AST_TEST_FAIL;
958         enum config_hook_flags hook_flags = { 0, };
959         struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED };
960         struct ast_config *cfg;
961
962         switch (cmd) {
963         case TEST_INIT:
964                 info->name = "config_hook";
965                 info->category = "/main/config/";
966                 info->summary = "Test config hooks";
967                 info->description =
968                         "Ensure that config hooks are called at approriate times,"
969                         "not called at inappropriate times, and that all information"
970                         "that should be present is present.";
971                 return AST_TEST_NOT_RUN;
972         case TEST_EXECUTE:
973                 break;
974         }
975
976         write_config_file();
977
978         /*
979          * Register a config hook to run when CONFIG_FILE is loaded by this module
980          */
981         ast_config_hook_register("test_hook",
982                         CONFIG_FILE,
983                         AST_MODULE,
984                         hook_flags,
985                         hook_cb);
986
987         /*
988          * Try loading the config file. This should result in the hook
989          * being called
990          */
991         cfg = ast_config_load(CONFIG_FILE, config_flags);
992         ast_config_destroy(cfg);
993         if (!hook_run || !hook_config_sane) {
994                 ast_test_status_update(test, "Config hook either did not run or was given bad data!\n");
995                 goto out;
996         }
997
998         /*
999          * Now try loading the wrong config file but from the right module.
1000          * Hook should not run
1001          */
1002         hook_run = 0;
1003         cfg = ast_config_load("asterisk.conf", config_flags);
1004         ast_config_destroy(cfg);
1005         if (hook_run) {
1006                 ast_test_status_update(test, "Config hook ran even though an incorrect file was specified.\n");
1007                 goto out;
1008         }
1009
1010         /*
1011          * Now try loading the correct config file but from the wrong module.
1012          * Hook should not run
1013          */
1014         hook_run = 0;
1015         cfg = ast_config_load2(CONFIG_FILE, "fake_module.so", config_flags);
1016         ast_config_destroy(cfg);
1017         if (hook_run) {
1018                 ast_test_status_update(test, "Config hook ran even though an incorrect module was specified.\n");
1019                 goto out;
1020         }
1021
1022         /*
1023          * Now try loading the file correctly, but without any changes to the file.
1024          * Hook should not run
1025          */
1026         hook_run = 0;
1027         cfg = ast_config_load(CONFIG_FILE, config_flags);
1028         /* Only destroy this cfg conditionally. Otherwise a crash happens. */
1029         if (cfg != CONFIG_STATUS_FILEUNCHANGED) {
1030                 ast_config_destroy(cfg);
1031         }
1032         if (hook_run) {
1033                 ast_test_status_update(test, "Config hook ran even though file contents had not changed\n");
1034                 goto out;
1035         }
1036
1037         res = AST_TEST_PASS;
1038
1039 out:
1040         delete_config_file();
1041         return res;
1042 }
1043
1044 enum {
1045         EXPECT_FAIL = 0,
1046         EXPECT_SUCCEED,
1047 };
1048
1049 #define TOOBIG_I32 "2147483649"
1050 #define TOOSMALL_I32 "-2147483649"
1051 #define TOOBIG_U32 "4294967297"
1052 #define TOOSMALL_U32 "-4294967297"
1053 #define DEFAULTVAL 42
1054 #define EPSILON 0.001
1055
1056 #define TEST_PARSE(input, should_succeed, expected_result, flags, result, ...) do {\
1057         int __res = ast_parse_arg(input, (flags), result, ##__VA_ARGS__); \
1058         if (!__res == !should_succeed) { \
1059                 ast_test_status_update(test, "ast_parse_arg failed on '%s'. %d/%d\n", input, __res, should_succeed); \
1060                 ret = AST_TEST_FAIL; \
1061         } else { \
1062                 if (((flags) & PARSE_TYPE) == PARSE_INT32) { \
1063                         int32_t *r = (int32_t *) (void *) result; \
1064                         int32_t e = (int32_t) expected_result; \
1065                         if (*r != e) { \
1066                                 ast_test_status_update(test, "ast_parse_arg int32_t failed with %d != %d\n", *r, e); \
1067                                 ret = AST_TEST_FAIL; \
1068                         } \
1069                 } else if (((flags) & PARSE_TYPE) == PARSE_UINT32) { \
1070                         uint32_t *r = (uint32_t *) (void *) result; \
1071                         uint32_t e = (uint32_t) expected_result; \
1072                         if (*r != e) { \
1073                                 ast_test_status_update(test, "ast_parse_arg uint32_t failed with %u != %u\n", *r, e); \
1074                                 ret = AST_TEST_FAIL; \
1075                         } \
1076                 } else if (((flags) & PARSE_TYPE) == PARSE_DOUBLE) { \
1077                         double *r = (double *) (void *) result; \
1078                         double e = (double) expected_result; \
1079                         if (fabs(*r - e) > EPSILON) { \
1080                                 ast_test_status_update(test, "ast_parse_arg double failed with %f != %f\n", *r, e); \
1081                                 ret = AST_TEST_FAIL; \
1082                         } \
1083                 } \
1084         } \
1085         *(result) = DEFAULTVAL; \
1086 } while (0)
1087
1088 AST_TEST_DEFINE(ast_parse_arg_test)
1089 {
1090         int ret = AST_TEST_PASS;
1091         int32_t int32_t_val = DEFAULTVAL;
1092         uint32_t uint32_t_val = DEFAULTVAL;
1093         double double_val = DEFAULTVAL;
1094
1095         switch (cmd) {
1096         case TEST_INIT:
1097                 info->name = "ast_parse_arg";
1098                 info->category = "/config/";
1099                 info->summary = "Test the output of ast_parse_arg";
1100                 info->description =
1101                         "Ensures that ast_parse_arg behaves as expected";
1102                 return AST_TEST_NOT_RUN;
1103         case TEST_EXECUTE:
1104                 break;
1105         }
1106
1107         /* int32 testing */
1108         TEST_PARSE("123", EXPECT_SUCCEED, 123, PARSE_INT32, &int32_t_val);
1109         TEST_PARSE("-123", EXPECT_SUCCEED, -123, PARSE_INT32, &int32_t_val);
1110         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_INT32, &int32_t_val);
1111         TEST_PARSE(TOOBIG_I32, EXPECT_FAIL, DEFAULTVAL, PARSE_INT32, &int32_t_val);
1112         TEST_PARSE(TOOSMALL_I32, EXPECT_FAIL, DEFAULTVAL, PARSE_INT32, &int32_t_val);
1113         TEST_PARSE("not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_INT32, &int32_t_val);
1114         TEST_PARSE("7not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_INT32, &int32_t_val);
1115         TEST_PARSE("123", EXPECT_SUCCEED, 123, PARSE_INT32 | PARSE_DEFAULT, &int32_t_val, 7);
1116         TEST_PARSE("-123", EXPECT_SUCCEED, -123, PARSE_INT32 | PARSE_DEFAULT, &int32_t_val, 7);
1117         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_INT32 | PARSE_DEFAULT, &int32_t_val, 7);
1118         TEST_PARSE(TOOBIG_I32, EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT, &int32_t_val, 7);
1119         TEST_PARSE(TOOSMALL_I32, EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT, &int32_t_val, 7);
1120         TEST_PARSE("not a number", EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT, &int32_t_val, 7);
1121         TEST_PARSE("7not a number", EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT, &int32_t_val, 7);
1122
1123         TEST_PARSE("123", EXPECT_SUCCEED, 123, PARSE_INT32 | PARSE_IN_RANGE, &int32_t_val, 0, 200);
1124         TEST_PARSE("-123", EXPECT_SUCCEED, -123, PARSE_INT32 | PARSE_IN_RANGE, &int32_t_val, -200, 100);
1125         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_INT32 | PARSE_IN_RANGE, &int32_t_val, -1, 0);
1126         TEST_PARSE("123", EXPECT_FAIL, DEFAULTVAL, PARSE_INT32 | PARSE_IN_RANGE, &int32_t_val, 0, 122);
1127         TEST_PARSE("-123", EXPECT_FAIL, DEFAULTVAL, PARSE_INT32 | PARSE_IN_RANGE, &int32_t_val, -122, 100);
1128         TEST_PARSE("0", EXPECT_FAIL, DEFAULTVAL, PARSE_INT32 | PARSE_IN_RANGE, &int32_t_val, 1, 100);
1129         TEST_PARSE(TOOBIG_I32, EXPECT_FAIL, DEFAULTVAL, PARSE_INT32 | PARSE_IN_RANGE, &int32_t_val, INT_MIN, INT_MAX);
1130         TEST_PARSE(TOOSMALL_I32, EXPECT_FAIL, DEFAULTVAL, PARSE_INT32 | PARSE_IN_RANGE, &int32_t_val, INT_MIN, INT_MAX);
1131         TEST_PARSE("not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_INT32 | PARSE_IN_RANGE, &int32_t_val, INT_MIN, INT_MAX);
1132         TEST_PARSE("7not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_INT32 | PARSE_IN_RANGE, &int32_t_val, INT_MIN, INT_MAX);
1133         TEST_PARSE("123", EXPECT_FAIL, DEFAULTVAL, PARSE_INT32 | PARSE_OUT_RANGE, &int32_t_val, 0, 200);
1134         TEST_PARSE("-123", EXPECT_FAIL, DEFAULTVAL, PARSE_INT32 | PARSE_OUT_RANGE, &int32_t_val, -200, 100);
1135         TEST_PARSE("0", EXPECT_FAIL, DEFAULTVAL, PARSE_INT32 | PARSE_OUT_RANGE, &int32_t_val, -1, 0);
1136         TEST_PARSE("123", EXPECT_SUCCEED, 123, PARSE_INT32 | PARSE_OUT_RANGE, &int32_t_val, 0, 122);
1137         TEST_PARSE("-123", EXPECT_SUCCEED, -123, PARSE_INT32 | PARSE_OUT_RANGE, &int32_t_val, -122, 100);
1138         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_INT32 | PARSE_OUT_RANGE, &int32_t_val, 1, 100);
1139         TEST_PARSE(TOOBIG_I32, EXPECT_FAIL, DEFAULTVAL, PARSE_INT32 | PARSE_OUT_RANGE, &int32_t_val, INT_MIN, INT_MAX);
1140         TEST_PARSE(TOOSMALL_I32, EXPECT_FAIL, DEFAULTVAL, PARSE_INT32 | PARSE_OUT_RANGE, &int32_t_val, INT_MIN, INT_MAX);
1141         TEST_PARSE("not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_INT32 | PARSE_OUT_RANGE, &int32_t_val, INT_MIN, INT_MAX);
1142         TEST_PARSE("7not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_INT32 | PARSE_OUT_RANGE, &int32_t_val, INT_MIN, INT_MAX);
1143
1144         TEST_PARSE("123", EXPECT_SUCCEED, 123, PARSE_INT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &int32_t_val, 7, 0, 200);
1145         TEST_PARSE("-123", EXPECT_SUCCEED, -123, PARSE_INT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &int32_t_val, 7, -200, 100);
1146         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_INT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &int32_t_val, 7, -1, 0);
1147         TEST_PARSE("123", EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &int32_t_val, 7, 0, 122);
1148         TEST_PARSE("-123", EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &int32_t_val, 7, -122, 100);
1149         TEST_PARSE("0", EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &int32_t_val, 7, 1, 100);
1150         TEST_PARSE(TOOBIG_I32, EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &int32_t_val, 7, INT_MIN, INT_MAX);
1151         TEST_PARSE(TOOSMALL_I32, EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &int32_t_val, 7, INT_MIN, INT_MAX);
1152         TEST_PARSE("not a number", EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &int32_t_val, 7, INT_MIN, INT_MAX);
1153         TEST_PARSE("7not a number", EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &int32_t_val, 7, INT_MIN, INT_MAX);
1154         TEST_PARSE("123", EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &int32_t_val, 7, 0, 200);
1155         TEST_PARSE("-123", EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &int32_t_val, 7, -200, 100);
1156         TEST_PARSE("0", EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &int32_t_val, 7, -1, 0);
1157         TEST_PARSE("123", EXPECT_SUCCEED, 123, PARSE_INT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &int32_t_val, 7, 0, 122);
1158         TEST_PARSE("-123", EXPECT_SUCCEED, -123, PARSE_INT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &int32_t_val, 7, -122, 100);
1159         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_INT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &int32_t_val, 7, 1, 100);
1160         TEST_PARSE(TOOBIG_I32, EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &int32_t_val, 7, INT_MIN, INT_MAX);
1161         TEST_PARSE(TOOSMALL_I32, EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &int32_t_val, 7, INT_MIN, INT_MAX);
1162         TEST_PARSE("not a number", EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &int32_t_val, 7, INT_MIN, INT_MAX);
1163         TEST_PARSE("7not a number", EXPECT_FAIL, 7, PARSE_INT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &int32_t_val, 7, INT_MIN, INT_MAX);
1164
1165         /* uuint32 testing */
1166         TEST_PARSE("123", EXPECT_SUCCEED, 123, PARSE_UINT32, &uint32_t_val);
1167         TEST_PARSE("-123", EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32, &uint32_t_val);
1168         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_UINT32, &uint32_t_val);
1169         TEST_PARSE(TOOBIG_U32, EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32, &uint32_t_val);
1170         TEST_PARSE(TOOSMALL_U32, EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32, &uint32_t_val);
1171         TEST_PARSE("not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32, &uint32_t_val);
1172         TEST_PARSE("7not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32, &uint32_t_val);
1173
1174         TEST_PARSE("123", EXPECT_SUCCEED, 123, PARSE_UINT32 | PARSE_DEFAULT, &uint32_t_val, 7);
1175         TEST_PARSE("-123", EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT, &uint32_t_val, 7);
1176         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_UINT32 | PARSE_DEFAULT, &uint32_t_val, 7);
1177         TEST_PARSE(TOOBIG_U32, EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT, &uint32_t_val, 7);
1178         TEST_PARSE(TOOSMALL_U32, EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT, &uint32_t_val, 7);
1179         TEST_PARSE("not a number", EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT, &uint32_t_val, 7);
1180         TEST_PARSE("7not a number", EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT, &uint32_t_val, 7);
1181
1182         TEST_PARSE("123", EXPECT_SUCCEED, 123, PARSE_UINT32 | PARSE_IN_RANGE, &uint32_t_val, 0, 200);
1183         TEST_PARSE("-123", EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32 | PARSE_IN_RANGE, &uint32_t_val, 0, 200);
1184         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_UINT32 | PARSE_IN_RANGE, &uint32_t_val, 0, 1);
1185
1186         TEST_PARSE("123", EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32 | PARSE_IN_RANGE, &uint32_t_val, 0, 122);
1187         TEST_PARSE("0", EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32 | PARSE_IN_RANGE, &uint32_t_val, 1, 100);
1188         TEST_PARSE(TOOBIG_U32, EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32 | PARSE_IN_RANGE, &uint32_t_val, INT_MIN, INT_MAX);
1189         TEST_PARSE(TOOSMALL_U32, EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32 | PARSE_IN_RANGE, &uint32_t_val, INT_MIN, INT_MAX);
1190         TEST_PARSE("not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32 | PARSE_IN_RANGE, &uint32_t_val, INT_MIN, INT_MAX);
1191         TEST_PARSE("7not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32 | PARSE_IN_RANGE, &uint32_t_val, INT_MIN, INT_MAX);
1192
1193         TEST_PARSE("123", EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32 | PARSE_OUT_RANGE, &uint32_t_val, 0, 200);
1194         TEST_PARSE("-123", EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32 | PARSE_OUT_RANGE, &uint32_t_val, 0, 200);
1195         TEST_PARSE("0", EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32 | PARSE_OUT_RANGE, &uint32_t_val, 0, 1);
1196
1197         TEST_PARSE("123", EXPECT_SUCCEED, 123, PARSE_UINT32 | PARSE_OUT_RANGE, &uint32_t_val, 0, 122);
1198         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_UINT32 | PARSE_OUT_RANGE, &uint32_t_val, 1, 100);
1199         TEST_PARSE(TOOBIG_U32, EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32 | PARSE_OUT_RANGE, &uint32_t_val, INT_MIN, INT_MAX);
1200         TEST_PARSE(TOOSMALL_U32, EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32 | PARSE_OUT_RANGE, &uint32_t_val, INT_MIN, INT_MAX);
1201         TEST_PARSE("not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32 | PARSE_OUT_RANGE, &uint32_t_val, INT_MIN, INT_MAX);
1202         TEST_PARSE("7not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32 | PARSE_OUT_RANGE, &uint32_t_val, INT_MIN, INT_MAX);
1203
1204         TEST_PARSE("123", EXPECT_SUCCEED, 123, PARSE_UINT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &uint32_t_val, 7, 0, 200);
1205         TEST_PARSE("-123", EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &uint32_t_val, 7, 0, 200);
1206         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_UINT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &uint32_t_val, 7, 0, 1);
1207         TEST_PARSE("123", EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &uint32_t_val, 7, 0, 122);
1208         TEST_PARSE("0", EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &uint32_t_val, 7, 1, 100);
1209         TEST_PARSE(TOOBIG_U32, EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &uint32_t_val, 7, INT_MIN, INT_MAX);
1210         TEST_PARSE(TOOSMALL_U32, EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &uint32_t_val, 7, INT_MIN, INT_MAX);
1211         TEST_PARSE("not a number", EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &uint32_t_val, 7, INT_MIN, INT_MAX);
1212         TEST_PARSE("7not a number", EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT | PARSE_IN_RANGE, &uint32_t_val, 7, INT_MIN, INT_MAX);
1213         TEST_PARSE("123", EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &uint32_t_val, 7, 0, 200);
1214         TEST_PARSE("-123", EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &uint32_t_val, 7, 0, 100);
1215         TEST_PARSE("0", EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &uint32_t_val, 7, 0, 1);
1216         TEST_PARSE("123", EXPECT_SUCCEED, 123, PARSE_UINT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &uint32_t_val, 7, 0, 122);
1217         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_UINT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &uint32_t_val, 7, 1, 100);
1218         TEST_PARSE(TOOBIG_U32, EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &uint32_t_val, 7, INT_MIN, INT_MAX);
1219         TEST_PARSE(TOOSMALL_U32, EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &uint32_t_val, 7, INT_MIN, INT_MAX);
1220         TEST_PARSE("not a number", EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &uint32_t_val, 7, INT_MIN, INT_MAX);
1221         TEST_PARSE("7not a number", EXPECT_FAIL, 7, PARSE_UINT32 | PARSE_DEFAULT | PARSE_OUT_RANGE, &uint32_t_val, 7, INT_MIN, INT_MAX);
1222
1223         TEST_PARSE("   -123", EXPECT_FAIL, DEFAULTVAL, PARSE_UINT32, &uint32_t_val);
1224
1225         /* double testing */
1226         TEST_PARSE("123", EXPECT_SUCCEED, 123, PARSE_DOUBLE, &double_val);
1227         TEST_PARSE("123.123", EXPECT_SUCCEED, 123.123, PARSE_DOUBLE, &double_val);
1228         TEST_PARSE("-123", EXPECT_SUCCEED, -123, PARSE_DOUBLE, &double_val);
1229         TEST_PARSE("-123.123", EXPECT_SUCCEED, -123.123, PARSE_DOUBLE, &double_val);
1230         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_DOUBLE, &double_val);
1231         TEST_PARSE("not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_DOUBLE, &double_val);
1232         TEST_PARSE("7.0not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_DOUBLE, &double_val);
1233         TEST_PARSE("123.123", EXPECT_SUCCEED, 123.123, PARSE_DOUBLE | PARSE_DEFAULT, &double_val, 7.0);
1234         TEST_PARSE("-123.123", EXPECT_SUCCEED, -123.123, PARSE_DOUBLE | PARSE_DEFAULT, &double_val, 7.0);
1235         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_DOUBLE | PARSE_DEFAULT, &double_val, 7.0);
1236         TEST_PARSE("not a number", EXPECT_FAIL, 7.0, PARSE_DOUBLE | PARSE_DEFAULT, &double_val, 7.0);
1237         TEST_PARSE("7.0not a number", EXPECT_FAIL, 7.0, PARSE_DOUBLE | PARSE_DEFAULT, &double_val, 7.0);
1238
1239         TEST_PARSE("123.123", EXPECT_SUCCEED, 123.123, PARSE_DOUBLE | PARSE_IN_RANGE, &double_val, 0.0, 200.0);
1240         TEST_PARSE("-123.123", EXPECT_SUCCEED, -123.123, PARSE_DOUBLE | PARSE_IN_RANGE, &double_val, -200.0, 100.0);
1241         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_DOUBLE | PARSE_IN_RANGE, &double_val, -1.0, 0.0);
1242         TEST_PARSE("123.123", EXPECT_FAIL, DEFAULTVAL, PARSE_DOUBLE | PARSE_IN_RANGE, &double_val, 0.0, 122.0);
1243         TEST_PARSE("-123.123", EXPECT_FAIL, DEFAULTVAL, PARSE_DOUBLE | PARSE_IN_RANGE, &double_val, -122.0, 100.0);
1244         TEST_PARSE("0", EXPECT_FAIL, DEFAULTVAL, PARSE_DOUBLE | PARSE_IN_RANGE, &double_val, 1.0, 100.0);
1245         TEST_PARSE("not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_DOUBLE | PARSE_IN_RANGE, &double_val, -HUGE_VAL, HUGE_VAL);
1246         TEST_PARSE("7not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_DOUBLE | PARSE_IN_RANGE, &double_val, -HUGE_VAL, HUGE_VAL);
1247         TEST_PARSE("123.123", EXPECT_FAIL, DEFAULTVAL, PARSE_DOUBLE | PARSE_OUT_RANGE, &double_val, 0.0, 200.0);
1248         TEST_PARSE("-123.123", EXPECT_FAIL, DEFAULTVAL, PARSE_DOUBLE | PARSE_OUT_RANGE, &double_val, -200.0, 100.0);
1249         TEST_PARSE("0", EXPECT_FAIL, DEFAULTVAL, PARSE_DOUBLE | PARSE_OUT_RANGE, &double_val, -1.0, 0.0);
1250         TEST_PARSE("123.123", EXPECT_SUCCEED, 123.123, PARSE_DOUBLE | PARSE_OUT_RANGE, &double_val, 0.0, 122.0);
1251         TEST_PARSE("-123.123", EXPECT_SUCCEED, -123.123, PARSE_DOUBLE | PARSE_OUT_RANGE, &double_val, -122.0, 100.0);
1252         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_DOUBLE | PARSE_OUT_RANGE, &double_val, 1.0, 100.0);
1253         TEST_PARSE("not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_DOUBLE | PARSE_OUT_RANGE, &double_val, -HUGE_VAL, HUGE_VAL);
1254         TEST_PARSE("7not a number", EXPECT_FAIL, DEFAULTVAL, PARSE_DOUBLE | PARSE_OUT_RANGE, &double_val, -HUGE_VAL, HUGE_VAL);
1255
1256         TEST_PARSE("123.123", EXPECT_SUCCEED, 123.123, PARSE_DOUBLE | PARSE_DEFAULT | PARSE_IN_RANGE, &double_val, 7.0, 0.0, 200.0);
1257         TEST_PARSE("-123.123", EXPECT_SUCCEED, -123.123, PARSE_DOUBLE | PARSE_DEFAULT | PARSE_IN_RANGE, &double_val, 7.0, -200.0, 100.0);
1258         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_DOUBLE | PARSE_DEFAULT | PARSE_IN_RANGE, &double_val, 7.0, -1.0, 0.0);
1259         TEST_PARSE("123.123", EXPECT_FAIL, 7.0, PARSE_DOUBLE | PARSE_DEFAULT | PARSE_IN_RANGE, &double_val, 7.0, 0.0, 122.0);
1260         TEST_PARSE("-123.123", EXPECT_FAIL, 7.0, PARSE_DOUBLE | PARSE_DEFAULT | PARSE_IN_RANGE, &double_val, 7.0, -122.0, 100.0);
1261         TEST_PARSE("0", EXPECT_FAIL, 7.0, PARSE_DOUBLE | PARSE_DEFAULT | PARSE_IN_RANGE, &double_val, 7.0, 1.0, 100.0);
1262         TEST_PARSE("not a number", EXPECT_FAIL, 7.0, PARSE_DOUBLE | PARSE_DEFAULT | PARSE_IN_RANGE, &double_val, 7.0, -HUGE_VAL, HUGE_VAL);
1263         TEST_PARSE("7not a number", EXPECT_FAIL, 7.0, PARSE_DOUBLE | PARSE_DEFAULT | PARSE_IN_RANGE, &double_val, 7.0, -HUGE_VAL, HUGE_VAL);
1264         TEST_PARSE("123.123", EXPECT_FAIL, 7.0, PARSE_DOUBLE | PARSE_DEFAULT | PARSE_OUT_RANGE, &double_val, 7.0, 0.0, 200.0);
1265         TEST_PARSE("-123.123", EXPECT_FAIL, 7.0, PARSE_DOUBLE | PARSE_DEFAULT | PARSE_OUT_RANGE, &double_val, 7.0, -200.0, 100.0);
1266         TEST_PARSE("0", EXPECT_FAIL, 7.0, PARSE_DOUBLE | PARSE_DEFAULT | PARSE_OUT_RANGE, &double_val, 7.0, -1.0, 0.0);
1267         TEST_PARSE("123.123", EXPECT_SUCCEED, 123.123, PARSE_DOUBLE | PARSE_DEFAULT | PARSE_OUT_RANGE, &double_val, 7.0, 0.0, 122.0);
1268         TEST_PARSE("-123.123", EXPECT_SUCCEED, -123.123, PARSE_DOUBLE | PARSE_DEFAULT | PARSE_OUT_RANGE, &double_val, 7.0, -122.0, 100.0);
1269         TEST_PARSE("0", EXPECT_SUCCEED, 0, PARSE_DOUBLE | PARSE_DEFAULT | PARSE_OUT_RANGE, &double_val, 7.0, 1.0, 100.0);
1270         TEST_PARSE("not a number", EXPECT_FAIL, 7.0, PARSE_DOUBLE | PARSE_DEFAULT | PARSE_OUT_RANGE, &double_val, 7.0, -HUGE_VAL, HUGE_VAL);
1271         TEST_PARSE("7not a number", EXPECT_FAIL, 7.0, PARSE_DOUBLE | PARSE_DEFAULT | PARSE_OUT_RANGE, &double_val, 7.0, -HUGE_VAL, HUGE_VAL);
1272
1273         /* ast_sockaddr_parse is tested extensively in test_netsock2.c and PARSE_ADDR is a very simple wrapper */
1274
1275         return ret;
1276 }
1277 struct test_item {
1278         AST_DECLARE_STRING_FIELDS(
1279                 AST_STRING_FIELD(name);
1280                 AST_STRING_FIELD(stropt);
1281         );
1282         int32_t intopt;
1283         uint32_t uintopt;
1284         unsigned int flags;
1285         double doubleopt;
1286         struct ast_sockaddr sockaddropt;
1287         int boolopt;
1288         struct ast_ha *aclopt;
1289         struct ast_format_cap *codeccapopt;
1290         unsigned int customopt:1;
1291 };
1292 struct test_config {
1293         struct test_item *global;
1294         struct test_item *global_defaults;
1295         struct ao2_container *items;
1296 };
1297
1298 static int test_item_hash(const void *obj, const int flags)
1299 {
1300         const struct test_item *item = obj;
1301         const char *name = (flags & OBJ_KEY) ? obj : item->name;
1302         return ast_str_case_hash(name);
1303 }
1304 static int test_item_cmp(void *obj, void *arg, int flags)
1305 {
1306         struct test_item *one = obj, *two = arg;
1307         const char *match = (flags & OBJ_KEY) ? arg : two->name;
1308         return strcasecmp(one->name, match) ? 0 : (CMP_MATCH | CMP_STOP);
1309 }
1310 static void test_item_destructor(void *obj)
1311 {
1312         struct test_item *item = obj;
1313         ast_string_field_free_memory(item);
1314         ao2_cleanup(item->codeccapopt);
1315         if (item->aclopt) {
1316                 ast_free_ha(item->aclopt);
1317         }
1318         return;
1319 }
1320 static void *test_item_alloc(const char *cat)
1321 {
1322         struct test_item *item;
1323         if (!(item = ao2_alloc(sizeof(*item), test_item_destructor))) {
1324                 return NULL;
1325         }
1326         if (ast_string_field_init(item, 128)) {
1327                 ao2_ref(item, -1);
1328                 return NULL;
1329         }
1330         if (!(item->codeccapopt = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
1331                 ao2_ref(item, -1);
1332                 return NULL;
1333         }
1334         ast_string_field_set(item, name, cat);
1335         return item;
1336 }
1337 static void test_config_destructor(void *obj)
1338 {
1339         struct test_config *cfg = obj;
1340         ao2_cleanup(cfg->global);
1341         ao2_cleanup(cfg->global_defaults);
1342         ao2_cleanup(cfg->items);
1343 }
1344 static void *test_config_alloc(void)
1345 {
1346         struct test_config *cfg;
1347         if (!(cfg = ao2_alloc(sizeof(*cfg), test_config_destructor))) {
1348                 goto error;
1349         }
1350         if (!(cfg->global = test_item_alloc("global"))) {
1351                 goto error;
1352         }
1353         if (!(cfg->global_defaults = test_item_alloc("global_defaults"))) {
1354                 goto error;
1355         }
1356         if (!(cfg->items = ao2_container_alloc(1, test_item_hash, test_item_cmp))) {
1357                 goto error;
1358         }
1359         return cfg;
1360 error:
1361         ao2_cleanup(cfg);
1362         return NULL;
1363 }
1364 static void *test_item_find(struct ao2_container *container, const char *cat)
1365 {
1366         return ao2_find(container, cat, OBJ_KEY);
1367 }
1368
1369 static int customopt_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
1370 {
1371         struct test_item *item = obj;
1372         if (!strcasecmp(var->name, "customopt")) {
1373                 item->customopt = ast_true(var->value);
1374         } else {
1375                 return -1;
1376         }
1377
1378         return 0;
1379 }
1380
1381 static struct aco_type global = {
1382         .type = ACO_GLOBAL,
1383         .item_offset = offsetof(struct test_config, global),
1384         .category_match = ACO_WHITELIST,
1385         .category = "^global$",
1386 };
1387 static struct aco_type global_defaults = {
1388         .type = ACO_GLOBAL,
1389         .item_offset = offsetof(struct test_config, global_defaults),
1390         .category_match = ACO_WHITELIST,
1391         .category = "^global_defaults$",
1392 };
1393 static struct aco_type item = {
1394         .type = ACO_ITEM,
1395         .category_match = ACO_BLACKLIST,
1396         .category = "^(global|global_defaults)$",
1397         .item_alloc = test_item_alloc,
1398         .item_find = test_item_find,
1399         .item_offset = offsetof(struct test_config, items),
1400 };
1401
1402 struct aco_file config_test_conf = {
1403         .filename = "config_test.conf",
1404         .types = ACO_TYPES(&global, &global_defaults, &item),
1405 };
1406
1407 static AO2_GLOBAL_OBJ_STATIC(global_obj);
1408 CONFIG_INFO_TEST(cfg_info, global_obj, test_config_alloc,
1409         .files = ACO_FILES(&config_test_conf),
1410 );
1411
1412 AST_TEST_DEFINE(config_options_test)
1413 {
1414         int res = AST_TEST_PASS, x, error;
1415         struct test_item defaults = { 0, }, configs = { 0, };
1416         struct test_item *arr[4];
1417         struct ast_sockaddr acl_allow = {{ 0, }}, acl_fail = {{ 0, }};
1418         RAII_VAR(struct test_config *, cfg, NULL, ao2_cleanup);
1419         RAII_VAR(struct test_item *, item, NULL, ao2_cleanup);
1420         RAII_VAR(struct test_item *, item_defaults, NULL, ao2_cleanup);
1421
1422         switch (cmd) {
1423         case TEST_INIT:
1424                 info->name = "config_options_test";
1425                 info->category = "/config/";
1426                 info->summary = "Config opptions unit test";
1427                 info->description =
1428                         "Tests the Config Options API";
1429                 return AST_TEST_NOT_RUN;
1430         case TEST_EXECUTE:
1431                 break;
1432         }
1433
1434 #define INT_DEFAULT "-2"
1435 #define INT_CONFIG "-1"
1436 #define UINT_DEFAULT "2"
1437 #define UINT_CONFIG "1"
1438 #define DOUBLE_DEFAULT "1.1"
1439 #define DOUBLE_CONFIG "0.1"
1440 #define SOCKADDR_DEFAULT "4.3.2.1:4321"
1441 #define SOCKADDR_CONFIG "1.2.3.4:1234"
1442 #define BOOL_DEFAULT "false"
1443 #define BOOL_CONFIG "true"
1444 #define BOOLFLAG1_DEFAULT "false"
1445 #define BOOLFLAG1_CONFIG "true"
1446 #define BOOLFLAG2_DEFAULT "false"
1447 #define BOOLFLAG2_CONFIG "false"
1448 #define BOOLFLAG3_DEFAULT "false"
1449 #define BOOLFLAG3_CONFIG "true"
1450 #define ACL_DEFAULT NULL
1451 #define ACL_CONFIG_PERMIT "1.2.3.4/32"
1452 #define ACL_CONFIG_DENY "0.0.0.0/0"
1453 #define CODEC_DEFAULT "!all,alaw"
1454 #define CODEC_CONFIG "!all,ulaw,g729"
1455 #define STR_DEFAULT "default"
1456 #define STR_CONFIG "test"
1457 #define CUSTOM_DEFAULT "no"
1458 #define CUSTOM_CONFIG "yes"
1459
1460 #define BOOLFLAG1 1 << 0
1461 #define BOOLFLAG2 1 << 1
1462 #define BOOLFLAG3 1 << 2
1463
1464         if (aco_info_init(&cfg_info)) {
1465                 ast_test_status_update(test, "Could not init cfg info\n");
1466                 return AST_TEST_FAIL;
1467         }
1468
1469         /* Register all options */
1470         aco_option_register(&cfg_info, "intopt", ACO_EXACT, config_test_conf.types, INT_DEFAULT, OPT_INT_T, 0, FLDSET(struct test_item, intopt));
1471         aco_option_register(&cfg_info, "uintopt", ACO_EXACT, config_test_conf.types, UINT_DEFAULT, OPT_UINT_T, 0, FLDSET(struct test_item, uintopt));
1472         aco_option_register(&cfg_info, "doubleopt", ACO_EXACT, config_test_conf.types, DOUBLE_DEFAULT, OPT_DOUBLE_T, 0, FLDSET(struct test_item, doubleopt));
1473         aco_option_register(&cfg_info, "sockaddropt", ACO_EXACT, config_test_conf.types, SOCKADDR_DEFAULT, OPT_SOCKADDR_T, 0, FLDSET(struct test_item, sockaddropt));
1474         aco_option_register(&cfg_info, "boolopt", ACO_EXACT, config_test_conf.types, BOOL_DEFAULT, OPT_BOOL_T, 1, FLDSET(struct test_item, boolopt));
1475         aco_option_register(&cfg_info, "boolflag1", ACO_EXACT, config_test_conf.types, BOOLFLAG1_DEFAULT, OPT_BOOLFLAG_T, 1, FLDSET(struct test_item, flags), BOOLFLAG1);
1476         aco_option_register(&cfg_info, "boolflag2", ACO_EXACT, config_test_conf.types, BOOLFLAG2_DEFAULT, OPT_BOOLFLAG_T, 1, FLDSET(struct test_item, flags), BOOLFLAG2);
1477         aco_option_register(&cfg_info, "boolflag3", ACO_EXACT, config_test_conf.types, BOOLFLAG3_DEFAULT, OPT_BOOLFLAG_T, 1, FLDSET(struct test_item, flags), BOOLFLAG3);
1478         aco_option_register(&cfg_info, "aclpermitopt", ACO_EXACT, config_test_conf.types, ACL_DEFAULT, OPT_ACL_T, 1, FLDSET(struct test_item, aclopt));
1479         aco_option_register(&cfg_info, "acldenyopt", ACO_EXACT, config_test_conf.types, ACL_DEFAULT, OPT_ACL_T, 0, FLDSET(struct test_item, aclopt));
1480         aco_option_register(&cfg_info, "codecopt", ACO_EXACT, config_test_conf.types, CODEC_DEFAULT, OPT_CODEC_T, 1, FLDSET(struct test_item, codeccapopt));
1481         aco_option_register(&cfg_info, "stropt", ACO_EXACT, config_test_conf.types, STR_DEFAULT, OPT_STRINGFIELD_T, 0, STRFLDSET(struct test_item, stropt));
1482         aco_option_register_custom(&cfg_info, "customopt", ACO_EXACT, config_test_conf.types, CUSTOM_DEFAULT, customopt_handler, 0);
1483         aco_option_register_deprecated(&cfg_info, "permit", config_test_conf.types, "aclpermitopt");
1484         aco_option_register_deprecated(&cfg_info, "deny", config_test_conf.types, "acldenyopt");
1485
1486         if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
1487                 ast_test_status_update(test, "Could not parse config\n");
1488                 return AST_TEST_FAIL;
1489         }
1490
1491         ast_parse_arg(INT_DEFAULT, PARSE_INT32, &defaults.intopt);
1492         ast_parse_arg(INT_CONFIG, PARSE_INT32, &configs.intopt);
1493         ast_parse_arg(UINT_DEFAULT, PARSE_UINT32, &defaults.uintopt);
1494         ast_parse_arg(UINT_CONFIG, PARSE_UINT32, &configs.uintopt);
1495         ast_parse_arg(DOUBLE_DEFAULT, PARSE_DOUBLE, &defaults.doubleopt);
1496         ast_parse_arg(DOUBLE_CONFIG, PARSE_DOUBLE, &configs.doubleopt);
1497         ast_parse_arg(SOCKADDR_DEFAULT, PARSE_ADDR, &defaults.sockaddropt);
1498         ast_parse_arg(SOCKADDR_CONFIG, PARSE_ADDR, &configs.sockaddropt);
1499         defaults.boolopt = ast_true(BOOL_DEFAULT);
1500         configs.boolopt = ast_true(BOOL_CONFIG);
1501         ast_set2_flag(&defaults, ast_true(BOOLFLAG1_DEFAULT), BOOLFLAG1);
1502         ast_set2_flag(&defaults, ast_true(BOOLFLAG2_DEFAULT), BOOLFLAG2);
1503         ast_set2_flag(&defaults, ast_true(BOOLFLAG3_DEFAULT), BOOLFLAG3);
1504         ast_set2_flag(&configs, ast_true(BOOLFLAG1_CONFIG), BOOLFLAG1);
1505         ast_set2_flag(&configs, ast_true(BOOLFLAG2_CONFIG), BOOLFLAG2);
1506         ast_set2_flag(&configs, ast_true(BOOLFLAG3_CONFIG), BOOLFLAG3);
1507
1508         defaults.aclopt = NULL;
1509         configs.aclopt = ast_append_ha("deny", ACL_CONFIG_DENY, configs.aclopt, &error);
1510         configs.aclopt = ast_append_ha("permit", ACL_CONFIG_PERMIT, configs.aclopt, &error);
1511         ast_sockaddr_parse(&acl_allow, "1.2.3.4", PARSE_PORT_FORBID);
1512         ast_sockaddr_parse(&acl_fail, "1.1.1.1", PARSE_PORT_FORBID);
1513
1514         defaults.codeccapopt = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
1515         ast_format_cap_update_by_allow_disallow(defaults.codeccapopt, CODEC_DEFAULT, 1);
1516
1517         configs.codeccapopt = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
1518         ast_format_cap_update_by_allow_disallow(configs.codeccapopt, CODEC_CONFIG, 1);
1519
1520         ast_string_field_init(&defaults, 128);
1521         ast_string_field_init(&configs, 128);
1522         ast_string_field_set(&defaults, stropt, STR_DEFAULT);
1523         ast_string_field_set(&configs, stropt, STR_CONFIG);
1524
1525         defaults.customopt = ast_true(CUSTOM_DEFAULT);
1526         configs.customopt = ast_true(CUSTOM_CONFIG);
1527
1528
1529         cfg = ao2_global_obj_ref(global_obj);
1530         if (!(item = ao2_find(cfg->items, "item", OBJ_KEY))) {
1531                 ast_test_status_update(test, "could not look up 'item'\n");
1532                 return AST_TEST_FAIL;
1533         }
1534         if (!(item_defaults = ao2_find(cfg->items, "item_defaults", OBJ_KEY))) {
1535                 ast_test_status_update(test, "could not look up 'item_defaults'\n");
1536                 return AST_TEST_FAIL;
1537         }
1538         arr[0] = cfg->global;
1539         arr[1] = item;
1540         arr[2] = cfg->global_defaults;
1541         arr[3] = item_defaults;
1542         /* Test global and item against configs, global_defaults and item_defaults against defaults */
1543
1544 #define NOT_EQUAL_FAIL(field, format)  \
1545         if (arr[x]->field != control->field) { \
1546                 ast_test_status_update(test, "%s did not match: " format " != " format " with x = %d\n", #field, arr[x]->field, control->field, x); \
1547                 res = AST_TEST_FAIL; \
1548         }
1549         for (x = 0; x < 4; x++) {
1550                 struct test_item *control = x < 2 ? &configs : &defaults;
1551
1552                 NOT_EQUAL_FAIL(intopt, "%d");
1553                 NOT_EQUAL_FAIL(uintopt, "%u");
1554                 NOT_EQUAL_FAIL(boolopt, "%d");
1555                 NOT_EQUAL_FAIL(flags, "%u");
1556                 NOT_EQUAL_FAIL(customopt, "%d");
1557                 if (fabs(arr[x]->doubleopt - control->doubleopt) > 0.001) {
1558                         ast_test_status_update(test, "doubleopt did not match: %f vs %f on loop %d\n", arr[x]->doubleopt, control->doubleopt, x);
1559                         res = AST_TEST_FAIL;
1560                 }
1561                 if (ast_sockaddr_cmp(&arr[x]->sockaddropt, &control->sockaddropt)) {
1562                         ast_test_status_update(test, "sockaddr did not match on loop %d\n", x);
1563                         res = AST_TEST_FAIL;
1564                 }
1565                 if (!ast_format_cap_identical(arr[x]->codeccapopt, control->codeccapopt)) {
1566                         struct ast_str *codec_buf1 = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
1567                         struct ast_str *codec_buf2 = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
1568
1569                         ast_test_status_update(test, "format did not match: '%s' vs '%s' on loop %d\n",
1570                                 ast_format_cap_get_names(arr[x]->codeccapopt, &codec_buf1),
1571                                 ast_format_cap_get_names(control->codeccapopt, &codec_buf2),
1572                                 x);
1573                         res = AST_TEST_FAIL;
1574                 }
1575                 if (strcasecmp(arr[x]->stropt, control->stropt)) {
1576                         ast_test_status_update(test, "stropt did not match: '%s' vs '%s' on loop %d\n", arr[x]->stropt, control->stropt, x);
1577                         res = AST_TEST_FAIL;
1578                 }
1579                 if (arr[x]->aclopt != control->aclopt && (ast_apply_ha(arr[x]->aclopt, &acl_allow) != ast_apply_ha(control->aclopt, &acl_allow) ||
1580                                 ast_apply_ha(arr[x]->aclopt, &acl_fail) != ast_apply_ha(control->aclopt, &acl_fail))) {
1581                         ast_test_status_update(test, "acl not match: on loop %d\n", x);
1582                         res = AST_TEST_FAIL;
1583                 }
1584         }
1585
1586         ast_free_ha(configs.aclopt);
1587         ao2_cleanup(defaults.codeccapopt);
1588         defaults.codeccapopt = NULL;
1589         ao2_cleanup(configs.codeccapopt);
1590         configs.codeccapopt = NULL;
1591         ast_string_field_free_memory(&defaults);
1592         ast_string_field_free_memory(&configs);
1593         return res;
1594 }
1595
1596 AST_TEST_DEFINE(config_dialplan_function)
1597 {
1598         enum ast_test_result_state res = AST_TEST_PASS;
1599         FILE *config_file;
1600         char filename[PATH_MAX];
1601         struct ast_str *buf;
1602
1603         switch (cmd) {
1604         case TEST_INIT:
1605                 info->name = "config_dialplan_function";
1606                 info->category = "/main/config/";
1607                 info->summary = "Test AST_CONFIG dialplan function";
1608                 info->description = "Test AST_CONFIG dialplan function";
1609                 return AST_TEST_NOT_RUN;
1610         case TEST_EXECUTE:
1611                 break;
1612         }
1613
1614         snprintf(filename, sizeof(filename), "%s/%s",
1615                         ast_config_AST_CONFIG_DIR, CONFIG_FILE);
1616         config_file = fopen(filename, "w");
1617
1618         if (!config_file) {
1619                 return AST_TEST_FAIL;
1620         }
1621
1622         fputs(
1623                 "[c1t](!)\n"
1624                 "var1=val1\n"
1625                 "var1=val2\n"
1626                 "var2=val21\n"
1627                 "\n"
1628                 "[c1](c1t)\n"
1629                 "var1=val3\n"
1630                 "var1=val4\n"
1631                 , config_file);
1632
1633         fclose(config_file);
1634
1635         if (!(buf = ast_str_create(32))) {
1636                 ast_test_status_update(test, "Failed to allocate return buffer\n");
1637                 res = AST_TEST_FAIL;
1638                 goto out;
1639         }
1640
1641         if (ast_func_read2(NULL, "AST_CONFIG("CONFIG_FILE",c1,var1)", &buf, 32)) {
1642                 ast_test_status_update(test, "Failed to retrieve field 'var1'\n");
1643                 res = AST_TEST_FAIL;
1644                 goto out;
1645         }
1646         if (strcmp(ast_str_buffer(buf), "val1")) {
1647                 ast_test_status_update(test, "Got '%s', should be '%s'\n",
1648                         ast_str_buffer(buf), "val1");
1649                 res = AST_TEST_FAIL;
1650                 goto out;
1651         }
1652
1653         ast_str_reset(buf);
1654         if (ast_func_read2(NULL, "AST_CONFIG("CONFIG_FILE",c1,var1,0)", &buf, 32)) {
1655                 ast_test_status_update(test, "Failed to retrieve field 'var1'\n");
1656                 res = AST_TEST_FAIL;
1657                 goto out;
1658         }
1659         if (strcmp(ast_str_buffer(buf), "val1")) {
1660                 ast_test_status_update(test, "Got '%s', should be '%s'\n",
1661                         ast_str_buffer(buf), "val1");
1662                 res = AST_TEST_FAIL;
1663                 goto out;
1664         }
1665
1666         ast_str_reset(buf);
1667         if (ast_func_read2(NULL, "AST_CONFIG("CONFIG_FILE",c1,var1,1)", &buf, 32)) {
1668                 ast_test_status_update(test, "Failed to retrieve field 'var1'\n");
1669                 res = AST_TEST_FAIL;
1670                 goto out;
1671         }
1672         if (strcmp(ast_str_buffer(buf), "val2")) {
1673                 ast_test_status_update(test, "Got '%s', should be '%s'\n",
1674                         ast_str_buffer(buf), "val2");
1675                 res = AST_TEST_FAIL;
1676                 goto out;
1677         }
1678
1679         ast_str_reset(buf);
1680         if (ast_func_read2(NULL, "AST_CONFIG("CONFIG_FILE",c1,var1,2)", &buf, 32)) {
1681                 ast_test_status_update(test, "Failed to retrieve field 'var1'\n");
1682                 res = AST_TEST_FAIL;
1683                 goto out;
1684         }
1685         if (strcmp(ast_str_buffer(buf), "val3")) {
1686                 ast_test_status_update(test, "Got '%s', should be '%s'\n",
1687                         ast_str_buffer(buf), "val3");
1688                 res = AST_TEST_FAIL;
1689                 goto out;
1690         }
1691
1692         ast_str_reset(buf);
1693         if (ast_func_read2(NULL, "AST_CONFIG("CONFIG_FILE",c1,var1,3)", &buf, 32)) {
1694                 ast_test_status_update(test, "Failed to retrieve field 'var1'\n");
1695                 res = AST_TEST_FAIL;
1696                 goto out;
1697         }
1698         if (strcmp(ast_str_buffer(buf), "val4")) {
1699                 ast_test_status_update(test, "Got '%s', should be '%s'\n",
1700                         ast_str_buffer(buf), "val4");
1701                 res = AST_TEST_FAIL;
1702                 goto out;
1703         }
1704
1705         ast_str_reset(buf);
1706         if (ast_func_read2(NULL, "AST_CONFIG("CONFIG_FILE",c1,var1,-1)", &buf, 32)) {
1707                 ast_test_status_update(test, "Failed to retrieve field 'var1'\n");
1708                 res = AST_TEST_FAIL;
1709                 goto out;
1710         }
1711         if (strcmp(ast_str_buffer(buf), "val4")) {
1712                 ast_test_status_update(test, "Got '%s', should be '%s'\n",
1713                         ast_str_buffer(buf), "val4");
1714                 res = AST_TEST_FAIL;
1715                 goto out;
1716         }
1717
1718         ast_str_reset(buf);
1719         if (ast_func_read2(NULL, "AST_CONFIG("CONFIG_FILE",c1,var2,-1)", &buf, 32)) {
1720                 ast_test_status_update(test, "Failed to retrieve field 'var2'\n");
1721                 res = AST_TEST_FAIL;
1722                 goto out;
1723         }
1724         if (strcmp(ast_str_buffer(buf), "val21")) {
1725                 ast_test_status_update(test, "Got '%s', should be '%s'\n",
1726                         ast_str_buffer(buf), "val21");
1727                 res = AST_TEST_FAIL;
1728                 goto out;
1729         }
1730
1731         ast_str_reset(buf);
1732         if (!ast_func_read2(NULL, "AST_CONFIG("CONFIG_FILE",c1,var1,5)", &buf, 32)) {
1733                 ast_test_status_update(test, "Should not have retrieved a value\n");
1734                 res = AST_TEST_FAIL;
1735                 goto out;
1736         }
1737
1738 out:
1739         if (buf) {
1740                 ast_free(buf);
1741         }
1742         delete_config_file();
1743         return res;
1744 }
1745
1746 AST_TEST_DEFINE(variable_lists_match)
1747 {
1748         RAII_VAR(struct ast_variable *, left, NULL, ast_variables_destroy);
1749         RAII_VAR(struct ast_variable *, right, NULL, ast_variables_destroy);
1750         struct ast_variable *var;
1751
1752         switch (cmd) {
1753         case TEST_INIT:
1754                 info->name = "variable_lists_match";
1755                 info->category = "/main/config/";
1756                 info->summary = "Test ast_variable_lists_match";
1757                 info->description =     "Test ast_variable_lists_match";
1758                 return AST_TEST_NOT_RUN;
1759         case TEST_EXECUTE:
1760                 break;
1761         }
1762
1763         var = ast_variable_new("aaa", "111", "");
1764         ast_test_validate(test, var);
1765         left = var;
1766         var = ast_variable_new("bbb", "222", "");
1767         ast_test_validate(test, var);
1768         ast_variable_list_append(&left, var);
1769
1770         var = ast_variable_new("aaa", "111", "");
1771         ast_test_validate(test, var);
1772         right = var;
1773
1774         ast_test_validate(test, ast_variable_lists_match(left, right, 0));
1775         ast_test_validate(test, !ast_variable_lists_match(left, right, 1));
1776
1777         var = ast_variable_new("bbb", "222", "");
1778         ast_test_validate(test, var);
1779         ast_variable_list_append(&right, var);
1780
1781         ast_test_validate(test, ast_variable_lists_match(left, right, 0));
1782         ast_test_validate(test, ast_variable_lists_match(left, right, 1));
1783
1784         var = ast_variable_new("ccc >", "333", "");
1785         ast_test_validate(test, var);
1786         ast_variable_list_append(&right, var);
1787
1788         ast_test_validate(test, !ast_variable_lists_match(left, right, 0));
1789         ast_test_validate(test, !ast_variable_lists_match(left, right, 1));
1790
1791         var = ast_variable_new("ccc", "444", "");
1792         ast_test_validate(test, var);
1793         ast_variable_list_append(&left, var);
1794
1795         ast_test_validate(test, ast_variable_lists_match(left, right, 0));
1796         ast_test_validate(test, !ast_variable_lists_match(left, right, 1));
1797
1798         ast_test_validate(test, !ast_variable_lists_match(left, NULL, 0));
1799         ast_test_validate(test, ast_variable_lists_match(NULL, NULL, 0));
1800         ast_test_validate(test, !ast_variable_lists_match(NULL, right, 0));
1801         ast_test_validate(test, ast_variable_lists_match(left, left, 0));
1802
1803         return AST_TEST_PASS;
1804 }
1805
1806 static int unload_module(void)
1807 {
1808         AST_TEST_UNREGISTER(config_save);
1809         AST_TEST_UNREGISTER(config_basic_ops);
1810         AST_TEST_UNREGISTER(config_filtered_ops);
1811         AST_TEST_UNREGISTER(config_template_ops);
1812         AST_TEST_UNREGISTER(copy_config);
1813         AST_TEST_UNREGISTER(config_hook);
1814         AST_TEST_UNREGISTER(ast_parse_arg_test);
1815         AST_TEST_UNREGISTER(config_options_test);
1816         AST_TEST_UNREGISTER(config_dialplan_function);
1817         AST_TEST_UNREGISTER(variable_lists_match);
1818         return 0;
1819 }
1820
1821 static int load_module(void)
1822 {
1823         AST_TEST_REGISTER(config_save);
1824         AST_TEST_REGISTER(config_basic_ops);
1825         AST_TEST_REGISTER(config_filtered_ops);
1826         AST_TEST_REGISTER(config_template_ops);
1827         AST_TEST_REGISTER(copy_config);
1828         AST_TEST_REGISTER(config_hook);
1829         AST_TEST_REGISTER(ast_parse_arg_test);
1830         AST_TEST_REGISTER(config_options_test);
1831         AST_TEST_REGISTER(config_dialplan_function);
1832         AST_TEST_REGISTER(variable_lists_match);
1833         return AST_MODULE_LOAD_SUCCESS;
1834 }
1835
1836 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Config test module");
1837