Asterisk - The Open Source Telephony Project  18.5.0
test_linkedlists.c
Go to the documentation of this file.
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 <[email protected]>
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;
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 
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);
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) {
232  }
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) {
255  }
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) {
277  }
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) {
299  }
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) {
315  MATCH_OR_FAIL(&test_list, "ABD", buf);
317  MATCH_OR_FAIL(&test_list, "ABCD", buf);
319  MATCH_OR_FAIL(&test_list, "ABC", buf);
320  }
321  }
323  MATCH_OR_FAIL(&test_list, "ABC", buf);
324  AST_LIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, list) {
326  }
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);
451 
452  AST_DLLIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, dbl_list) {
454  }
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) {
477  }
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) {
496  MATCH_OR_FAIL_DBL(&test_list, "ABD", buf);
498  MATCH_OR_FAIL_DBL(&test_list, "ABCD", buf);
500  MATCH_OR_FAIL_DBL(&test_list, "ABC", buf);
501  }
502  }
504  MATCH_OR_FAIL_DBL(&test_list, "ABC", buf);
505  AST_DLLIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, dbl_list) {
507  }
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) {
521  MATCH_OR_FAIL_DBL(&test_list, "ABD", buf);
523  MATCH_OR_FAIL_DBL(&test_list, "ABCD", buf);
525  MATCH_OR_FAIL_DBL(&test_list, "ACD", buf);
526  }
527  }
529  MATCH_OR_FAIL_DBL(&test_list, "ACD", buf);
530  AST_DLLIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, dbl_list) {
532  }
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) {
544  MATCH_OR_FAIL_DBL(&test_list, "AB", buf);
546  MATCH_OR_FAIL_DBL(&test_list, "ABD", buf);
548  MATCH_OR_FAIL_DBL(&test_list, "ABCD", buf);
550  MATCH_OR_FAIL_DBL(&test_list, "ACD", buf);
551  }
552  }
554  MATCH_OR_FAIL_DBL(&test_list, "ACD", buf);
555  AST_DLLIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, dbl_list) {
557  }
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);
574  if (bogus == &d) {
576  MATCH_OR_FAIL_DBL(&test_list, "ABD", buf);
578  MATCH_OR_FAIL_DBL(&test_list, "ABCD", buf);
580  MATCH_OR_FAIL_DBL(&test_list, "ABC", buf);
581  }
582  }
584  MATCH_OR_FAIL_DBL(&test_list, "ABC", buf);
587  }
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);
599  if (bogus == &b) {
601  MATCH_OR_FAIL_DBL(&test_list, "ABD", buf);
603  MATCH_OR_FAIL_DBL(&test_list, "ABCD", buf);
605  MATCH_OR_FAIL_DBL(&test_list, "ACD", buf);
606  }
607  }
609  MATCH_OR_FAIL_DBL(&test_list, "ACD", buf);
610  AST_DLLIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, dbl_list) {
612  }
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);
622  if (bogus == &b) {
624  MATCH_OR_FAIL_DBL(&test_list, "AB", buf);
626  MATCH_OR_FAIL_DBL(&test_list, "ABD", buf);
628  MATCH_OR_FAIL_DBL(&test_list, "ABCD", buf);
630  MATCH_OR_FAIL_DBL(&test_list, "ACD", buf);
631  }
632  }
634  MATCH_OR_FAIL_DBL(&test_list, "ACD", buf);
635  AST_DLLIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, dbl_list) {
637  }
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);
659 }
660 
#define AST_DLLIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: dlinkedlists.h:848
static int dbl_list_expect_forward(struct test_dbl_llist *test_list, const char *expect, struct ast_str **buf)
#define AST_LIST_INSERT_LIST_AFTER(head, list, elm, field)
Inserts a whole list after a specific entry in a list.
Definition: linkedlists.h:811
#define AST_DLLIST_TRAVERSE_BACKWARDS(head, var, field)
Loops over (traverses) the entries in a list in reverse order, starting at the end.
Definition: dlinkedlists.h:617
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:567
Asterisk main include file. File version handling, generic pbx functions.
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:420
#define AST_DLLIST_INSERT_BEFORE(head, listelm, elm, field)
Inserts a list entry before a given entry.
String manipulation functions.
#define AST_DLLIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
static struct test_val d
#define AST_DLLIST_REMOVE_VERIFY(head, elm, field)
Removes a specific node from a list if it is in the list.
struct test_val::@513 dbl_list
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:438
#define AST_DLLIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
#define AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: dlinkedlists.h:887
Test Framework API.
#define AST_DLLIST_INSERT_AFTER(head, listelm, elm, field)
Inserts a list entry after a given entry.
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1091
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:449
static int load_module(void)
#define AST_DLLIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: dlinkedlists.h:752
static struct test_val c
const char * str
Definition: app_jack.c:147
#define NULL
Definition: resample.c:96
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
Definition: linkedlists.h:855
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:614
#define AST_DLLIST_INSERT_AFTER_CURRENT(elm, field)
Inserts a list node after the current node during a traversal.
Definition: dlinkedlists.h:722
#define AST_LIST_INSERT_AFTER(head, listelm, elm, field)
Inserts a list entry after a given entry.
Definition: linkedlists.h:694
#define AST_DLLIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
#define AST_DLLIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: dlinkedlists.h:445
A set of macros to manage doubly-linked lists.
#define AST_DLLIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
Definition: dlinkedlists.h:211
static int dbl_list_expect_reverse(struct test_dbl_llist *test_list, const char *expect, struct ast_str **buf)
#define AST_DLLIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: dlinkedlists.h:575
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:556
static int list_expect(struct test_llist *test_list, const char *expect, struct ast_str **buf)
A set of macros to manage forward-linked lists.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
AST_LIST_HEAD_NOLOCK(contactliststruct, contact)
#define AST_DLLIST_INSERT_BEFORE_CURRENT(elm, field)
Inserts a list node before the current node during a traversal.
Definition: dlinkedlists.h:695
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
#define AST_DLLIST_APPEND_DLLIST(head, list, field)
Appends a whole list to the tail of a list.
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
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)
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define AST_LIST_LAST(head)
Returns the last entry contained in a list.
Definition: linkedlists.h:428
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:409
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:710
#define ast_free(a)
Definition: astmm.h:182
static int unload_module(void)
#define AST_DLLIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: dlinkedlists.h:468
#define MATCH_OR_FAIL_DBL(list, val, retbuf)
#define AST_DLLIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: dlinkedlists.h:912
#define ELEM_OR_FAIL(x, y)
Support for logging to various files, console and syslog Configuration in file logger.conf.
#define MATCH_OR_FAIL(list, val, retbuf)
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
Definition: strings.h:653
#define AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END
Closes a safe loop traversal block.
Definition: dlinkedlists.h:920
const char * name
#define AST_DLLIST_PREV(elm, field)
Returns the previous entry in the list before the given entry.
Definition: dlinkedlists.h:456
struct test_val::@512 list
#define AST_DLLIST_REMOVE_TAIL(head, field)
Removes and returns the tail node from a list.
#define AST_DLLIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
static struct test_val b
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:528
#define AST_LIST_INSERT_BEFORE_CURRENT(elm, field)
Inserts a list entry before the current entry during a traversal.
Definition: linkedlists.h:598
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Asterisk module definitions.
#define AST_DLLIST_FIRST(head)
Returns the first entry contained in a list.
Definition: dlinkedlists.h:421
#define AST_DLLIST_LAST(head)
Returns the last entry contained in a list.
Definition: dlinkedlists.h:430
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620
#define AST_DLLIST_ENTRY(type)
Declare previous/forward links inside a list entry.
Definition: dlinkedlists.h:412
#define AST_LIST_APPEND_LIST(head, list, field)
Appends a whole list to the tail of a list.
Definition: linkedlists.h:782
static struct test_val a
AST_TEST_DEFINE(single_ll_tests)