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