Merge "test_http_media_cache: Fix failing test."
[asterisk/asterisk.git] / tests / test_dlinklists.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2008, Steve Murphy
5  *
6  * Steve Murphy <murf@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 /*! \file
20  *
21  * \brief Doubly-Linked List Tests
22  *
23  * \author\verbatim Steve Murphy <murf@digium.com> \endverbatim
24  * 
25  * This module will run some DLL tests at load time
26  * \ingroup tests
27  */
28
29 /*** MODULEINFO
30         <depend>TEST_FRAMEWORK</depend>
31         <support_level>core</support_level>
32  ***/
33
34 #include "asterisk.h"
35
36 ASTERISK_REGISTER_FILE()
37
38 #include "asterisk/file.h"
39 #include "asterisk/channel.h"
40 #include "asterisk/pbx.h"
41 #include "asterisk/module.h"
42 #include "asterisk/lock.h"
43 #include "asterisk/app.h"
44
45
46 #include "asterisk/dlinkedlists.h"
47
48 /* Tests for DLLists! We really should, and here is a nice place to do it in asterisk */
49
50 struct test1
51 {
52         char name[10];
53         AST_DLLIST_ENTRY(test1) list;
54 };
55
56 struct test_container
57 {
58         AST_DLLIST_HEAD(entries, test1) entries;
59     int count;
60 };
61
62 static void print_list(struct test_container *x, char *expect)
63 {
64         struct test1 *t1;
65         char buff[1000];
66         buff[0] = 0;
67         AST_DLLIST_TRAVERSE(&x->entries, t1, list) {
68                 strcat(buff,t1->name);
69                 if (t1 != AST_DLLIST_LAST(&x->entries))
70                         strcat(buff," <=> ");
71         }
72         
73         ast_debug(1,"Got: %s  [expect %s]\n", buff, expect);
74 }
75
76 static void print_list_backwards(struct test_container *x, char *expect)
77 {
78         struct test1 *t1;
79         char buff[1000];
80         buff[0] = 0;
81         AST_DLLIST_TRAVERSE_BACKWARDS(&x->entries, t1, list) {
82                 strcat(buff,t1->name);
83                 if (t1 != AST_DLLIST_FIRST(&x->entries))
84                         strcat(buff," <=> ");
85         }
86         
87         ast_debug(1,"Got: %s  [expect %s]\n", buff, expect);
88 }
89
90 static struct test_container *make_cont(void)
91 {
92         struct test_container *t = ast_calloc(sizeof(struct test_container),1);
93         return t;
94 }
95
96 static struct test1 *make_test1(char *name)
97 {
98         struct test1 *t1 = ast_calloc(sizeof(struct test1),1);
99         strcpy(t1->name, name);
100         return t1;
101 }
102
103 static void destroy_test_container(struct test_container *x)
104 {
105         /* remove all the test1's */
106         struct test1 *t1;
107         AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_BEGIN(&x->entries, t1, list) {
108                 AST_DLLIST_REMOVE_CURRENT(list);
109                 ast_free(t1);
110         }
111         AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END;
112         ast_free(x);
113 }
114
115 /* Macros to test:
116 AST_DLLIST_LOCK(head)
117 AST_RWDLLIST_WRLOCK(head)
118 AST_RWDLLIST_WRLOCK(head) 
119 AST_RWDLLIST_RDLOCK(head)
120 AST_DLLIST_TRYLOCK(head)
121 AST_RWDLLIST_TRYWRLOCK(head)
122 AST_RWDLLIST_TRYRDLOCK(head)
123 AST_DLLIST_UNLOCK(head)
124 AST_RWDLLIST_UNLOCK(head)
125
126 AST_DLLIST_HEAD(name, type)
127 AST_RWDLLIST_HEAD(name, type)
128 AST_DLLIST_HEAD_NOLOCK(name, type)
129 AST_DLLIST_HEAD_STATIC(name, type)
130 AST_RWDLLIST_HEAD_STATIC(name, type)
131 AST_DLLIST_HEAD_NOLOCK_STATIC(name, type)
132 AST_DLLIST_HEAD_SET(head, entry)
133 AST_RWDLLIST_HEAD_SET(head, entry)
134 AST_DLLIST_HEAD_SET_NOLOCK(head, entry)
135 AST_DLLIST_HEAD_INIT(head)
136 AST_RWDLLIST_HEAD_INIT(head)
137 AST_DLLIST_HEAD_INIT_NOLOCK(head)
138
139 AST_RWDLLIST_HEAD_DESTROY(head)
140
141 AST_DLLIST_ENTRY(type)
142
143 --- the above not going to be dealt with here ---
144
145 AST_DLLIST_INSERT_HEAD(head, elm, field)
146 AST_DLLIST_TRAVERSE(head,var,field)
147 AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_BEGIN(head, var, field)
148 AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END
149 AST_DLLIST_FIRST(head)
150 AST_DLLIST_LAST(head)
151 AST_DLLIST_NEXT(elm, field)
152 AST_DLLIST_PREV(elm, field)
153 AST_DLLIST_EMPTY(head)
154 AST_DLLIST_TRAVERSE_BACKWARDS(head,var,field)
155 AST_DLLIST_INSERT_AFTER(head, listelm, elm, field)
156 AST_DLLIST_INSERT_TAIL(head, elm, field)
157 AST_DLLIST_REMOVE_HEAD(head, field)
158 AST_DLLIST_REMOVE(head, elm, field)
159 AST_DLLIST_TRAVERSE_SAFE_BEGIN(head, var, field)
160 AST_DLLIST_TRAVERSE_SAFE_END
161 AST_DLLIST_REMOVE_CURRENT(field)
162 AST_DLLIST_MOVE_CURRENT(newhead, field)
163 AST_DLLIST_INSERT_BEFORE_CURRENT(elm, field) 
164
165
166 AST_DLLIST_MOVE_CURRENT_BACKWARDS(newhead, field)
167 AST_DLLIST_INSERT_BEFORE_CURRENT_BACKWARDS(elm, field)
168 AST_DLLIST_HEAD_DESTROY(head)
169
170 AST_DLLIST_APPEND_DLLIST(head, list, field)
171
172 */
173
174 static void dll_tests(void)
175 {
176         struct test_container *tc;
177         struct test1 *a;
178         struct test1 *b;
179         struct test1 *c;
180         struct test1 *d;
181         struct test1 *e;
182         
183         ast_debug(1,"Test AST_DLLIST_INSERT_HEAD, AST_DLLIST_TRAVERSE, AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_BEGIN, AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END\n");
184         tc = make_cont();
185         a = make_test1("A");
186         b = make_test1("B");
187         c = make_test1("C");
188         d = make_test1("D");
189         AST_DLLIST_INSERT_HEAD(&tc->entries, d, list);
190         AST_DLLIST_INSERT_HEAD(&tc->entries, c, list);
191         AST_DLLIST_INSERT_HEAD(&tc->entries, b, list);
192         AST_DLLIST_INSERT_HEAD(&tc->entries, a, list);
193         print_list(tc, "A <=> B <=> C <=> D");
194
195         destroy_test_container(tc);
196         
197         tc = make_cont();
198
199         if (AST_DLLIST_EMPTY(&tc->entries))
200                 ast_debug(1,"Test AST_DLLIST_EMPTY....OK\n");
201         else
202                 ast_log(LOG_ERROR,"Test AST_DLLIST_EMPTY....PROBLEM!!\n");
203
204
205         a = make_test1("A");
206         b = make_test1("B");
207         c = make_test1("C");
208         d = make_test1("D");
209         
210         ast_debug(1,"Test AST_DLLIST_INSERT_TAIL\n");
211         AST_DLLIST_INSERT_TAIL(&tc->entries, a, list);
212         AST_DLLIST_INSERT_TAIL(&tc->entries, b, list);
213         AST_DLLIST_INSERT_TAIL(&tc->entries, c, list);
214         AST_DLLIST_INSERT_TAIL(&tc->entries, d, list);
215         print_list(tc, "A <=> B <=> C <=> D");
216
217         if (AST_DLLIST_FIRST(&tc->entries) == a)
218                 ast_debug(1,"Test AST_DLLIST_FIRST....OK\n");
219         else
220                 ast_log(LOG_ERROR,"Test AST_DLLIST_FIRST....PROBLEM\n");
221
222         if (AST_DLLIST_LAST(&tc->entries) == d)
223                 ast_debug(1,"Test AST_DLLIST_LAST....OK\n");
224         else
225                 ast_log(LOG_ERROR,"Test AST_DLLIST_LAST....PROBLEM\n");
226
227         if (AST_DLLIST_NEXT(a,list) == b)
228                 ast_debug(1,"Test AST_DLLIST_NEXT....OK\n");
229         else
230                 ast_log(LOG_ERROR,"Test AST_DLLIST_NEXT....PROBLEM\n");
231
232         if (AST_DLLIST_PREV(d,list) == c)
233                 ast_debug(1,"Test AST_DLLIST_PREV....OK\n");
234         else
235                 ast_log(LOG_ERROR,"Test AST_DLLIST_PREV....PROBLEM\n");
236
237         destroy_test_container(tc);
238
239         tc = make_cont();
240
241         a = make_test1("A");
242         b = make_test1("B");
243         c = make_test1("C");
244         d = make_test1("D");
245
246         ast_debug(1,"Test AST_DLLIST_INSERT_AFTER, AST_DLLIST_TRAVERSE_BACKWARDS\n");
247         AST_DLLIST_INSERT_HEAD(&tc->entries, a, list);
248         AST_DLLIST_INSERT_AFTER(&tc->entries, a, b, list);
249         AST_DLLIST_INSERT_AFTER(&tc->entries, b, c, list);
250         AST_DLLIST_INSERT_AFTER(&tc->entries, c, d, list);
251         print_list_backwards(tc, "D <=> C <=> B <=> A");
252
253         ast_debug(1,"Test AST_DLLIST_REMOVE_HEAD\n");
254         AST_DLLIST_REMOVE_HEAD(&tc->entries, list);
255         print_list_backwards(tc, "D <=> C <=> B");
256         ast_debug(1,"Test AST_DLLIST_REMOVE_HEAD\n");
257         AST_DLLIST_REMOVE_HEAD(&tc->entries, list);
258         print_list_backwards(tc, "D <=> C");
259         ast_debug(1,"Test AST_DLLIST_REMOVE_HEAD\n");
260         AST_DLLIST_REMOVE_HEAD(&tc->entries, list);
261         print_list_backwards(tc, "D");
262         AST_DLLIST_REMOVE_HEAD(&tc->entries, list);
263
264         if (AST_DLLIST_EMPTY(&tc->entries))
265                 ast_debug(1,"Test AST_DLLIST_REMOVE_HEAD....OK\n");
266         else
267                 ast_log(LOG_ERROR,"Test AST_DLLIST_REMOVE_HEAD....PROBLEM!!\n");
268
269         AST_DLLIST_INSERT_HEAD(&tc->entries, a, list);
270         AST_DLLIST_INSERT_AFTER(&tc->entries, a, b, list);
271         AST_DLLIST_INSERT_AFTER(&tc->entries, b, c, list);
272         AST_DLLIST_INSERT_AFTER(&tc->entries, c, d, list);
273
274         ast_debug(1,"Test AST_DLLIST_REMOVE\n");
275         AST_DLLIST_REMOVE(&tc->entries, c, list);
276         print_list(tc, "A <=> B <=> D");
277         AST_DLLIST_REMOVE(&tc->entries, a, list);
278         print_list(tc, "B <=> D");
279         AST_DLLIST_REMOVE(&tc->entries, d, list);
280         print_list(tc, "B");
281         AST_DLLIST_REMOVE(&tc->entries, b, list);
282         
283         if (AST_DLLIST_EMPTY(&tc->entries))
284                 ast_debug(1,"Test AST_DLLIST_REMOVE....OK\n");
285         else
286                 ast_log(LOG_ERROR,"Test AST_DLLIST_REMOVE....PROBLEM!!\n");
287
288         AST_DLLIST_INSERT_HEAD(&tc->entries, a, list);
289         AST_DLLIST_INSERT_AFTER(&tc->entries, a, b, list);
290         AST_DLLIST_INSERT_AFTER(&tc->entries, b, c, list);
291         AST_DLLIST_INSERT_AFTER(&tc->entries, c, d, list);
292
293         AST_DLLIST_TRAVERSE_SAFE_BEGIN(&tc->entries, e, list) {
294                 AST_DLLIST_REMOVE_CURRENT(list);
295         }
296         AST_DLLIST_TRAVERSE_SAFE_END;
297         if (AST_DLLIST_EMPTY(&tc->entries))
298                 ast_debug(1,"Test AST_DLLIST_REMOVE_CURRENT... OK\n");
299         else
300                 ast_log(LOG_ERROR,"Test AST_DLLIST_REMOVE_CURRENT... PROBLEM\n");
301         
302         ast_debug(1,"Test AST_DLLIST_MOVE_CURRENT, AST_DLLIST_INSERT_BEFORE_CURRENT\n");
303         AST_DLLIST_INSERT_HEAD(&tc->entries, a, list);
304         AST_DLLIST_INSERT_AFTER(&tc->entries, a, b, list);
305         AST_DLLIST_INSERT_AFTER(&tc->entries, b, c, list);
306         AST_DLLIST_TRAVERSE_SAFE_BEGIN(&tc->entries, e, list) {
307                 if (e == a) {
308                         AST_DLLIST_INSERT_BEFORE_CURRENT(d, list);  /* D A B C */
309                 }
310                 
311                 if (e == b) {
312                         AST_DLLIST_MOVE_CURRENT(&tc->entries, list); /* D A C B */
313                 }
314                 
315         }
316         AST_DLLIST_TRAVERSE_SAFE_END;
317         print_list(tc, "D <=> A <=> C <=> B");
318         
319         destroy_test_container(tc);
320
321         tc = make_cont();
322
323         a = make_test1("A");
324         b = make_test1("B");
325         c = make_test1("C");
326         d = make_test1("D");
327
328         ast_debug(1,"Test: AST_DLLIST_MOVE_CURRENT_BACKWARDS and AST_DLLIST_INSERT_BEFORE_CURRENT_BACKWARDS\n");
329         AST_DLLIST_INSERT_HEAD(&tc->entries, a, list);
330         AST_DLLIST_INSERT_AFTER(&tc->entries, a, b, list);
331         AST_DLLIST_INSERT_AFTER(&tc->entries, b, c, list);
332         AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_BEGIN(&tc->entries, e, list) {
333                 if (e == c && AST_DLLIST_FIRST(&tc->entries) != c) {
334                         AST_DLLIST_MOVE_CURRENT_BACKWARDS(&tc->entries, list); /* C A B */
335                         print_list(tc, "C <=> A <=> B");
336                 }
337
338                 if (e == b) {
339                         AST_DLLIST_REMOVE_CURRENT(list);  /* C A */
340                         ast_free(b);
341                         print_list(tc, "C <=> A");
342                 }
343                 if (e == a) {
344                         AST_DLLIST_INSERT_BEFORE_CURRENT_BACKWARDS(d, list); /* C A D */
345                         print_list(tc, "C <=> A <=> D");
346                 }
347                 
348         }
349         AST_DLLIST_TRAVERSE_SAFE_END;
350         print_list(tc, "C <=> A <=> D");
351
352         destroy_test_container(tc);
353 }
354
355 static int unload_module(void)
356 {
357         return 0;
358 }
359
360 static int load_module(void)
361 {
362         dll_tests();
363         return AST_MODULE_LOAD_SUCCESS;
364 }
365
366 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Test Doubly-Linked Lists");