Asterisk - The Open Source Telephony Project  18.5.0
test_gosub.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 Gosub tests
22  *
23  * \author Tilghman Lesher \verbatim <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/module.h"
37 #include "asterisk/test.h"
38 #include "asterisk/pbx.h"
39 #include "asterisk/channel.h"
40 
41 AST_TEST_DEFINE(test_gosub)
42 {
43 #define CONTEXT_NAME "tests_test_gosub_virtual_context"
44  int res = AST_TEST_PASS, i;
45  struct ast_channel *chan;
46  struct ast_str *str;
47  struct testplan {
48  const char *app;
49  const char *args;
50  const char *expected_value;
51  } testplan[] = {
52  { NULL, "${STACK_PEEK(1,e,1)}", "" }, /* Stack is empty */
53  { "Gosub", "tests_test_gosub_virtual_context,s,1" },
54  { NULL, "${PRIORITY}", "1" },
55  { NULL, "${EXTEN}", "s" },
56  { NULL, "${STACK_PEEK(1,e,1)}", "" }, /* No extension originally */
57  { "Gosub", "test,dne,1", (const char *) -1 }, /* This is the only invocation that should fail. */
58  { NULL, "${PRIORITY}", "1" },
59  { NULL, "${EXTEN}", "s" },
60  { "Gosub", "tests_test_gosub_virtual_context,s,1(5,5,5,5,5)" },
61  { NULL, "${PRIORITY}", "1" },
62  { NULL, "$[0${ARG1} + 0${ARG5}]", "10" },
63  { NULL, "${STACK_PEEK(1,e)}", "s" },
64  { NULL, "${STACK_PEEK(1,c)}", "tests_test_gosub_virtual_context" },
65  { NULL, "${STACK_PEEK(1,p)}", "1" },
66  { NULL, "${STACK_PEEK(1,l)}", "tests_test_gosub_virtual_context,s,1" },
67  { "StackPop", "" },
68  { NULL, "${STACK_PEEK(1,e,1)}", "" }, /* Only 1 frame deep, my caller is top-level */
69  { "Gosub", "tests_test_gosub_virtual_context,s,1(5,5,5,5,5)" },
70  { "Gosub", "tests_test_gosub_virtual_context,s,1(4,4,4,4)" },
71  { NULL, "$[0${ARG1} + 0${ARG5}]", "4" },
72  { NULL, "$[0${ARG1} + 0${ARG4}]", "8" },
73  { "Gosub", "tests_test_gosub_virtual_context,s,1(3,3,3)" },
74  { NULL, "$[0${ARG1} + 0${ARG4}]", "3" },
75  { NULL, "$[0${ARG1} + 0${ARG3}]", "6" },
76  { "Gosub", "tests_test_gosub_virtual_context,s,1(2,2)" },
77  { NULL, "$[0${ARG1} + 0${ARG3}]", "2" },
78  { NULL, "$[0${ARG1} + 0${ARG2}]", "4" },
79  { "Gosub", "tests_test_gosub_virtual_context,s,1(1)" },
80  { NULL, "$[0${ARG1} + 0${ARG2}]", "1" },
81  { NULL, "$[0${ARG1} + 0${ARG1}]", "2" },
82  { "Gosub", "tests_test_gosub_virtual_context,s,1" },
83  { NULL, "$[0${ARG1} + 0${ARG1}]", "0" }, /* All arguments are correctly masked */
84  { "Set", "LOCAL(foo)=5" },
85  { NULL, "${foo}", "5" }, /* LOCAL() set a variable correctly */
86  { NULL, "${LOCAL_PEEK(0,ARG1)}", "" }, /* LOCAL_PEEK() arguments work correctly */
87  { NULL, "${LOCAL_PEEK(4,ARG1)}", "4" }, /* LOCAL_PEEK() arguments work correctly */
88  { NULL, "$[0${LOCAL_PEEK(3,ARG1)} + 0${LOCAL_PEEK(5,ARG1)}]", "8" },
89  { "StackPop", "" },
90  { NULL, "${foo}", "" }, /* StackPop removed the variable set with LOCAL() */
91  { "Return", "7" },
92  { NULL, "${GOSUB_RETVAL}", "7" }, /* Return sets a return value correctly */
93  { NULL, "$[0${GOSUB_RETVAL} + 0${ARG1}]", "9" }, /* Two frames less means ARG1 should have 2 */
94  };
95 
96  switch (cmd) {
97  case TEST_INIT:
98  info->name = "gosub application";
99  info->category = "/apps/app_gosub/";
100  info->summary = "Verify functionality of gosub application";
101  info->description =
102  "Verify functionality of gosub application";
103  return AST_TEST_NOT_RUN;
104  case TEST_EXECUTE:
105  break;
106  }
107 
108  if (!(chan = ast_dummy_channel_alloc())) {
109  ast_test_status_update(test, "Unable to allocate dummy channel\n");
110  return AST_TEST_FAIL;
111  }
112 
113  if (!(str = ast_str_create(16))) {
114  ast_test_status_update(test, "Unable to allocate dynamic string buffer\n");
115  ast_channel_unref(chan);
116  return AST_TEST_FAIL;
117  }
118 
119  /* Create our test dialplan */
120  if (!ast_context_find_or_create(NULL, NULL, CONTEXT_NAME, "test_gosub")) {
121  ast_test_status_update(test, "Unable to create test dialplan context");
122  ast_free(str);
123  ast_channel_unref(chan);
124  return AST_TEST_FAIL;
125  }
126 
127  ast_add_extension(CONTEXT_NAME, 1, "s", 1, NULL, NULL, "NoOp", ast_strdup(""), ast_free_ptr, "test_gosub");
128 
129  for (i = 0; i < ARRAY_LEN(testplan); i++) {
130  if (testplan[i].app == NULL) {
131  /* Evaluation */
132  ast_str_substitute_variables(&str, 0, chan, testplan[i].args);
133  if (strcmp(ast_str_buffer(str), testplan[i].expected_value)) {
134  ast_test_status_update(test, "Evaluation of '%s' returned '%s' instead of the expected value '%s'\n",
135  testplan[i].args, ast_str_buffer(str), testplan[i].expected_value);
136  res = AST_TEST_FAIL;
137  }
138  } else {
139  /* Run application */
140  intptr_t exec_res;
141  struct ast_app *app = pbx_findapp(testplan[i].app);
142  if (!app) {
143  ast_test_status_update(test, "Could not find '%s' in application listing!\n", testplan[i].app);
144  res = AST_TEST_FAIL;
145  break;
146  }
147 
148  if ((exec_res = pbx_exec(chan, app, testplan[i].args)) && ((const char *) exec_res != testplan[i].expected_value)) {
149  ast_test_status_update(test, "Application '%s' exited abnormally (with code %d)\n", testplan[i].app, (int) exec_res);
150  res = AST_TEST_FAIL;
151  break;
152  }
153  }
154  }
155 
156  ast_free(str);
157  ast_channel_unref(chan);
159  ast_context_destroy(NULL, "test_gosub");
160 
161  return res;
162 }
163 
164 static int unload_module(void)
165 {
166  AST_TEST_UNREGISTER(test_gosub);
167  return 0;
168 }
169 
170 static int load_module(void)
171 {
172  AST_TEST_REGISTER(test_gosub);
174 }
175 
Main Channel structure associated with a channel.
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:567
Asterisk main include file. File version handling, generic pbx functions.
static int unload_module(void)
Definition: test_gosub.c:164
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data)
Execute an application.
Definition: pbx_app.c:471
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2981
AST_TEST_DEFINE(test_gosub)
Definition: test_gosub.c:41
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
#define CONTEXT_NAME
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
Test Framework API.
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
static int load_module(void)
Definition: test_gosub.c:170
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
const char * str
Definition: app_jack.c:147
const char * args
#define NULL
Definition: resample.c:96
void ast_free_ptr(void *ptr)
free() wrapper
Definition: astmm.c:1771
int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
Simply remove extension from context.
Definition: pbx.c:4952
Utility functions.
General Asterisk PBX channel definitions.
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define ast_dummy_channel_alloc()
Create a fake channel structure.
Definition: channel.h:1283
Core PBX routines and definitions.
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128
def info(msg)
#define ast_free(a)
Definition: astmm.h:182
int ast_add_extension(const char *context, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar)
Add and extension to an extension context.
Definition: pbx.c:6970
ast_app: A registered application
Definition: pbx_app.c:45
void ast_context_destroy(struct ast_context *con, const char *registrar)
Destroy a context (matches the specified context or ANY context if NULL)
Definition: conf2ael.c:625
struct ast_context * ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
Register a new context or find an existing one.
Definition: pbx.c:6198
struct ast_app * pbx_findapp(const char *app)
Look up an application.
Definition: ael_main.c:165
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
static const char app[]
Definition: app_mysql.c:62
Asterisk module definitions.
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620