Asterisk - The Open Source Telephony Project GIT-master-0644429
test_func_file.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2010, 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/*!
20 * \file
21 * \brief Function FILE tests
22 *
23 * \author\verbatim Tilghman Lesher <tlesher AT digium DOT com> \endverbatim
24 *
25 * \ingroup tests
26 */
27
28/*** MODULEINFO
29 <depend>TEST_FRAMEWORK</depend>
30 <support_level>core</support_level>
31 ***/
32
33#include "asterisk.h"
34
35#include "asterisk/utils.h"
36#include "asterisk/app.h"
37#include "asterisk/module.h"
38#include "asterisk/test.h"
39#include "asterisk/pbx.h"
40
41#define C1024 \
42 "1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF"
43
44static struct {
45 const char *contents;
46 const char *args;
47 const char *value;
48} read_tests[] = {
49 /* 4 different ways of specifying the first character */
50 { "123456789", "0,1", "1" },
51 { "123456789", "0,-8", "1" },
52 { "123456789", "-9,1", "1" },
53 { "123456789", "-9,-8", "1" },
54 /* Does 0-length work? */
55 { "123456789", "0,0", "" },
56 { "123456789", "-9,0", "" },
57 { "123456789", "-9,-9", "" },
58 /* Does negative length work? */
59 { "123456789", "5,-6", "" },
60 { "123456789", "-5,-6", "" },
61 /* No length */
62 { "123456789", "-5", "56789" },
63 { "123456789", "4", "56789" },
64 /* Passed file length */
65 { "123456789", "8,10", "9" },
66 { "123456789", "10,1", "" },
67 /* Middle of file */
68 { "123456789", "2,5", "34567" },
69 { "123456789", "-7,5", "34567" },
70 /* Line mode, 4 ways of specifying the first character */
71 { "123\n456\n789\n", "0,1,l", "123\n" },
72 { "123\n456\n789\n", "-3,1,l", "123\n" },
73 { "123\n456\n789\n", "0,-2,l", "123\n" },
74 { "123\n456\n789\n", "-3,-2,l", "123\n" },
75 /* Line mode, 0-length */
76 { "123\n456\n789\n", "0,0,l", "" },
77 { "123\n456\n789\n", "-3,0,l", "" },
78 { "123\n456\n789\n", "-3,-3,l", "" },
79 /* Line mode, negative length */
80 { "123\n456\n789\n", "2,-2,l", "" },
81 { "123\n456\n789\n", "-2,-3,l", "" },
82 /* No length */
83 { "123\n456\n789\n", "1,,l", "456\n789\n" },
84 { "123\n456\n789\n", "-2,,l", "456\n789\n" },
85};
86
87static struct {
88 const char *contents;
89 const char *args;
90 const char *value;
91 const char *contents2;
92} write_tests[] = {
93 /* Single character replace */
94 { "123456789", "0,1", "a", "a23456789" },
95 { "123456789", "-9,1", "a", "a23456789" },
96 { "123456789", "0,-8", "a", "a23456789" },
97 { "123456789", "-9,-8", "a", "a23456789" },
98 { "123456789", "5,1", "b", "12345b789" },
99 { "123456789", "-4,1", "b", "12345b789" },
100 { "123456789", "5,-3", "b", "12345b789" },
101 { "123456789", "-4,-3", "b", "12345b789" },
102 /* Replace 2 characters with 1 */
103 { "123456789", "0,2", "c", "c3456789" },
104 { "123456789", "-9,2", "c", "c3456789" },
105 { "123456789", "0,-7", "c", "c3456789" },
106 { "123456789", "-9,-7", "c", "c3456789" },
107 { "123456789", "4,2", "d", "1234d789" },
108 { "123456789", "-5,2", "d", "1234d789" },
109 { "123456789", "4,-3", "d", "1234d789" },
110 { "123456789", "-5,-3", "d", "1234d789" },
111 /* Truncate file */
112 { "123456789", "5", "e", "12345e" },
113 { "123456789", "5", "", "12345" },
114 { "123456789", "-4", "e", "12345e" },
115 { "123456789", "-4", "", "12345" },
116 /* Replace 1 character with 2 */
117 { "123456789", "0,1", "fg", "fg23456789" },
118 { "123456789", "0,-8", "fg", "fg23456789" },
119 { "123456789", "-9,1", "fg", "fg23456789" },
120 { "123456789", "-9,-8", "fg", "fg23456789" },
121 /* Overwrite file */
122 { "123456789", "", "h", "h" },
123 { "123456789", ",,,", "h", "h" },
124 { "123\n456\n789\n", ",,l", "h", "h\n" },
125 { "123\n456\n789\n", ",,ld", "h", "h" },
126 /* Single line replace, same length */
127 { "123\n456\n789\n", "0,1,l", "abc", "abc\n456\n789\n" },
128 { "123\n456\n789\n", "-3,1,l", "abc", "abc\n456\n789\n" },
129 { "123\n456\n789\n", "0,-2,l", "abc", "abc\n456\n789\n" },
130 { "123\n456\n789\n", "-3,-2,l", "abc", "abc\n456\n789\n" },
131 { "123\n456\n789\n", "1,1,l", "abc", "123\nabc\n789\n" },
132 { "123\n456\n789\n", "1,-1,l", "abc", "123\nabc\n789\n" },
133 { "123\n456\n789\n", "-2,1,l", "abc", "123\nabc\n789\n" },
134 { "123\n456\n789\n", "-2,-1,l", "abc", "123\nabc\n789\n" },
135 /* Single line replace, one character short */
136 { "123\n456\n789\n", "0,1,l", "ab", "ab\n456\n789\n" },
137 { "123\n456\n789\n", "-3,1,l", "ab", "ab\n456\n789\n" },
138 { "123\n456\n789\n", "0,-2,l", "ab", "ab\n456\n789\n" },
139 { "123\n456\n789\n", "-3,-2,l", "ab", "ab\n456\n789\n" },
140 { "123\n456\n789\n", "1,1,l", "ab", "123\nab\n789\n" },
141 { "123\n456\n789\n", "1,-1,l", "ab", "123\nab\n789\n" },
142 { "123\n456\n789\n", "-2,1,l", "ab", "123\nab\n789\n" },
143 { "123\n456\n789\n", "-2,-1,l", "ab", "123\nab\n789\n" },
144 /* Single line replace, one character long */
145 { "123\n456\n789\n", "0,1,l", "abcd", "abcd\n456\n789\n" },
146 { "123\n456\n789\n", "-3,1,l", "abcd", "abcd\n456\n789\n" },
147 { "123\n456\n789\n", "0,-2,l", "abcd", "abcd\n456\n789\n" },
148 { "123\n456\n789\n", "-3,-2,l", "abcd", "abcd\n456\n789\n" },
149 { "123\n456\n789\n", "1,1,l", "abcd", "123\nabcd\n789\n" },
150 { "123\n456\n789\n", "1,-1,l", "abcd", "123\nabcd\n789\n" },
151 { "123\n456\n789\n", "-2,1,l", "abcd", "123\nabcd\n789\n" },
152 { "123\n456\n789\n", "-2,-1,l", "abcd", "123\nabcd\n789\n" },
153 /* Multi-line replace, same number of characters, 2 lines for 1 */
154 { "123\n456\n789\n", "0,2,l", "abcdefg", "abcdefg\n789\n" },
155 { "123\n456\n789\n", "-3,2,l", "abcdefg", "abcdefg\n789\n" },
156 { "123\n456\n789\n", "0,-1,l", "abcdefg", "abcdefg\n789\n" },
157 { "123\n456\n789\n", "-3,-1,l", "abcdefg", "abcdefg\n789\n" },
158 { "123\n456\n789\n", "1,2,l", "abcdefg", "123\nabcdefg\n" },
159 { "123\n456\n789\n", "1,,l", "abcdefg", "123\nabcdefg\n" },
160 { "123\n456\n789\n", "-2,2,l", "abcdefg", "123\nabcdefg\n" },
161 { "123\n456\n789\n", "-2,,l", "abcdefg", "123\nabcdefg\n" },
162 /* Multi-line replace, shorter number of characters, 2 lines for 1 */
163 { "123\n456\n789\n", "0,2,l", "abcd", "abcd\n789\n" },
164 { "123\n456\n789\n", "-3,2,l", "abcd", "abcd\n789\n" },
165 { "123\n456\n789\n", "0,-1,l", "abcd", "abcd\n789\n" },
166 { "123\n456\n789\n", "-3,-1,l", "abcd", "abcd\n789\n" },
167 { "123\n456\n789\n", "1,2,l", "abcd", "123\nabcd\n" },
168 { "123\n456\n789\n", "1,,l", "abcd", "123\nabcd\n" },
169 { "123\n456\n789\n", "-2,2,l", "abcd", "123\nabcd\n" },
170 { "123\n456\n789\n", "-2,,l", "abcd", "123\nabcd\n" },
171 /* Multi-line replace, longer number of characters, 2 lines for 1 */
172 { "123\n456\n789\n", "0,2,l", "abcdefghijklmnop", "abcdefghijklmnop\n789\n" },
173 { "123\n456\n789\n", "-3,2,l", "abcdefghijklmnop", "abcdefghijklmnop\n789\n" },
174 { "123\n456\n789\n", "0,-1,l", "abcdefghijklmnop", "abcdefghijklmnop\n789\n" },
175 { "123\n456\n789\n", "-3,-1,l", "abcdefghijklmnop", "abcdefghijklmnop\n789\n" },
176 { "123\n456\n789\n", "1,2,l", "abcdefghijklmnop", "123\nabcdefghijklmnop\n" },
177 { "123\n456\n789\n", "1,,l", "abcdefghijklmnop", "123\nabcdefghijklmnop\n" },
178 { "123\n456\n789\n", "-2,2,l", "abcdefghijklmnop", "123\nabcdefghijklmnop\n" },
179 { "123\n456\n789\n", "-2,,l", "abcdefghijklmnop", "123\nabcdefghijklmnop\n" },
180 /* Insert line */
181 { "123\n456\n789\n", "0,0,l", "abcd", "abcd\n123\n456\n789\n" },
182 { "123\n456\n789\n", "-3,0,l", "abcd", "abcd\n123\n456\n789\n" },
183 { "123\n456\n789\n", "1,0,l", "abcd", "123\nabcd\n456\n789\n" },
184 { "123\n456\n789\n", "-2,0,l", "abcd", "123\nabcd\n456\n789\n" },
185 { "123\n456\n789\n", "2,0,l", "abcd", "123\n456\nabcd\n789\n" },
186 { "123\n456\n789\n", "-1,0,l", "abcd", "123\n456\nabcd\n789\n" },
187 { "123\n456\n789\n", "3,0,l", "abcd", "123\n456\n789\nabcd\n" },
188 { "123\n456\n789\n", ",,la", "abcd", "123\n456\n789\nabcd\n" },
189 /* Single line, replace with blank line */
190 { "123\n456\n789\n", "0,1,l", "", "\n456\n789\n" },
191 { "123\n456\n789\n", "-3,1,l", "", "\n456\n789\n" },
192 { "123\n456\n789\n", "0,-2,l", "", "\n456\n789\n" },
193 { "123\n456\n789\n", "-3,-2,l", "", "\n456\n789\n" },
194 { "123\n456\n789\n", "1,1,l", "", "123\n\n789\n" },
195 { "123\n456\n789\n", "1,-1,l", "", "123\n\n789\n" },
196 { "123\n456\n789\n", "-2,1,l", "", "123\n\n789\n" },
197 { "123\n456\n789\n", "-2,-1,l", "", "123\n\n789\n" },
198 /* Single line, delete */
199 { "123\n456\n789\n", "0,1,ld", "", "456\n789\n" },
200 { "123\n456\n789\n", "-3,1,ld", "", "456\n789\n" },
201 { "123\n456\n789\n", "0,-2,ld", "", "456\n789\n" },
202 { "123\n456\n789\n", "-3,-2,ld", "", "456\n789\n" },
203 { "123\n456\n789\n", "1,1,ld", "", "123\n789\n" },
204 { "123\n456\n789\n", "1,-1,ld", "", "123\n789\n" },
205 { "123\n456\n789\n", "-2,1,ld", "", "123\n789\n" },
206 { "123\n456\n789\n", "-2,-1,ld", "", "123\n789\n" },
207 /* Really long tests */
208 { "1234567890ABCDEF" C1024 C1024 C1024 C1024 C1024,
209 "0,1", "a",
210 "a234567890ABCDEF" C1024 C1024 C1024 C1024 C1024 },
211 { "1234567890ABCDEF" C1024 C1024 C1024 C1024 C1024,
212 "0,1", "abcd",
213 "abcd234567890ABCDEF" C1024 C1024 C1024 C1024 C1024 },
214 { "1234567890ABCDEF" C1024 C1024 C1024 C1024 C1024,
215 "0,10", "abcd",
216 "abcdABCDEF" C1024 C1024 C1024 C1024 C1024 },
217 { "1" C1024 "\n2" C1024 "\n3" C1024 "\n4" C1024 "\n5" C1024 "\n6" C1024 "\n",
218 "0,1,l", "abcd",
219 "abcd\n2" C1024 "\n3" C1024 "\n4" C1024 "\n5" C1024 "\n6" C1024 "\n" },
220 { "1234\n1" C1024 "\n2" C1024 "\n3" C1024 "\n4" C1024 "\n5" C1024 "\n6" C1024 "\n",
221 "0,1,l", "abcd",
222 "abcd\n1" C1024 "\n2" C1024 "\n3" C1024 "\n4" C1024 "\n5" C1024 "\n6" C1024 "\n" },
223 { "1234\n1" C1024 "\n2" C1024 "\n3" C1024 "\n4" C1024 "\n5" C1024 "\n6" C1024 "\n",
224 "0,1,l", "a",
225 "a\n1" C1024 "\n2" C1024 "\n3" C1024 "\n4" C1024 "\n5" C1024 "\n6" C1024 "\n" },
227
228static char *file2display(struct ast_str **buf, ssize_t len, const char *input)
229{
230 const char *ptr;
232 for (ptr = input; *ptr; ptr++) {
233 if (*ptr == '\n') {
234 ast_str_append(buf, len, "\\n");
235 } else if (*ptr == '\r') {
236 ast_str_append(buf, len, "\\r");
237 } else if (*ptr == '\t') {
238 ast_str_append(buf, len, "\\t");
239 } else if (*ptr < ' ' || *ptr > 125) {
240 ast_str_append(buf, len, "\\x%hhX", *ptr);
241 } else {
242 ast_str_append(buf, len, "%c", *ptr);
243 }
244 }
245 return ast_str_buffer(*buf);
246}
247
248AST_TEST_DEFINE(test_func_file)
249{
250 int res = AST_TEST_PASS;
251 int i;
252 char dir[] = "/tmp/test_func_file.XXXXXX";
253 char file[80], expression[256];
254 struct ast_str *buf, *disp[2] = { NULL, NULL };
255 char fbuf[8192];
256 FILE *fh;
257
258 switch (cmd) {
259 case TEST_INIT:
260 info->name = "func_file";
261 info->category = "/funcs/func_env/";
262 info->summary = "Verify behavior of the FILE() dialplan function";
263 info->description =
264 "Verifies that the examples of the FILE() dialplan function documentation work as described.";
265 return AST_TEST_NOT_RUN;
266 case TEST_EXECUTE:
267 break;
268 }
269
270 if (!mkdtemp(dir)) {
271 ast_test_status_update(test, "Cannot create temporary directory: %s\n", strerror(errno));
272 return AST_TEST_FAIL;
273 }
274
275 disp[0] = ast_str_create(16);
276 disp[1] = ast_str_create(16);
277 if (!(buf = ast_str_create(16)) || !disp[0] || !disp[1]) {
278 ast_free(buf);
279 ast_free(disp[0]);
280 ast_free(disp[1]);
281 rmdir(dir);
282 return AST_TEST_FAIL;
283 }
284
285 snprintf(file, sizeof(file), "%s/test.txt", dir);
286
287 for (i = 0; i < ARRAY_LEN(read_tests); i++) {
288 if (!(fh = fopen(file, "w"))) {
289 ast_test_status_update(test, "Cannot open test file: %s\n", strerror(errno));
290 ast_free(buf);
291 ast_free(disp[0]);
292 ast_free(disp[1]);
293 unlink(file);
294 rmdir(dir);
295 return AST_TEST_FAIL;
296 }
297
298 if (fwrite(read_tests[i].contents, 1, strlen(read_tests[i].contents), fh) < strlen(read_tests[i].contents)) {
299 ast_test_status_update(test, "Cannot write initial values into test file: %s\n", strerror(errno));
300 ast_free(buf);
301 ast_free(disp[0]);
302 ast_free(disp[1]);
303 fclose(fh);
304 unlink(file);
305 rmdir(dir);
306 return AST_TEST_FAIL;
307 }
308
309 fclose(fh);
310
311 snprintf(expression, sizeof(expression), "${FILE(%s,%s)}", file, read_tests[i].args);
312 ast_str_substitute_variables(&buf, 0, NULL, expression);
313
314 if (strcmp(ast_str_buffer(buf), read_tests[i].value)) {
315 ast_test_status_update(test, "Expression '${FILE(...,%s)}' did not produce ('%s') the expected value ('%s')\n",
316 read_tests[i].args, file2display(&disp[0], 0, ast_str_buffer(buf)), file2display(&disp[1], 0, read_tests[i].value));
317 res = AST_TEST_FAIL;
318 }
319 }
320
321 ast_free(buf);
322
323 for (i = 0; i < ARRAY_LEN(write_tests); i++) {
324 if (!(fh = fopen(file, "w"))) {
325 ast_test_status_update(test, "Cannot open test file: %s\n", strerror(errno));
326 ast_free(disp[0]);
327 ast_free(disp[1]);
328 unlink(file);
329 rmdir(dir);
330 return AST_TEST_FAIL;
331 }
332
333 if (fwrite(write_tests[i].contents, 1, strlen(write_tests[i].contents), fh) < strlen(write_tests[i].contents)) {
334 ast_test_status_update(test, "Cannot write initial values into test file: %s\n", strerror(errno));
335 ast_free(disp[0]);
336 ast_free(disp[1]);
337 fclose(fh);
338 unlink(file);
339 rmdir(dir);
340 return AST_TEST_FAIL;
341 }
342
343 fclose(fh);
344
345 snprintf(expression, sizeof(expression), "FILE(%s,%s)", file, write_tests[i].args);
346 ast_func_write(NULL, expression, write_tests[i].value);
347
348 if (!(fh = fopen(file, "r"))) {
349 ast_test_status_update(test, "Cannot open test file: %s\n", strerror(errno));
350 ast_free(disp[0]);
351 ast_free(disp[1]);
352 unlink(file);
353 rmdir(dir);
354 return AST_TEST_FAIL;
355 }
356
357 memset(fbuf, 0, sizeof(fbuf));
358 if (!fread(fbuf, 1, sizeof(fbuf), fh)) {
359 ast_test_status_update(test, "Cannot read write results from test file: %s\n", strerror(errno));
360 ast_free(disp[0]);
361 ast_free(disp[1]);
362 fclose(fh);
363 unlink(file);
364 rmdir(dir);
365 return AST_TEST_FAIL;
366 }
367
368 fclose(fh);
369
370 if (strcmp(fbuf, write_tests[i].contents2)) {
371 ast_test_status_update(test, "Expression 'FILE(...,%s)=%s' did not produce ('%s') the expected result ('%s')\n",
372 write_tests[i].args, write_tests[i].value, file2display(&disp[0], 0, fbuf), file2display(&disp[1], 0, write_tests[i].contents2));
373 res = AST_TEST_FAIL;
374 } else {
375 ast_test_status_update(test, "Expression 'FILE(...,%s)=%s'... OK!\n", write_tests[i].args, write_tests[i].value);
376 }
377 }
378
379 ast_free(disp[0]);
380 ast_free(disp[1]);
381 unlink(file);
382 rmdir(dir);
383
384 return res;
385}
386
387static int unload_module(void)
388{
389 AST_TEST_UNREGISTER(test_func_file);
390 return 0;
391}
392
393static int load_module(void)
394{
395 AST_TEST_REGISTER(test_func_file);
397}
398
static int input(yyscan_t yyscanner)
Definition: ast_expr2f.c:1570
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
char * mkdtemp(char *template_s)
int errno
Asterisk module definitions.
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:581
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
def info(msg)
Core PBX routines and definitions.
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
executes a write operation on a function
#define NULL
Definition: resample.c:96
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
Definition: strings.h:693
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
Support for dynamic strings.
Definition: strings.h:623
Test Framework API.
@ TEST_INIT
Definition: test.h:200
@ TEST_EXECUTE
Definition: test.h:201
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128
@ AST_TEST_PASS
Definition: test.h:195
@ AST_TEST_FAIL
Definition: test.h:196
@ AST_TEST_NOT_RUN
Definition: test.h:194
#define C1024
static char * file2display(struct ast_str **buf, ssize_t len, const char *input)
static struct @498 read_tests[]
const char * args
const char * value
const char * contents2
static int load_module(void)
static int unload_module(void)
AST_TEST_DEFINE(test_func_file)
const char * contents
static struct @499 write_tests[]
Utility functions.
#define ARRAY_LEN(a)
Definition: utils.h:666