ae5aa7b765e08d92374134e7b442247e12636b59
[asterisk/asterisk.git] / tests / test_substitution.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2009, Digium, Inc.
5  *
6  * Tilghman Lesher <tlesher AT digium DOT 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 /*! \file
20  *
21  * \brief Substitution Test
22  *
23  * \author\verbatim Tilghman Lesher <tlesher AT digium DOT com> \endverbatim
24  * 
25  * \ingroup tests
26  */
27
28 /*** MODULEINFO
29         <defaultenabled>no</defaultenabled>
30  ***/
31
32 #include "asterisk.h"
33
34 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
35
36 #include "asterisk/file.h"
37 #include "asterisk/channel.h"
38 #include "asterisk/pbx.h"
39 #include "asterisk/module.h"
40 #include "asterisk/lock.h"
41 #include "asterisk/app.h"
42 #include "asterisk/strings.h"
43 #include "asterisk/stringfields.h"
44 #include "asterisk/threadstorage.h"
45 #include "asterisk/cli.h"
46
47 AST_THREADSTORAGE(buf_buf);
48 AST_THREADSTORAGE(var_buf);
49
50 static void test_chan_integer(int fd, struct ast_channel *c, int *ifield, const char *expression)
51 {
52         int i, okay = 1, value1 = -1, value2 = -1;
53         char workspace[4096];
54         struct ast_str *str = ast_str_thread_get(&buf_buf, 16);
55
56         for (i = 0; i < 256; i++) {
57                 *ifield = i;
58                 ast_str_substitute_variables(&str, 0, c, expression);
59                 pbx_substitute_variables_helper(c, expression, workspace, sizeof(workspace));
60                 if (sscanf(workspace, "%d", &value1) != 1 || value1 != i || sscanf(ast_str_buffer(str), "%d", &value2) != 1 || value2 != i) {
61                         ast_cli(fd, "%s != %s and/or %d != %d != %d\n", ast_str_buffer(str), workspace, value1, value2, i);
62                         okay = 0;
63                         break;
64                 }
65         }
66         ast_cli(fd, "Testing '%s' . . . . . %s\n", expression, okay ? "passed" : "FAILED");
67 }
68
69 static void test_chan_string(int fd, struct ast_channel *c, char *cfield, size_t cfieldsize, const char *expression)
70 {
71         const char *values[] = { "one", "three", "reallylongdinosaursoundingthingwithwordsinit" };
72         int i, okay = 1;
73         char workspace[4096];
74         struct ast_str *str = ast_str_thread_get(&buf_buf, 16);
75
76         for (i = 0; i < ARRAY_LEN(values); i++) {
77                 ast_copy_string(cfield, values[i], cfieldsize);
78                 ast_str_substitute_variables(&str, 0, c, expression);
79                 pbx_substitute_variables_helper(c, expression, workspace, sizeof(workspace));
80                 if (strcmp(cfield, ast_str_buffer(str)) != 0 || strcmp(cfield, workspace) != 0) {
81                         ast_cli(fd, "%s != %s != %s\n", cfield, ast_str_buffer(str), workspace);
82                         okay = 0;
83                         break;
84                 }
85         }
86         ast_cli(fd, "Testing '%s' . . . . . %s\n", expression, okay ? "passed" : "FAILED");
87 }
88
89 static void test_chan_variable(int fd, struct ast_channel *c, const char *varname)
90 {
91         const char *values[] = { "one", "three", "reallylongdinosaursoundingthingwithwordsinit" };
92         int i, okay = 1;
93         char workspace[4096];
94         struct ast_str *str = ast_str_thread_get(&buf_buf, 16);
95         struct ast_str *var = ast_str_thread_get(&var_buf, 16);
96
97         ast_str_set(&var, 0, "${%s}", varname);
98         for (i = 0; i < ARRAY_LEN(values); i++) {
99                 pbx_builtin_setvar_helper(c, varname, values[i]);
100                 ast_str_substitute_variables(&str, 0, c, ast_str_buffer(var));
101                 pbx_substitute_variables_helper(c, ast_str_buffer(var), workspace, sizeof(workspace));
102                 if (strcmp(values[i], ast_str_buffer(str)) != 0 || strcmp(values[i], workspace) != 0) {
103                         ast_cli(fd, "%s != %s != %s\n", values[i], ast_str_buffer(str), workspace);
104                         okay = 0;
105                         break;
106                 }
107         }
108         ast_cli(fd, "Testing '%s' . . . . . %s\n", ast_str_buffer(var), okay ? "passed" : "FAILED");
109 }
110
111 static void test_chan_function(int fd, struct ast_channel *c, const char *expression)
112 {
113         int okay = 1;
114         char workspace[4096];
115         struct ast_str *str = ast_str_thread_get(&buf_buf, 16);
116
117         ast_str_substitute_variables(&str, 0, c, expression);
118         pbx_substitute_variables_helper(c, expression, workspace, sizeof(workspace));
119         if (strcmp(workspace, ast_str_buffer(str)) != 0) {
120                 ast_cli(fd, "%s != %s\n", ast_str_buffer(str), workspace);
121                 okay = 0;
122         }
123         ast_cli(fd, "Testing '%s' . . . . . %s\n", expression, okay ? "passed" : "FAILED");
124 }
125
126 static void test_2way_function(int fd, struct ast_channel *c, const char *encode1, const char *encode2, const char *decode1, const char *decode2)
127 {
128         struct ast_str *str = ast_str_thread_get(&buf_buf, 16), *expression = ast_str_alloca(120);
129
130         ast_str_set(&expression, 0, "%s%s%s", encode1, "foobarbaz", encode2);
131         ast_str_substitute_variables(&str, 0, c, ast_str_buffer(expression));
132         ast_str_set(&expression, 0, "%s%s%s", decode1, ast_str_buffer(str), decode2);
133         ast_str_substitute_variables(&str, 0, c, ast_str_buffer(expression));
134         ast_cli(fd, "Testing '%s%s' and '%s%s' . . . . . %s\n", encode1, encode2, decode1, decode2, !strcmp(ast_str_buffer(str), "foobarbaz") ? "passed" : "FAILED");
135         if (strcmp(ast_str_buffer(str), "foobarbaz")) {
136                 ast_cli(fd, "  '%s' != 'foobarbaz'\n", ast_str_buffer(str));
137         }
138 }
139
140 static void test_expected_result(int fd, struct ast_channel *c, const char *expression, const char *result)
141 {
142         struct ast_str *str = ast_str_thread_get(&buf_buf, 16);
143         ast_str_substitute_variables(&str, 0, c, expression);
144         ast_cli(fd, "Testing '%s' ('%s') == '%s' . . . . . %s\n", ast_str_buffer(str), expression, result, !strcmp(ast_str_buffer(str), result) ? "passed" : "FAILED");
145 }
146
147 static char *handle_cli_test_substitution(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
148 {
149         struct ast_channel *c;
150         int i;
151
152         switch (cmd) {
153         case CLI_INIT:
154                 e->command = "test substitution";
155                 e->usage = ""
156                         "Usage: test substitution\n"
157                         "   Test variable and function substitution.\n";
158                 return NULL;
159         case CLI_GENERATE:
160                 return NULL;
161         }
162
163         if (a->argc != e->args) {
164                 return CLI_SHOWUSAGE;
165         }
166
167         ast_cli(a->fd, "Testing variable substitution ...\n");
168         c = ast_dummy_channel_alloc();
169
170         test_chan_integer(a->fd, c, &c->cid.cid_pres, "${CALLINGPRES}");
171         test_chan_integer(a->fd, c, &c->cid.cid_ani2, "${CALLINGANI2}");
172         test_chan_integer(a->fd, c, &c->cid.cid_ton, "${CALLINGTON}");
173         test_chan_integer(a->fd, c, &c->cid.cid_tns, "${CALLINGTNS}");
174         test_chan_integer(a->fd, c, &c->hangupcause, "${HANGUPCAUSE}");
175         test_chan_integer(a->fd, c, &c->priority, "${PRIORITY}");
176         test_chan_string(a->fd, c, c->context, sizeof(c->context), "${CONTEXT}");
177         test_chan_string(a->fd, c, c->exten, sizeof(c->exten), "${EXTEN}");
178         test_chan_variable(a->fd, c, "CHANNEL(language)");
179         test_chan_variable(a->fd, c, "CHANNEL(musicclass)");
180         test_chan_variable(a->fd, c, "CHANNEL(parkinglot)");
181         test_chan_variable(a->fd, c, "CALLERID(name)");
182         test_chan_variable(a->fd, c, "CURLOPT(proxyuserpwd)");
183         test_chan_variable(a->fd, c, "CDR(foo)");
184         test_chan_variable(a->fd, c, "ENV(foo)");
185         test_chan_variable(a->fd, c, "GLOBAL(foo)");
186         test_chan_variable(a->fd, c, "GROUP()");
187         test_2way_function(a->fd, c, "${AES_ENCRYPT(abcdefghijklmnop,", ")}", "${AES_DECRYPT(abcdefghijklmnop,", ")}");
188         test_2way_function(a->fd, c, "${BASE64_ENCODE(", ")}", "${BASE64_DECODE(", ")}");
189         pbx_builtin_setvar_helper(c, "foo", "123");
190         pbx_builtin_setvar_helper(c, "bar", "foo");
191         pbx_builtin_setvar_helper(c, "baz", "fo");
192         test_expected_result(a->fd, c, "${foo}${foo}", "123123");
193         test_expected_result(a->fd, c, "A${foo}A${foo}A", "A123A123A");
194         test_expected_result(a->fd, c, "A${${bar}}A", "A123A");
195         test_expected_result(a->fd, c, "A${${baz}o}A", "A123A");
196         test_expected_result(a->fd, c, "A${${baz}o:1}A", "A23A");
197         test_expected_result(a->fd, c, "A${${baz}o:1:1}A", "A2A");
198         test_expected_result(a->fd, c, "A${${baz}o:1:-1}A", "A2A");
199         test_expected_result(a->fd, c, "A${${baz}o:-1:1}A", "A3A");
200         test_expected_result(a->fd, c, "A${${baz}o:-2:1}A", "A2A");
201         test_expected_result(a->fd, c, "A${${baz}o:-2:-1}A", "A2A");
202
203         /* For testing dialplan functions */
204         for (i = 0; ; i++) {
205                 char *cmd = ast_cli_generator("core show function", "", i);
206                 if (cmd == NULL) {
207                         break;
208                 }
209                 if (strcmp(cmd, "CHANNEL") && strcmp(cmd, "CALLERID") && strcmp(cmd, "CURLOPT") && strncmp(cmd, "AES", 3) && strncmp(cmd, "BASE64", 6) && strcmp(cmd, "CDR") && strcmp(cmd, "ENV") && strcmp(cmd, "GLOBAL") && strcmp(cmd, "GROUP") && strcmp(cmd, "CUT") && strcmp(cmd, "LISTFILTER") && strcmp(cmd, "PP_EACH_EXTENSION") && strcmp(cmd, "SET")) {
210                         struct ast_custom_function *acf = ast_custom_function_find(cmd);
211                         if (acf->read && acf->read2) {
212                                 char expression[80];
213                                 snprintf(expression, sizeof(expression), "${%s(foo)}", cmd);
214                                 test_chan_function(a->fd, c, expression);
215                         }
216                 }
217                 ast_free(cmd);
218         }
219
220         ast_channel_release(c);
221
222         return CLI_SUCCESS;
223 }
224
225 static struct ast_cli_entry cli_substitution[] = {
226         AST_CLI_DEFINE(handle_cli_test_substitution, "Test variable substitution"),
227 };
228
229 static int unload_module(void)
230 {
231         ast_cli_unregister_multiple(cli_substitution, ARRAY_LEN(cli_substitution));
232         return 0;
233 }
234
235 static int load_module(void)
236 {
237         ast_cli_register_multiple(cli_substitution, ARRAY_LEN(cli_substitution));
238         return AST_MODULE_LOAD_SUCCESS;
239 }
240
241 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Substitution tests");