Loader: Remove unneeded load_pri declarations.
[asterisk/asterisk.git] / tests / test_linkedlists.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2011, Terry Wilson
5  *
6  * See http://www.asterisk.org for more information about
7  * the Asterisk project. Please do not directly contact
8  * any of the maintainers of this project for assistance;
9  * the project provides a web site, mailing lists and IRC
10  * channels for your use.
11  *
12  * This program is free software, distributed under the terms of
13  * the GNU General Public License Version 2. See the LICENSE file
14  * at the top of the source tree.
15  */
16
17 /*! \file
18  *
19  * \brief Linked List Tests
20  *
21  * \author Terry Wilson <twilson@digium.com>
22  *
23  * \ingroup tests
24  */
25
26 /*** MODULEINFO
27         <depend>TEST_FRAMEWORK</depend>
28         <support_level>core</support_level>
29  ***/
30
31 #include "asterisk.h"
32
33 #include "asterisk/module.h"
34 #include "asterisk/test.h"
35 #include "asterisk/strings.h"
36 #include "asterisk/logger.h"
37 #include "asterisk/linkedlists.h"
38 #include "asterisk/dlinkedlists.h"
39
40 struct test_val {
41         const char *name;
42         AST_LIST_ENTRY(test_val) list;
43         AST_DLLIST_ENTRY(test_val) dbl_list;
44 };
45
46 static struct test_val a = { "A" };
47 static struct test_val b = { "B" };
48 static struct test_val c = { "C" };
49 static struct test_val d = { "D" };
50
51 AST_LIST_HEAD_NOLOCK(test_llist, test_val);
52 AST_DLLIST_HEAD_NOLOCK(test_dbl_llist, test_val);
53
54 static int list_expect(struct test_llist *test_list, const char *expect, struct ast_str **buf)
55 {
56         struct test_val *i;
57
58         ast_str_reset(*buf);
59         AST_LIST_TRAVERSE(test_list, i, list) {
60                 ast_str_append(buf, 0, "%s", i->name);
61         }
62
63         return strcmp(expect, ast_str_buffer(*buf));
64 }
65
66 static int dbl_list_expect_forward(struct test_dbl_llist *test_list, const char *expect, struct ast_str **buf)
67 {
68         struct test_val *i;
69
70         ast_str_reset(*buf);
71         AST_DLLIST_TRAVERSE(test_list, i, dbl_list) {
72                 ast_str_append(buf, 0, "%s", i->name);
73         }
74
75         return strcmp(expect, ast_str_buffer(*buf));
76 }
77
78 static int dbl_list_expect_reverse(struct test_dbl_llist *test_list, const char *expect, struct ast_str **buf)
79 {
80         struct test_val *i;
81         char *str;
82         int len = strlen(expect);
83         int idx;
84
85         ast_str_reset(*buf);
86         AST_DLLIST_TRAVERSE_BACKWARDS(test_list, i, dbl_list) {
87                 ast_str_append(buf, 0, "%s", i->name);
88         }
89
90         /* Check reverse string. */
91         str = ast_str_buffer(*buf);
92         if (len != strlen(str)) {
93                 return 1;
94         }
95         for (idx = 0; idx < len; ++idx) {
96                 if (expect[idx] != str[len - idx - 1]) {
97                         return 1;
98                 }
99         }
100         return 0;
101 }
102
103 #define MATCH_OR_FAIL(list, val, retbuf) \
104         if (list_expect(list, val, &retbuf)) { \
105                 ast_test_status_update(test, "Expected: %s, Got: %s\n", val, ast_str_buffer(retbuf)); \
106                 return AST_TEST_FAIL; \
107         }
108
109 #define MATCH_OR_FAIL_DBL(list, val, retbuf) \
110         if (dbl_list_expect_forward(list, val, &retbuf)) { \
111                 ast_test_status_update(test, "Expected: %s, Got: %s\n", val, ast_str_buffer(retbuf)); \
112                 return AST_TEST_FAIL; \
113         } \
114         if (dbl_list_expect_reverse(list, val, &retbuf)) { \
115                 ast_test_status_update(test, "Expected reverse of: %s, Got: %s\n", val, ast_str_buffer(retbuf)); \
116                 return AST_TEST_FAIL; \
117         }
118
119 #define ELEM_OR_FAIL(x,y) \
120         if ((x) != (y)) { \
121                 ast_test_status_update(test, "Expected: %s, Got: %s\n", (x)->name, (y)->name); \
122                 return AST_TEST_FAIL; \
123         }
124
125 AST_TEST_DEFINE(single_ll_tests)
126 {
127         RAII_VAR(struct ast_str *, buf, NULL, ast_free);
128         struct test_llist test_list = { 0, };
129         struct test_llist other_list = { 0, };
130         struct test_val *bogus;
131
132         switch (cmd) {
133         case TEST_INIT:
134                 info->name = "ll_tests";
135                 info->category = "/main/linkedlists/";
136                 info->summary = "single linked list unit test";
137                 info->description =
138                         "Test the single linked list API";
139                 return AST_TEST_NOT_RUN;
140         case TEST_EXECUTE:
141                 break;
142         }
143
144         if (!(buf = ast_str_create(16))) {
145                 return AST_TEST_FAIL;
146         }
147
148         if (!(bogus = ast_alloca(sizeof(*bogus)))) {
149                 return AST_TEST_FAIL;
150         }
151
152         if (AST_LIST_REMOVE(&test_list, bogus, list)) {
153                 ast_test_status_update(test, "AST_LIST_REMOVE should safely return NULL for missing element from empty list\n");
154                 return AST_TEST_FAIL;
155         }
156
157         /* INSERT_HEAD and REMOVE_HEAD tests */
158         AST_LIST_INSERT_HEAD(&test_list, &a, list);
159         MATCH_OR_FAIL(&test_list, "A", buf);
160         AST_LIST_INSERT_HEAD(&test_list, &b, list);
161         MATCH_OR_FAIL(&test_list, "BA", buf);
162         AST_LIST_REMOVE_HEAD(&test_list, list);
163         MATCH_OR_FAIL(&test_list, "A", buf);
164         AST_LIST_REMOVE_HEAD(&test_list, list);
165         MATCH_OR_FAIL(&test_list, "", buf);
166         if (AST_LIST_REMOVE_HEAD(&test_list, list)) {
167                 ast_test_status_update(test, "Somehow removed an item from the head of a list that didn't exist\n");
168                 return AST_TEST_FAIL;
169         }
170         MATCH_OR_FAIL(&test_list, "", buf);
171
172         /* Check empty list test */
173
174         if (!AST_LIST_EMPTY(&test_list)) {
175                 ast_test_status_update(test, "List should be empty\n");
176                 return AST_TEST_FAIL;
177         }
178
179         /* Insert tail and remove specific item tests. */
180
181         AST_LIST_INSERT_TAIL(&test_list, &a, list);
182         MATCH_OR_FAIL(&test_list, "A", buf);
183         AST_LIST_INSERT_TAIL(&test_list, &b, list);
184         MATCH_OR_FAIL(&test_list, "AB", buf);
185         AST_LIST_INSERT_TAIL(&test_list, &c, list);
186         MATCH_OR_FAIL(&test_list, "ABC", buf);
187         AST_LIST_INSERT_TAIL(&test_list, &d, list);
188         MATCH_OR_FAIL(&test_list, "ABCD", buf);
189         if (AST_LIST_REMOVE(&test_list, bogus, list)) {
190                 ast_test_status_update(test, "AST_LIST_REMOVE should safely return NULL for missing element\n");
191                 return AST_TEST_FAIL;
192         }
193         bogus = NULL;
194         if (AST_LIST_REMOVE(&test_list, bogus, list)) {
195                 ast_test_status_update(test, "AST_LIST_REMOVE should safely return NULL for element set to NULL\n");
196                 return AST_TEST_FAIL;
197         }
198         AST_LIST_REMOVE(&test_list, &b, list);
199         MATCH_OR_FAIL(&test_list, "ACD", buf);
200         AST_LIST_REMOVE(&test_list, &d, list);
201         MATCH_OR_FAIL(&test_list, "AC", buf);
202         AST_LIST_REMOVE(&test_list, &a, list);
203         MATCH_OR_FAIL(&test_list, "C", buf);
204         AST_LIST_REMOVE(&test_list, &c, list);
205         MATCH_OR_FAIL(&test_list, "", buf);
206         if (!AST_LIST_EMPTY(&test_list)) {
207                 ast_test_status_update(test, "List should be empty\n");
208                 return AST_TEST_FAIL;
209         }
210         if (AST_LIST_REMOVE(&test_list, bogus, list)) {
211                 ast_test_status_update(test, "AST_LIST_REMOVE should safely return NULL asked to remove a NULL pointer from an empty list\n");
212                 return AST_TEST_FAIL;
213         }
214
215         /* Insert item after specific item tests */
216
217         AST_LIST_INSERT_HEAD(&test_list, &a, list);
218         MATCH_OR_FAIL(&test_list, "A", buf);
219         AST_LIST_INSERT_TAIL(&test_list, &c, list);
220         MATCH_OR_FAIL(&test_list, "AC", buf);
221         AST_LIST_INSERT_AFTER(&test_list, &a, &b, list);
222         MATCH_OR_FAIL(&test_list, "ABC", buf);
223         AST_LIST_INSERT_AFTER(&test_list, &c, &d, list);
224         MATCH_OR_FAIL(&test_list, "ABCD", buf);
225
226         ELEM_OR_FAIL(AST_LIST_FIRST(&test_list), &a);
227         ELEM_OR_FAIL(AST_LIST_LAST(&test_list), &d);
228         ELEM_OR_FAIL(AST_LIST_NEXT(&a, list), &b);
229
230         AST_LIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, list) {
231                 AST_LIST_REMOVE_CURRENT(list);
232         }
233         AST_LIST_TRAVERSE_SAFE_END;
234
235         if (!AST_LIST_EMPTY(&test_list)) {
236                 ast_test_status_update(test, "List should be empty after traversing and removal. It wasn't.\n");
237                 return AST_TEST_FAIL;
238         }
239
240         /* Append list test */
241
242         AST_LIST_INSERT_HEAD(&test_list, &a, list);
243         MATCH_OR_FAIL(&test_list, "A", buf);
244         AST_LIST_INSERT_TAIL(&test_list, &b, list);
245         MATCH_OR_FAIL(&test_list, "AB", buf);
246         AST_LIST_INSERT_HEAD(&other_list, &c, list);
247         MATCH_OR_FAIL(&other_list, "C", buf);
248         AST_LIST_INSERT_TAIL(&other_list, &d, list);
249         MATCH_OR_FAIL(&other_list, "CD", buf);
250         AST_LIST_APPEND_LIST(&test_list, &other_list, list);
251         MATCH_OR_FAIL(&test_list, "ABCD", buf);
252         MATCH_OR_FAIL(&other_list, "", buf);
253         AST_LIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, list) {
254                 AST_LIST_REMOVE_CURRENT(list);
255         }
256         AST_LIST_TRAVERSE_SAFE_END;
257         if (!AST_LIST_EMPTY(&test_list)) {
258                 ast_test_status_update(test, "List should be empty after traversing and removal. It wasn't.\n");
259                 return AST_TEST_FAIL;
260         }
261
262         /* Insert list after specific item in middle test */
263
264         AST_LIST_INSERT_HEAD(&test_list, &a, list);
265         MATCH_OR_FAIL(&test_list, "A", buf);
266         AST_LIST_INSERT_TAIL(&test_list, &d, list);
267         MATCH_OR_FAIL(&test_list, "AD", buf);
268         AST_LIST_INSERT_HEAD(&other_list, &b, list);
269         MATCH_OR_FAIL(&other_list, "B", buf);
270         AST_LIST_INSERT_TAIL(&other_list, &c, list);
271         MATCH_OR_FAIL(&other_list, "BC", buf);
272         AST_LIST_INSERT_LIST_AFTER(&test_list, &other_list, &a, list);
273         MATCH_OR_FAIL(&test_list, "ABCD", buf);
274         MATCH_OR_FAIL(&other_list, "", buf);
275         AST_LIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, list) {
276                 AST_LIST_REMOVE_CURRENT(list);
277         }
278         AST_LIST_TRAVERSE_SAFE_END;
279         if (!AST_LIST_EMPTY(&test_list)) {
280                 ast_test_status_update(test, "List should be empty after traversing and removal. It wasn't.\n");
281                 return AST_TEST_FAIL;
282         }
283
284         /* Insert list after specific item on end test */
285
286         AST_LIST_INSERT_HEAD(&test_list, &a, list);
287         MATCH_OR_FAIL(&test_list, "A", buf);
288         AST_LIST_INSERT_TAIL(&test_list, &b, list);
289         MATCH_OR_FAIL(&test_list, "AB", buf);
290         AST_LIST_INSERT_HEAD(&other_list, &c, list);
291         MATCH_OR_FAIL(&other_list, "C", buf);
292         AST_LIST_INSERT_TAIL(&other_list, &d, list);
293         MATCH_OR_FAIL(&other_list, "CD", buf);
294         AST_LIST_INSERT_LIST_AFTER(&test_list, &other_list, &b, list);
295         MATCH_OR_FAIL(&test_list, "ABCD", buf);
296         MATCH_OR_FAIL(&other_list, "", buf);
297         AST_LIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, list) {
298                 AST_LIST_REMOVE_CURRENT(list);
299         }
300         AST_LIST_TRAVERSE_SAFE_END;
301         if (!AST_LIST_EMPTY(&test_list)) {
302                 ast_test_status_update(test, "List should be empty after traversing and removal. It wasn't.\n");
303                 return AST_TEST_FAIL;
304         }
305
306         /* Safe traversal list modification tests */
307
308         AST_LIST_INSERT_HEAD(&test_list, &a, list);
309         MATCH_OR_FAIL(&test_list, "A", buf);
310         AST_LIST_INSERT_TAIL(&test_list, &d, list);
311         MATCH_OR_FAIL(&test_list, "AD", buf);
312         AST_LIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, list) {
313                 if (bogus == &d) {
314                         AST_LIST_INSERT_BEFORE_CURRENT(&b, list);
315                         MATCH_OR_FAIL(&test_list, "ABD", buf);
316                         AST_LIST_INSERT_BEFORE_CURRENT(&c, list);
317                         MATCH_OR_FAIL(&test_list, "ABCD", buf);
318                         AST_LIST_REMOVE_CURRENT(list);
319                         MATCH_OR_FAIL(&test_list, "ABC", buf);
320                 }
321         }
322         AST_LIST_TRAVERSE_SAFE_END;
323         MATCH_OR_FAIL(&test_list, "ABC", buf);
324         AST_LIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, list) {
325                 AST_LIST_REMOVE_CURRENT(list);
326         }
327         AST_LIST_TRAVERSE_SAFE_END;
328         if (!AST_LIST_EMPTY(&test_list)) {
329                 ast_test_status_update(test, "List should be empty after traversing and removal. It wasn't.\n");
330                 return AST_TEST_FAIL;
331         }
332
333         return AST_TEST_PASS;
334 }
335
336 AST_TEST_DEFINE(double_ll_tests)
337 {
338         RAII_VAR(struct ast_str *, buf, NULL, ast_free);
339         struct test_dbl_llist test_list = { 0, };
340         struct test_dbl_llist other_list = { 0, };
341         struct test_val *bogus;
342
343         switch (cmd) {
344         case TEST_INIT:
345                 info->name = "double_ll_tests";
346                 info->category = "/main/linkedlists/";
347                 info->summary = "double linked list unit test";
348                 info->description =
349                         "Test the double linked list API";
350                 return AST_TEST_NOT_RUN;
351         case TEST_EXECUTE:
352                 break;
353         }
354
355         if (!(buf = ast_str_create(16))) {
356                 return AST_TEST_FAIL;
357         }
358
359         bogus = ast_alloca(sizeof(*bogus));
360
361         if (AST_DLLIST_REMOVE_VERIFY(&test_list, bogus, dbl_list)) {
362                 ast_test_status_update(test, "AST_DLLIST_REMOVE_VERIFY should safely return NULL for missing element from empty list\n");
363                 return AST_TEST_FAIL;
364         }
365
366         /* INSERT_HEAD and REMOVE_HEAD tests */
367         AST_DLLIST_INSERT_HEAD(&test_list, &a, dbl_list);
368         MATCH_OR_FAIL_DBL(&test_list, "A", buf);
369         AST_DLLIST_INSERT_HEAD(&test_list, &b, dbl_list);
370         MATCH_OR_FAIL_DBL(&test_list, "BA", buf);
371         AST_DLLIST_REMOVE_HEAD(&test_list, dbl_list);
372         MATCH_OR_FAIL_DBL(&test_list, "A", buf);
373         AST_DLLIST_REMOVE_HEAD(&test_list, dbl_list);
374         MATCH_OR_FAIL_DBL(&test_list, "", buf);
375         if (AST_DLLIST_REMOVE_HEAD(&test_list, dbl_list)) {
376                 ast_test_status_update(test, "Somehow removed an item from the head of a list that didn't exist\n");
377                 return AST_TEST_FAIL;
378         }
379         MATCH_OR_FAIL_DBL(&test_list, "", buf);
380
381         /* Check empty list test */
382
383         if (!AST_DLLIST_EMPTY(&test_list)) {
384                 ast_test_status_update(test, "List should be empty\n");
385                 return AST_TEST_FAIL;
386         }
387
388         /* Insert tail and remove specific item tests. */
389
390         AST_DLLIST_INSERT_TAIL(&test_list, &a, dbl_list);
391         MATCH_OR_FAIL_DBL(&test_list, "A", buf);
392         AST_DLLIST_INSERT_TAIL(&test_list, &b, dbl_list);
393         MATCH_OR_FAIL_DBL(&test_list, "AB", buf);
394         AST_DLLIST_INSERT_TAIL(&test_list, &c, dbl_list);
395         MATCH_OR_FAIL_DBL(&test_list, "ABC", buf);
396         AST_DLLIST_INSERT_TAIL(&test_list, &d, dbl_list);
397         MATCH_OR_FAIL_DBL(&test_list, "ABCD", buf);
398         if (AST_DLLIST_REMOVE_VERIFY(&test_list, bogus, dbl_list)) {
399                 ast_test_status_update(test, "AST_DLLIST_REMOVE_VERIFY should safely return NULL for missing element\n");
400                 return AST_TEST_FAIL;
401         }
402         bogus = NULL;
403         if (AST_DLLIST_REMOVE_VERIFY(&test_list, bogus, dbl_list)) {
404                 ast_test_status_update(test, "AST_DLLIST_REMOVE_VERIFY should safely return NULL for element set to NULL\n");
405                 return AST_TEST_FAIL;
406         }
407         AST_DLLIST_REMOVE(&test_list, &b, dbl_list);
408         MATCH_OR_FAIL_DBL(&test_list, "ACD", buf);
409         AST_DLLIST_REMOVE(&test_list, &d, dbl_list);
410         MATCH_OR_FAIL_DBL(&test_list, "AC", buf);
411         AST_DLLIST_REMOVE(&test_list, &a, dbl_list);
412         MATCH_OR_FAIL_DBL(&test_list, "C", buf);
413         AST_DLLIST_REMOVE(&test_list, &c, dbl_list);
414         MATCH_OR_FAIL_DBL(&test_list, "", buf);
415         if (!AST_DLLIST_EMPTY(&test_list)) {
416                 ast_test_status_update(test, "List should be empty\n");
417                 return AST_TEST_FAIL;
418         }
419         if (AST_DLLIST_REMOVE_VERIFY(&test_list, bogus, dbl_list)) {
420                 ast_test_status_update(test, "AST_DLLIST_REMOVE_VERIFY should safely return NULL asked to remove a NULL pointer from an empty list\n");
421                 return AST_TEST_FAIL;
422         }
423
424         /* Insert item after and before specific item tests */
425
426         AST_DLLIST_INSERT_HEAD(&test_list, &a, dbl_list);
427         MATCH_OR_FAIL_DBL(&test_list, "A", buf);
428         AST_DLLIST_INSERT_TAIL(&test_list, &c, dbl_list);
429         MATCH_OR_FAIL_DBL(&test_list, "AC", buf);
430         AST_DLLIST_INSERT_AFTER(&test_list, &a, &b, dbl_list);
431         MATCH_OR_FAIL_DBL(&test_list, "ABC", buf);
432         AST_DLLIST_INSERT_AFTER(&test_list, &c, &d, dbl_list);
433         MATCH_OR_FAIL_DBL(&test_list, "ABCD", buf);
434         AST_DLLIST_REMOVE_TAIL(&test_list, dbl_list);
435         MATCH_OR_FAIL_DBL(&test_list, "ABC", buf);
436         AST_DLLIST_REMOVE_TAIL(&test_list, dbl_list);
437         MATCH_OR_FAIL_DBL(&test_list, "AB", buf);
438         AST_DLLIST_INSERT_TAIL(&test_list, &d, dbl_list);
439         MATCH_OR_FAIL_DBL(&test_list, "ABD", buf);
440         AST_DLLIST_INSERT_BEFORE(&test_list, &d, &c, dbl_list);
441         MATCH_OR_FAIL_DBL(&test_list, "ABCD", buf);
442         AST_DLLIST_REMOVE_HEAD(&test_list, dbl_list);
443         MATCH_OR_FAIL_DBL(&test_list, "BCD", buf);
444         AST_DLLIST_INSERT_BEFORE(&test_list, &b, &a, dbl_list);
445         MATCH_OR_FAIL_DBL(&test_list, "ABCD", buf);
446
447         ELEM_OR_FAIL(AST_DLLIST_FIRST(&test_list), &a);
448         ELEM_OR_FAIL(AST_DLLIST_LAST(&test_list), &d);
449         ELEM_OR_FAIL(AST_DLLIST_NEXT(&a, dbl_list), &b);
450         ELEM_OR_FAIL(AST_DLLIST_PREV(&b, dbl_list), &a);
451
452         AST_DLLIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, dbl_list) {
453                 AST_DLLIST_REMOVE_CURRENT(dbl_list);
454         }
455         AST_DLLIST_TRAVERSE_SAFE_END;
456
457         if (!AST_DLLIST_EMPTY(&test_list)) {
458                 ast_test_status_update(test, "List should be empty after traversing and removal. It wasn't.\n");
459                 return AST_TEST_FAIL;
460         }
461
462         /* Append list test */
463
464         AST_DLLIST_INSERT_HEAD(&test_list, &a, dbl_list);
465         MATCH_OR_FAIL_DBL(&test_list, "A", buf);
466         AST_DLLIST_INSERT_TAIL(&test_list, &b, dbl_list);
467         MATCH_OR_FAIL_DBL(&test_list, "AB", buf);
468         AST_DLLIST_INSERT_HEAD(&other_list, &c, dbl_list);
469         MATCH_OR_FAIL_DBL(&other_list, "C", buf);
470         AST_DLLIST_INSERT_TAIL(&other_list, &d, dbl_list);
471         MATCH_OR_FAIL_DBL(&other_list, "CD", buf);
472         AST_DLLIST_APPEND_DLLIST(&test_list, &other_list, dbl_list);
473         MATCH_OR_FAIL_DBL(&test_list, "ABCD", buf);
474         MATCH_OR_FAIL_DBL(&other_list, "", buf);
475         AST_DLLIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, dbl_list) {
476                 AST_DLLIST_REMOVE_CURRENT(dbl_list);
477         }
478         AST_DLLIST_TRAVERSE_SAFE_END;
479         if (!AST_DLLIST_EMPTY(&test_list)) {
480                 ast_test_status_update(test, "List should be empty after traversing and removal. It wasn't.\n");
481                 return AST_TEST_FAIL;
482         }
483
484         /*
485          * Safe traversal list modification tests
486          * Traverse starting from first element
487          */
488
489         AST_DLLIST_INSERT_HEAD(&test_list, &a, dbl_list);
490         MATCH_OR_FAIL_DBL(&test_list, "A", buf);
491         AST_DLLIST_INSERT_TAIL(&test_list, &d, dbl_list);
492         MATCH_OR_FAIL_DBL(&test_list, "AD", buf);
493         AST_DLLIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, dbl_list) {
494                 if (bogus == &d) {
495                         AST_DLLIST_INSERT_BEFORE_CURRENT(&b, dbl_list);
496                         MATCH_OR_FAIL_DBL(&test_list, "ABD", buf);
497                         AST_DLLIST_INSERT_BEFORE_CURRENT(&c, dbl_list);
498                         MATCH_OR_FAIL_DBL(&test_list, "ABCD", buf);
499                         AST_DLLIST_REMOVE_CURRENT(dbl_list);
500                         MATCH_OR_FAIL_DBL(&test_list, "ABC", buf);
501                 }
502         }
503         AST_DLLIST_TRAVERSE_SAFE_END;
504         MATCH_OR_FAIL_DBL(&test_list, "ABC", buf);
505         AST_DLLIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, dbl_list) {
506                 AST_DLLIST_REMOVE_CURRENT(dbl_list);
507         }
508         AST_DLLIST_TRAVERSE_SAFE_END;
509         if (!AST_DLLIST_EMPTY(&test_list)) {
510                 ast_test_status_update(test, "List should be empty after traversing and removal. It wasn't.\n");
511                 return AST_TEST_FAIL;
512         }
513
514         AST_DLLIST_INSERT_HEAD(&test_list, &b, dbl_list);
515         MATCH_OR_FAIL_DBL(&test_list, "B", buf);
516         AST_DLLIST_INSERT_TAIL(&test_list, &d, dbl_list);
517         MATCH_OR_FAIL_DBL(&test_list, "BD", buf);
518         AST_DLLIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, dbl_list) {
519                 if (bogus == &b) {
520                         AST_DLLIST_INSERT_BEFORE_CURRENT(&a, dbl_list);
521                         MATCH_OR_FAIL_DBL(&test_list, "ABD", buf);
522                         AST_DLLIST_INSERT_AFTER_CURRENT(&c, dbl_list);
523                         MATCH_OR_FAIL_DBL(&test_list, "ABCD", buf);
524                         AST_DLLIST_REMOVE_CURRENT(dbl_list);
525                         MATCH_OR_FAIL_DBL(&test_list, "ACD", buf);
526                 }
527         }
528         AST_DLLIST_TRAVERSE_SAFE_END;
529         MATCH_OR_FAIL_DBL(&test_list, "ACD", buf);
530         AST_DLLIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, dbl_list) {
531                 AST_DLLIST_REMOVE_CURRENT(dbl_list);
532         }
533         AST_DLLIST_TRAVERSE_SAFE_END;
534         if (!AST_DLLIST_EMPTY(&test_list)) {
535                 ast_test_status_update(test, "List should be empty after traversing and removal. It wasn't.\n");
536                 return AST_TEST_FAIL;
537         }
538
539         AST_DLLIST_INSERT_HEAD(&test_list, &b, dbl_list);
540         MATCH_OR_FAIL_DBL(&test_list, "B", buf);
541         AST_DLLIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, dbl_list) {
542                 if (bogus == &b) {
543                         AST_DLLIST_INSERT_BEFORE_CURRENT(&a, dbl_list);
544                         MATCH_OR_FAIL_DBL(&test_list, "AB", buf);
545                         AST_DLLIST_INSERT_AFTER_CURRENT(&d, dbl_list);
546                         MATCH_OR_FAIL_DBL(&test_list, "ABD", buf);
547                         AST_DLLIST_INSERT_AFTER_CURRENT(&c, dbl_list);
548                         MATCH_OR_FAIL_DBL(&test_list, "ABCD", buf);
549                         AST_DLLIST_REMOVE_CURRENT(dbl_list);
550                         MATCH_OR_FAIL_DBL(&test_list, "ACD", buf);
551                 }
552         }
553         AST_DLLIST_TRAVERSE_SAFE_END;
554         MATCH_OR_FAIL_DBL(&test_list, "ACD", buf);
555         AST_DLLIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, dbl_list) {
556                 AST_DLLIST_REMOVE_CURRENT(dbl_list);
557         }
558         AST_DLLIST_TRAVERSE_SAFE_END;
559         if (!AST_DLLIST_EMPTY(&test_list)) {
560                 ast_test_status_update(test, "List should be empty after traversing and removal. It wasn't.\n");
561                 return AST_TEST_FAIL;
562         }
563
564         /*
565          * Safe traversal list modification tests
566          * Traverse starting from last element
567          */
568
569         AST_DLLIST_INSERT_HEAD(&test_list, &a, dbl_list);
570         MATCH_OR_FAIL_DBL(&test_list, "A", buf);
571         AST_DLLIST_INSERT_TAIL(&test_list, &d, dbl_list);
572         MATCH_OR_FAIL_DBL(&test_list, "AD", buf);
573         AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_BEGIN(&test_list, bogus, dbl_list) {
574                 if (bogus == &d) {
575                         AST_DLLIST_INSERT_BEFORE_CURRENT(&b, dbl_list);
576                         MATCH_OR_FAIL_DBL(&test_list, "ABD", buf);
577                         AST_DLLIST_INSERT_BEFORE_CURRENT(&c, dbl_list);
578                         MATCH_OR_FAIL_DBL(&test_list, "ABCD", buf);
579                         AST_DLLIST_REMOVE_CURRENT(dbl_list);
580                         MATCH_OR_FAIL_DBL(&test_list, "ABC", buf);
581                 }
582         }
583         AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END;
584         MATCH_OR_FAIL_DBL(&test_list, "ABC", buf);
585         AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_BEGIN(&test_list, bogus, dbl_list) {
586                 AST_DLLIST_REMOVE_CURRENT(dbl_list);
587         }
588         AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END;
589         if (!AST_DLLIST_EMPTY(&test_list)) {
590                 ast_test_status_update(test, "List should be empty after traversing and removal. It wasn't.\n");
591                 return AST_TEST_FAIL;
592         }
593
594         AST_DLLIST_INSERT_HEAD(&test_list, &b, dbl_list);
595         MATCH_OR_FAIL_DBL(&test_list, "B", buf);
596         AST_DLLIST_INSERT_TAIL(&test_list, &d, dbl_list);
597         MATCH_OR_FAIL_DBL(&test_list, "BD", buf);
598         AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_BEGIN(&test_list, bogus, dbl_list) {
599                 if (bogus == &b) {
600                         AST_DLLIST_INSERT_BEFORE_CURRENT(&a, dbl_list);
601                         MATCH_OR_FAIL_DBL(&test_list, "ABD", buf);
602                         AST_DLLIST_INSERT_AFTER_CURRENT(&c, dbl_list);
603                         MATCH_OR_FAIL_DBL(&test_list, "ABCD", buf);
604                         AST_DLLIST_REMOVE_CURRENT(dbl_list);
605                         MATCH_OR_FAIL_DBL(&test_list, "ACD", buf);
606                 }
607         }
608         AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END;
609         MATCH_OR_FAIL_DBL(&test_list, "ACD", buf);
610         AST_DLLIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, dbl_list) {
611                 AST_DLLIST_REMOVE_CURRENT(dbl_list);
612         }
613         AST_DLLIST_TRAVERSE_SAFE_END;
614         if (!AST_DLLIST_EMPTY(&test_list)) {
615                 ast_test_status_update(test, "List should be empty after traversing and removal. It wasn't.\n");
616                 return AST_TEST_FAIL;
617         }
618
619         AST_DLLIST_INSERT_HEAD(&test_list, &b, dbl_list);
620         MATCH_OR_FAIL_DBL(&test_list, "B", buf);
621         AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_BEGIN(&test_list, bogus, dbl_list) {
622                 if (bogus == &b) {
623                         AST_DLLIST_INSERT_BEFORE_CURRENT(&a, dbl_list);
624                         MATCH_OR_FAIL_DBL(&test_list, "AB", buf);
625                         AST_DLLIST_INSERT_AFTER_CURRENT(&d, dbl_list);
626                         MATCH_OR_FAIL_DBL(&test_list, "ABD", buf);
627                         AST_DLLIST_INSERT_AFTER_CURRENT(&c, dbl_list);
628                         MATCH_OR_FAIL_DBL(&test_list, "ABCD", buf);
629                         AST_DLLIST_REMOVE_CURRENT(dbl_list);
630                         MATCH_OR_FAIL_DBL(&test_list, "ACD", buf);
631                 }
632         }
633         AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END;
634         MATCH_OR_FAIL_DBL(&test_list, "ACD", buf);
635         AST_DLLIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, dbl_list) {
636                 AST_DLLIST_REMOVE_CURRENT(dbl_list);
637         }
638         AST_DLLIST_TRAVERSE_SAFE_END;
639         if (!AST_DLLIST_EMPTY(&test_list)) {
640                 ast_test_status_update(test, "List should be empty after traversing and removal. It wasn't.\n");
641                 return AST_TEST_FAIL;
642         }
643
644         return AST_TEST_PASS;
645 }
646
647 static int unload_module(void)
648 {
649         AST_TEST_UNREGISTER(single_ll_tests);
650         AST_TEST_UNREGISTER(double_ll_tests);
651         return 0;
652 }
653
654 static int load_module(void)
655 {
656         AST_TEST_REGISTER(single_ll_tests);
657         AST_TEST_REGISTER(double_ll_tests);
658         return AST_MODULE_LOAD_SUCCESS;
659 }
660
661 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Test Linked Lists");