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