loader: Add dependency fields to module structures.
[asterisk/asterisk.git] / tests / test_ari_model.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * David M. Lee, II <dlee@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 Test the native ARI JSON validators.
22  *
23  * \author David M. Lee, II <dlee@digium.com>
24  */
25
26 /*** MODULEINFO
27         <depend>TEST_FRAMEWORK</depend>
28         <depend>res_ari_model</depend>
29         <support_level>core</support_level>
30  ***/
31
32 #include "asterisk.h"
33
34 #include "asterisk/utils.h"
35 #include "asterisk/module.h"
36 #include "asterisk/test.h"
37 #include "../res/ari/ari_model_validators.h"
38
39 #if defined(TEST_FRAMEWORK)
40 /*!
41  * Wrapper of ast_test_validate_int() so an external function pointer is not used.
42  *
43  * \note Must do this because using an external function pointer
44  * does not play nicely when loading with RTLD_LAZY.
45  */
46 static int wrap_ast_ari_validate_int(struct ast_json *json)
47 {
48         return ast_ari_validate_int(json);
49 }
50 #endif  /* defined(TEST_FRAMEWORK) */
51
52 #if defined(TEST_FRAMEWORK)
53 /*!
54  * Wrapper of ast_ari_validate_string() so an external function pointer is not used.
55  *
56  * \note Must do this because using an external function pointer
57  * does not play nicely when loading with RTLD_LAZY.
58  */
59 static int wrap_ast_ari_validate_string(struct ast_json *json)
60 {
61         return ast_ari_validate_string(json);
62 }
63 #endif  /* defined(TEST_FRAMEWORK) */
64
65 AST_TEST_DEFINE(validate_byte)
66 {
67         RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
68         RAII_VAR(struct ast_json *, str, NULL, ast_json_unref);
69         int res;
70
71         switch (cmd) {
72         case TEST_INIT:
73                 info->name = __func__;
74                 info->category = "/ari/validators/";
75                 info->summary = "Test byte validation";
76                 info->description =
77                         "Test byte validation";
78                 return AST_TEST_NOT_RUN;
79         case TEST_EXECUTE:
80                 break;
81         }
82
83         uut = ast_json_integer_create(-128);
84         ast_test_validate(test, NULL != uut);
85         ast_test_validate(test, ast_ari_validate_byte(uut));
86
87         res = ast_json_integer_set(uut, 0);
88         ast_test_validate(test, 0 == res);
89         ast_test_validate(test, ast_ari_validate_byte(uut));
90
91         res = ast_json_integer_set(uut, 255);
92         ast_test_validate(test, 0 == res);
93         ast_test_validate(test, ast_ari_validate_byte(uut));
94
95         res = ast_json_integer_set(uut, -129);
96         ast_test_validate(test, 0 == res);
97         ast_test_validate(test, !ast_ari_validate_byte(uut));
98
99         res = ast_json_integer_set(uut, 256);
100         ast_test_validate(test, 0 == res);
101         ast_test_validate(test, !ast_ari_validate_byte(uut));
102
103         str = ast_json_string_create("not a byte");
104         ast_test_validate(test, NULL != str);
105         ast_test_validate(test, !ast_ari_validate_byte(str));
106
107         /* Even if the string has an integral value */
108         res = ast_json_string_set(str, "0");
109         ast_test_validate(test, 0 == res);
110         ast_test_validate(test, !ast_ari_validate_byte(str));
111
112         ast_test_validate(test, !ast_ari_validate_byte(ast_json_null()));
113
114         return AST_TEST_PASS;
115 }
116
117 AST_TEST_DEFINE(validate_boolean)
118 {
119         RAII_VAR(struct ast_json *, str, NULL, ast_json_unref);
120         int res;
121
122         switch (cmd) {
123         case TEST_INIT:
124                 info->name = __func__;
125                 info->category = "/ari/validators/";
126                 info->summary = "Test byte validation";
127                 info->description =
128                         "Test byte validation";
129                 return AST_TEST_NOT_RUN;
130         case TEST_EXECUTE:
131                 break;
132         }
133
134         ast_test_validate(test, ast_ari_validate_boolean(ast_json_true()));
135         ast_test_validate(test, ast_ari_validate_boolean(ast_json_false()));
136
137         str = ast_json_string_create("not a bool");
138         ast_test_validate(test, NULL != str);
139         ast_test_validate(test, !ast_ari_validate_boolean(str));
140
141         /* Even if the string has a boolean value */
142         res = ast_json_string_set(str, "true");
143         ast_test_validate(test, 0 == res);
144         ast_test_validate(test, !ast_ari_validate_boolean(str));
145
146         /* Even if the string has a boolean text in it */
147         res = ast_json_string_set(str, "true");
148         ast_test_validate(test, 0 == res);
149         ast_test_validate(test, !ast_ari_validate_boolean(str));
150
151         ast_test_validate(test, !ast_ari_validate_boolean(ast_json_null()));
152
153         return AST_TEST_PASS;
154 }
155
156 AST_TEST_DEFINE(validate_int)
157 {
158         RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
159         RAII_VAR(struct ast_json *, str, NULL, ast_json_unref);
160         int res;
161
162         switch (cmd) {
163         case TEST_INIT:
164                 info->name = __func__;
165                 info->category = "/ari/validators/";
166                 info->summary = "Test int validation";
167                 info->description =
168                         "Test int validation";
169                 return AST_TEST_NOT_RUN;
170         case TEST_EXECUTE:
171                 break;
172         }
173
174         uut = ast_json_integer_create(-2147483648LL);
175         ast_test_validate(test, NULL != uut);
176         ast_test_validate(test, ast_ari_validate_int(uut));
177
178         res = ast_json_integer_set(uut, 0);
179         ast_test_validate(test, 0 == res);
180         ast_test_validate(test, ast_ari_validate_int(uut));
181
182         res = ast_json_integer_set(uut, 2147483647LL);
183         ast_test_validate(test, 0 == res);
184         ast_test_validate(test, ast_ari_validate_int(uut));
185
186         res = ast_json_integer_set(uut, -2147483649LL);
187         ast_test_validate(test, 0 == res);
188         ast_test_validate(test, !ast_ari_validate_int(uut));
189
190         res = ast_json_integer_set(uut, 2147483648LL);
191         ast_test_validate(test, 0 == res);
192         ast_test_validate(test, !ast_ari_validate_int(uut));
193
194         str = ast_json_string_create("not a int");
195         ast_test_validate(test, NULL != str);
196         ast_test_validate(test, !ast_ari_validate_int(str));
197
198         /* Even if the string has an integral value */
199         res = ast_json_string_set(str, "0");
200         ast_test_validate(test, 0 == res);
201         ast_test_validate(test, !ast_ari_validate_int(str));
202
203         ast_test_validate(test, !ast_ari_validate_int(ast_json_null()));
204
205         return AST_TEST_PASS;
206 }
207
208 AST_TEST_DEFINE(validate_long)
209 {
210         RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
211         RAII_VAR(struct ast_json *, str, NULL, ast_json_unref);
212         int res;
213
214         switch (cmd) {
215         case TEST_INIT:
216                 info->name = __func__;
217                 info->category = "/ari/validators/";
218                 info->summary = "Test long validation";
219                 info->description =
220                         "Test long validation";
221                 return AST_TEST_NOT_RUN;
222         case TEST_EXECUTE:
223                 break;
224         }
225
226         uut = ast_json_integer_create(0);
227         ast_test_validate(test, NULL != uut);
228         ast_test_validate(test, ast_ari_validate_long(uut));
229
230         str = ast_json_string_create("not a long");
231         ast_test_validate(test, NULL != str);
232         ast_test_validate(test, !ast_ari_validate_long(str));
233
234         /* Even if the string has an integral value */
235         res = ast_json_string_set(str, "0");
236         ast_test_validate(test, 0 == res);
237         ast_test_validate(test, !ast_ari_validate_long(str));
238
239         ast_test_validate(test, !ast_ari_validate_long(ast_json_null()));
240
241         return AST_TEST_PASS;
242 }
243
244 AST_TEST_DEFINE(validate_string)
245 {
246         RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
247         RAII_VAR(struct ast_json *, str, NULL, ast_json_unref);
248         int res;
249
250         switch (cmd) {
251         case TEST_INIT:
252                 info->name = __func__;
253                 info->category = "/ari/validators/";
254                 info->summary = "Test string validation";
255                 info->description =
256                         "Test string validation";
257                 return AST_TEST_NOT_RUN;
258         case TEST_EXECUTE:
259                 break;
260         }
261
262         uut = ast_json_string_create("text");
263         ast_test_validate(test, NULL != uut);
264         ast_test_validate(test, ast_ari_validate_string(uut));
265
266         res = ast_json_string_set(uut, "");
267         ast_test_validate(test, 0 == res);
268         ast_test_validate(test, ast_ari_validate_string(uut));
269
270         ast_test_validate(test, !ast_ari_validate_string(ast_json_null()));
271
272         return AST_TEST_PASS;
273 }
274
275 AST_TEST_DEFINE(validate_date)
276 {
277         RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
278         RAII_VAR(struct ast_json *, str, NULL, ast_json_unref);
279         enum ast_test_result_state test_res;
280         int res;
281         int i;
282         const char *valid_dates[] = {
283                 /* Time is optional */
284                 "2013-06-17",
285                 /* Seconds are optional */
286                 "2013-06-17T23:59Z",
287                 /* Subseconds are optional */
288                 "2013-06-17T23:59:59Z",
289                 /* Leap seconds are valid */
290                 "2013-06-30T23:59:61Z",
291                 /* Subseconds are allowed */
292                 "2013-06-17T23:59:59.999999Z",
293                 /* Now with -06:00 for the timezone */
294                 "2013-06-17T23:59-06:00",
295                 "2013-06-17T23:59:59-06:00",
296                 "2013-06-30T23:59:61-06:00",
297                 "2013-06-17T23:59:59.999999-06:00",
298                 /* Again, with +06:30 for the timezone */
299                 "2013-06-17T23:59+06:30",
300                 "2013-06-17T23:59:59+06:30",
301                 "2013-06-30T23:59:61+06:30",
302                 "2013-06-17T23:59:59.999999+06:30",
303                 /* So the colon in the timezone is optional */
304                 "2013-06-17T23:59-0600",
305                 "2013-06-17T23:59:59-0600",
306                 "2013-06-30T23:59:61-0600",
307                 "2013-06-17T23:59:59.999999-0600",
308                 /* Sure, why not */
309                 "2013-06-17T23:59+0630",
310                 "2013-06-17T23:59:59+0630",
311                 "2013-06-30T23:59:61+0630",
312                 "2013-06-17T23:59:59.999999+0630",
313                 "9999-12-31T23:59:61.999999Z",
314                 /* In fact, you don't even have to specify minutes */
315                 "2013-06-17T23:59-06",
316                 "2013-06-17T23:59:59-06",
317                 "2013-06-30T23:59:61-06",
318                 "2013-06-17T23:59:59.999999-06",
319         };
320
321         /* There are lots of invalid dates that the validator lets through.
322          * Those would be strings properly formatted as a ridiculous date. Such
323          * as 0000-00-00, or 9999-19-39. Those are harder to catch with a regex,
324          * and actually aren't as important. So long as the valid dates pass the
325          * validator, and poorly formatted dates are rejected, it's fine.
326          * Catching the occasional ridiculous date is just bonus.
327          */
328         const char *invalid_dates[] = {
329                 "",
330                 "Not a date",
331                 "2013-06-17T", /* Missing time, but has T */
332                 "2013-06-17T23:59:59.Z", /* Missing subsecond, but has dot */
333                 "2013-06-17T23:59", /* Missing timezone, but has time */
334                 "2013-06-17T23:59:59.999999", /* Missing timezone */
335                 "9999-99-31T23:59:61.999999Z", /* Invalid month */
336                 "9999-12-99T23:59:61.999999Z", /* Invalid day */
337                 "9999-12-31T99:59:61.999999Z", /* Invalid hour */
338                 "9999-12-31T23:99:61.999999Z", /* Invalid minute */
339                 "9999-12-31T23:59:99.999999Z", /* Invalid second */
340                 "2013-06-17T23:59:59.999999-99:00", /* Invalid timezone */
341                 "2013-06-17T23:59:59.999999-06:99", /* Invalid timezone */
342                 "2013-06-17T23:59:59.999999-06:", /* Invalid timezone */
343                 "2013-06-17T23:59:59.999999-06:0", /* Invalid timezone */
344                 "2013-06-17T23:59:59.999999-060", /* Invalid timezone */
345         };
346
347         switch (cmd) {
348         case TEST_INIT:
349                 info->name = __func__;
350                 info->category = "/ari/validators/";
351                 info->summary = "Test date validation";
352                 info->description =
353                         "Test date validation";
354                 return AST_TEST_NOT_RUN;
355         case TEST_EXECUTE:
356                 break;
357         }
358
359         uut = ast_json_string_create("");
360         ast_test_validate(test, NULL != uut);
361
362         /* Instead of using ast_test_validate, we'll collect the results from
363          * several test cases, since we have so many */
364         test_res = AST_TEST_PASS;
365         for (i = 0; i < ARRAY_LEN(valid_dates); ++i) {
366                 res = ast_json_string_set(uut, valid_dates[i]);
367                 ast_test_validate(test, 0 == res);
368                 if (!ast_ari_validate_date(uut)) {
369                         ast_test_status_update(test,
370                                 "Expected '%s' to be a valid date\n",
371                                 valid_dates[i]);
372                         test_res = AST_TEST_FAIL;
373                 }
374         }
375
376         for (i = 0; i < ARRAY_LEN(invalid_dates); ++i) {
377                 res = ast_json_string_set(uut, invalid_dates[i]);
378                 ast_test_validate(test, 0 == res);
379                 if (ast_ari_validate_date(uut)) {
380                         ast_test_status_update(test,
381                                 "Expected '%s' to be an invalid date\n",
382                                 invalid_dates[i]);
383                         test_res = AST_TEST_FAIL;
384                 }
385         }
386
387         ast_test_validate(test, !ast_ari_validate_string(ast_json_null()));
388
389         return test_res;
390 }
391
392 AST_TEST_DEFINE(validate_list)
393 {
394         RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
395         RAII_VAR(struct ast_json *, str, NULL, ast_json_unref);
396         int res;
397
398         switch (cmd) {
399         case TEST_INIT:
400                 info->name = __func__;
401                 info->category = "/ari/validators/";
402                 info->summary = "Test list validation";
403                 info->description =
404                         "Test list validation";
405                 return AST_TEST_NOT_RUN;
406         case TEST_EXECUTE:
407                 break;
408         }
409
410         uut = ast_json_array_create();
411         ast_test_validate(test, NULL != uut);
412         ast_test_validate(test, ast_ari_validate_list(uut, wrap_ast_ari_validate_string));
413         ast_test_validate(test, ast_ari_validate_list(uut, wrap_ast_ari_validate_int));
414
415         res = ast_json_array_append(uut, ast_json_string_create(""));
416         ast_test_validate(test, 0 == res);
417         ast_test_validate(test, ast_ari_validate_list(uut, wrap_ast_ari_validate_string));
418         ast_test_validate(test, !ast_ari_validate_list(uut, wrap_ast_ari_validate_int));
419
420         res = ast_json_array_append(uut, ast_json_integer_create(0));
421         ast_test_validate(test, 0 == res);
422         ast_test_validate(test, !ast_ari_validate_list(uut, wrap_ast_ari_validate_string));
423         ast_test_validate(test, !ast_ari_validate_list(uut, wrap_ast_ari_validate_int));
424
425         ast_test_validate(test,
426                 !ast_ari_validate_list(ast_json_null(), wrap_ast_ari_validate_string));
427
428         return AST_TEST_PASS;
429 }
430
431 static int unload_module(void)
432 {
433         AST_TEST_UNREGISTER(validate_byte);
434         AST_TEST_UNREGISTER(validate_boolean);
435         AST_TEST_UNREGISTER(validate_int);
436         AST_TEST_UNREGISTER(validate_long);
437         AST_TEST_UNREGISTER(validate_string);
438         AST_TEST_UNREGISTER(validate_date);
439         AST_TEST_UNREGISTER(validate_list);
440         return 0;
441 }
442
443 static int load_module(void)
444 {
445         AST_TEST_REGISTER(validate_byte);
446         AST_TEST_REGISTER(validate_boolean);
447         AST_TEST_REGISTER(validate_int);
448         AST_TEST_REGISTER(validate_long);
449         AST_TEST_REGISTER(validate_string);
450         AST_TEST_REGISTER(validate_date);
451         AST_TEST_REGISTER(validate_list);
452         return AST_MODULE_LOAD_SUCCESS;
453 }
454
455 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Skeleton (sample) Test",
456         .support_level = AST_MODULE_SUPPORT_CORE,
457         .load = load_module,
458         .unload = unload_module,
459         .requires = "res_ari_model",
460 );