Asterisk - The Open Source Telephony Project  GIT-master-93d0901
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 <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;
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 
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 
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 
87  ast_str_append(buf, 0, "%s", i->name);
88  }
89 
90  /* Check reverse string. */
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  memset(bogus, 0, sizeof(*bogus));
152 
153  if (AST_LIST_REMOVE(&test_list, bogus, list)) {
154  ast_test_status_update(test, "AST_LIST_REMOVE should safely return NULL for missing element from empty list\n");
155  return AST_TEST_FAIL;
156  }
157 
158  /* INSERT_HEAD and REMOVE_HEAD tests */
159  AST_LIST_INSERT_HEAD(&test_list, &a, list);
160  MATCH_OR_FAIL(&test_list, "A", buf);
161  AST_LIST_INSERT_HEAD(&test_list, &b, list);
162  MATCH_OR_FAIL(&test_list, "BA", buf);
163  AST_LIST_REMOVE_HEAD(&test_list, list);
164  MATCH_OR_FAIL(&test_list, "A", buf);
165  AST_LIST_REMOVE_HEAD(&test_list, list);
166  MATCH_OR_FAIL(&test_list, "", buf);
167  if (AST_LIST_REMOVE_HEAD(&test_list, list)) {
168  ast_test_status_update(test, "Somehow removed an item from the head of a list that didn't exist\n");
169  return AST_TEST_FAIL;
170  }
171  MATCH_OR_FAIL(&test_list, "", buf);
172 
173  /* Check empty list test */
174 
175  if (!AST_LIST_EMPTY(&test_list)) {
176  ast_test_status_update(test, "List should be empty\n");
177  return AST_TEST_FAIL;
178  }
179 
180  /* Insert tail and remove specific item tests. */
181 
182  AST_LIST_INSERT_TAIL(&test_list, &a, list);
183  MATCH_OR_FAIL(&test_list, "A", buf);
184  AST_LIST_INSERT_TAIL(&test_list, &b, list);
185  MATCH_OR_FAIL(&test_list, "AB", buf);
186  AST_LIST_INSERT_TAIL(&test_list, &c, list);
187  MATCH_OR_FAIL(&test_list, "ABC", buf);
188  AST_LIST_INSERT_TAIL(&test_list, &d, list);
189  MATCH_OR_FAIL(&test_list, "ABCD", buf);
190  if (AST_LIST_REMOVE(&test_list, bogus, list)) {
191  ast_test_status_update(test, "AST_LIST_REMOVE should safely return NULL for missing element\n");
192  return AST_TEST_FAIL;
193  }
194  bogus = NULL;
195  if (AST_LIST_REMOVE(&test_list, bogus, list)) {
196  ast_test_status_update(test, "AST_LIST_REMOVE should safely return NULL for element set to NULL\n");
197  return AST_TEST_FAIL;
198  }
199  AST_LIST_REMOVE(&test_list, &b, list);
200  MATCH_OR_FAIL(&test_list, "ACD", buf);
201  AST_LIST_REMOVE(&test_list, &d, list);
202  MATCH_OR_FAIL(&test_list, "AC", buf);
203  AST_LIST_REMOVE(&test_list, &a, list);
204  MATCH_OR_FAIL(&test_list, "C", buf);
205  AST_LIST_REMOVE(&test_list, &c, list);
206  MATCH_OR_FAIL(&test_list, "", buf);
207  if (!AST_LIST_EMPTY(&test_list)) {
208  ast_test_status_update(test, "List should be empty\n");
209  return AST_TEST_FAIL;
210  }
211  if (AST_LIST_REMOVE(&test_list, bogus, list)) {
212  ast_test_status_update(test, "AST_LIST_REMOVE should safely return NULL asked to remove a NULL pointer from an empty list\n");
213  return AST_TEST_FAIL;
214  }
215 
216  /* Insert item after specific item tests */
217 
218  AST_LIST_INSERT_HEAD(&test_list, &a, list);
219  MATCH_OR_FAIL(&test_list, "A", buf);
220  AST_LIST_INSERT_TAIL(&test_list, &c, list);
221  MATCH_OR_FAIL(&test_list, "AC", buf);
222  AST_LIST_INSERT_AFTER(&test_list, &a, &b, list);
223  MATCH_OR_FAIL(&test_list, "ABC", buf);
224  AST_LIST_INSERT_AFTER(&test_list, &c, &d, list);
225  MATCH_OR_FAIL(&test_list, "ABCD", buf);
226 
227  ELEM_OR_FAIL(AST_LIST_FIRST(&test_list), &a);
228  ELEM_OR_FAIL(AST_LIST_LAST(&test_list), &d);
230 
231  AST_LIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, list) {
233  }
235 
236  if (!AST_LIST_EMPTY(&test_list)) {
237  ast_test_status_update(test, "List should be empty after traversing and removal. It wasn't.\n");
238  return AST_TEST_FAIL;
239  }
240 
241  /* Append list test */
242 
243  AST_LIST_INSERT_HEAD(&test_list, &a, list);
244  MATCH_OR_FAIL(&test_list, "A", buf);
245  AST_LIST_INSERT_TAIL(&test_list, &b, list);
246  MATCH_OR_FAIL(&test_list, "AB", buf);
247  AST_LIST_INSERT_HEAD(&other_list, &c, list);
248  MATCH_OR_FAIL(&other_list, "C", buf);
249  AST_LIST_INSERT_TAIL(&other_list, &d, list);
250  MATCH_OR_FAIL(&other_list, "CD", buf);
251  AST_LIST_APPEND_LIST(&test_list, &other_list, list);
252  MATCH_OR_FAIL(&test_list, "ABCD", buf);
253  MATCH_OR_FAIL(&other_list, "", buf);
254  AST_LIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, list) {
256  }
258  if (!AST_LIST_EMPTY(&test_list)) {
259  ast_test_status_update(test, "List should be empty after traversing and removal. It wasn't.\n");
260  return AST_TEST_FAIL;
261  }
262 
263  /* Insert list after specific item in middle test */
264 
265  AST_LIST_INSERT_HEAD(&test_list, &a, list);
266  MATCH_OR_FAIL(&test_list, "A", buf);
267  AST_LIST_INSERT_TAIL(&test_list, &d, list);
268  MATCH_OR_FAIL(&test_list, "AD", buf);
269  AST_LIST_INSERT_HEAD(&other_list, &b, list);
270  MATCH_OR_FAIL(&other_list, "B", buf);
271  AST_LIST_INSERT_TAIL(&other_list, &c, list);
272  MATCH_OR_FAIL(&other_list, "BC", buf);
273  AST_LIST_INSERT_LIST_AFTER(&test_list, &other_list, &a, list);
274  MATCH_OR_FAIL(&test_list, "ABCD", buf);
275  MATCH_OR_FAIL(&other_list, "", buf);
276  AST_LIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, list) {
278  }
280  if (!AST_LIST_EMPTY(&test_list)) {
281  ast_test_status_update(test, "List should be empty after traversing and removal. It wasn't.\n");
282  return AST_TEST_FAIL;
283  }
284 
285  /* Insert list after specific item on end test */
286 
287  AST_LIST_INSERT_HEAD(&test_list, &a, list);
288  MATCH_OR_FAIL(&test_list, "A", buf);
289  AST_LIST_INSERT_TAIL(&test_list, &b, list);
290  MATCH_OR_FAIL(&test_list, "AB", buf);
291  AST_LIST_INSERT_HEAD(&other_list, &c, list);
292  MATCH_OR_FAIL(&other_list, "C", buf);
293  AST_LIST_INSERT_TAIL(&other_list, &d, list);
294  MATCH_OR_FAIL(&other_list, "CD", buf);
295  AST_LIST_INSERT_LIST_AFTER(&test_list, &other_list, &b, list);
296  MATCH_OR_FAIL(&test_list, "ABCD", buf);
297  MATCH_OR_FAIL(&other_list, "", buf);
298  AST_LIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, list) {
300  }
302  if (!AST_LIST_EMPTY(&test_list)) {
303  ast_test_status_update(test, "List should be empty after traversing and removal. It wasn't.\n");
304  return AST_TEST_FAIL;
305  }
306 
307  /* Safe traversal list modification tests */
308 
309  AST_LIST_INSERT_HEAD(&test_list, &a, list);
310  MATCH_OR_FAIL(&test_list, "A", buf);
311  AST_LIST_INSERT_TAIL(&test_list, &d, list);
312  MATCH_OR_FAIL(&test_list, "AD", buf);
313  AST_LIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, list) {
314  if (bogus == &d) {
316  MATCH_OR_FAIL(&test_list, "ABD", buf);
318  MATCH_OR_FAIL(&test_list, "ABCD", buf);
320  MATCH_OR_FAIL(&test_list, "ABC", buf);
321  }
322  }
324  MATCH_OR_FAIL(&test_list, "ABC", buf);
325  AST_LIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, list) {
327  }
329  if (!AST_LIST_EMPTY(&test_list)) {
330  ast_test_status_update(test, "List should be empty after traversing and removal. It wasn't.\n");
331  return AST_TEST_FAIL;
332  }
333 
334  return AST_TEST_PASS;
335 }
336 
337 AST_TEST_DEFINE(double_ll_tests)
338 {
339  RAII_VAR(struct ast_str *, buf, NULL, ast_free);
340  struct test_dbl_llist test_list = { 0, };
341  struct test_dbl_llist other_list = { 0, };
342  struct test_val *bogus;
343 
344  switch (cmd) {
345  case TEST_INIT:
346  info->name = "double_ll_tests";
347  info->category = "/main/linkedlists/";
348  info->summary = "double linked list unit test";
349  info->description =
350  "Test the double linked list API";
351  return AST_TEST_NOT_RUN;
352  case TEST_EXECUTE:
353  break;
354  }
355 
356  if (!(buf = ast_str_create(16))) {
357  return AST_TEST_FAIL;
358  }
359 
360  bogus = ast_alloca(sizeof(*bogus));
361 
362  if (AST_DLLIST_REMOVE_VERIFY(&test_list, bogus, dbl_list)) {
363  ast_test_status_update(test, "AST_DLLIST_REMOVE_VERIFY should safely return NULL for missing element from empty list\n");
364  return AST_TEST_FAIL;
365  }
366 
367  /* INSERT_HEAD and REMOVE_HEAD tests */
368  AST_DLLIST_INSERT_HEAD(&test_list, &a, dbl_list);
369  MATCH_OR_FAIL_DBL(&test_list, "A", buf);
370  AST_DLLIST_INSERT_HEAD(&test_list, &b, dbl_list);
371  MATCH_OR_FAIL_DBL(&test_list, "BA", buf);
372  AST_DLLIST_REMOVE_HEAD(&test_list, dbl_list);
373  MATCH_OR_FAIL_DBL(&test_list, "A", buf);
374  AST_DLLIST_REMOVE_HEAD(&test_list, dbl_list);
375  MATCH_OR_FAIL_DBL(&test_list, "", buf);
376  if (AST_DLLIST_REMOVE_HEAD(&test_list, dbl_list)) {
377  ast_test_status_update(test, "Somehow removed an item from the head of a list that didn't exist\n");
378  return AST_TEST_FAIL;
379  }
380  MATCH_OR_FAIL_DBL(&test_list, "", buf);
381 
382  /* Check empty list test */
383 
384  if (!AST_DLLIST_EMPTY(&test_list)) {
385  ast_test_status_update(test, "List should be empty\n");
386  return AST_TEST_FAIL;
387  }
388 
389  /* Insert tail and remove specific item tests. */
390 
391  AST_DLLIST_INSERT_TAIL(&test_list, &a, dbl_list);
392  MATCH_OR_FAIL_DBL(&test_list, "A", buf);
393  AST_DLLIST_INSERT_TAIL(&test_list, &b, dbl_list);
394  MATCH_OR_FAIL_DBL(&test_list, "AB", buf);
395  AST_DLLIST_INSERT_TAIL(&test_list, &c, dbl_list);
396  MATCH_OR_FAIL_DBL(&test_list, "ABC", buf);
397  AST_DLLIST_INSERT_TAIL(&test_list, &d, dbl_list);
398  MATCH_OR_FAIL_DBL(&test_list, "ABCD", buf);
399  if (AST_DLLIST_REMOVE_VERIFY(&test_list, bogus, dbl_list)) {
400  ast_test_status_update(test, "AST_DLLIST_REMOVE_VERIFY should safely return NULL for missing element\n");
401  return AST_TEST_FAIL;
402  }
403  bogus = NULL;
404  if (AST_DLLIST_REMOVE_VERIFY(&test_list, bogus, dbl_list)) {
405  ast_test_status_update(test, "AST_DLLIST_REMOVE_VERIFY should safely return NULL for element set to NULL\n");
406  return AST_TEST_FAIL;
407  }
408  AST_DLLIST_REMOVE(&test_list, &b, dbl_list);
409  MATCH_OR_FAIL_DBL(&test_list, "ACD", buf);
410  AST_DLLIST_REMOVE(&test_list, &d, dbl_list);
411  MATCH_OR_FAIL_DBL(&test_list, "AC", buf);
412  AST_DLLIST_REMOVE(&test_list, &a, dbl_list);
413  MATCH_OR_FAIL_DBL(&test_list, "C", buf);
414  AST_DLLIST_REMOVE(&test_list, &c, dbl_list);
415  MATCH_OR_FAIL_DBL(&test_list, "", buf);
416  if (!AST_DLLIST_EMPTY(&test_list)) {
417  ast_test_status_update(test, "List should be empty\n");
418  return AST_TEST_FAIL;
419  }
420  if (AST_DLLIST_REMOVE_VERIFY(&test_list, bogus, dbl_list)) {
421  ast_test_status_update(test, "AST_DLLIST_REMOVE_VERIFY should safely return NULL asked to remove a NULL pointer from an empty list\n");
422  return AST_TEST_FAIL;
423  }
424 
425  /* Insert item after and before specific item tests */
426 
427  AST_DLLIST_INSERT_HEAD(&test_list, &a, dbl_list);
428  MATCH_OR_FAIL_DBL(&test_list, "A", buf);
429  AST_DLLIST_INSERT_TAIL(&test_list, &c, dbl_list);
430  MATCH_OR_FAIL_DBL(&test_list, "AC", buf);
431  AST_DLLIST_INSERT_AFTER(&test_list, &a, &b, dbl_list);
432  MATCH_OR_FAIL_DBL(&test_list, "ABC", buf);
433  AST_DLLIST_INSERT_AFTER(&test_list, &c, &d, dbl_list);
434  MATCH_OR_FAIL_DBL(&test_list, "ABCD", buf);
435  AST_DLLIST_REMOVE_TAIL(&test_list, dbl_list);
436  MATCH_OR_FAIL_DBL(&test_list, "ABC", buf);
437  AST_DLLIST_REMOVE_TAIL(&test_list, dbl_list);
438  MATCH_OR_FAIL_DBL(&test_list, "AB", buf);
439  AST_DLLIST_INSERT_TAIL(&test_list, &d, dbl_list);
440  MATCH_OR_FAIL_DBL(&test_list, "ABD", buf);
441  AST_DLLIST_INSERT_BEFORE(&test_list, &d, &c, dbl_list);
442  MATCH_OR_FAIL_DBL(&test_list, "ABCD", buf);
443  AST_DLLIST_REMOVE_HEAD(&test_list, dbl_list);
444  MATCH_OR_FAIL_DBL(&test_list, "BCD", buf);
445  AST_DLLIST_INSERT_BEFORE(&test_list, &b, &a, dbl_list);
446  MATCH_OR_FAIL_DBL(&test_list, "ABCD", buf);
447 
448  ELEM_OR_FAIL(AST_DLLIST_FIRST(&test_list), &a);
449  ELEM_OR_FAIL(AST_DLLIST_LAST(&test_list), &d);
452 
453  AST_DLLIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, dbl_list) {
455  }
457 
458  if (!AST_DLLIST_EMPTY(&test_list)) {
459  ast_test_status_update(test, "List should be empty after traversing and removal. It wasn't.\n");
460  return AST_TEST_FAIL;
461  }
462 
463  /* Append list test */
464 
465  AST_DLLIST_INSERT_HEAD(&test_list, &a, dbl_list);
466  MATCH_OR_FAIL_DBL(&test_list, "A", buf);
467  AST_DLLIST_INSERT_TAIL(&test_list, &b, dbl_list);
468  MATCH_OR_FAIL_DBL(&test_list, "AB", buf);
469  AST_DLLIST_INSERT_HEAD(&other_list, &c, dbl_list);
470  MATCH_OR_FAIL_DBL(&other_list, "C", buf);
471  AST_DLLIST_INSERT_TAIL(&other_list, &d, dbl_list);
472  MATCH_OR_FAIL_DBL(&other_list, "CD", buf);
473  AST_DLLIST_APPEND_DLLIST(&test_list, &other_list, dbl_list);
474  MATCH_OR_FAIL_DBL(&test_list, "ABCD", buf);
475  MATCH_OR_FAIL_DBL(&other_list, "", buf);
476  AST_DLLIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, dbl_list) {
478  }
480  if (!AST_DLLIST_EMPTY(&test_list)) {
481  ast_test_status_update(test, "List should be empty after traversing and removal. It wasn't.\n");
482  return AST_TEST_FAIL;
483  }
484 
485  /*
486  * Safe traversal list modification tests
487  * Traverse starting from first element
488  */
489 
490  AST_DLLIST_INSERT_HEAD(&test_list, &a, dbl_list);
491  MATCH_OR_FAIL_DBL(&test_list, "A", buf);
492  AST_DLLIST_INSERT_TAIL(&test_list, &d, dbl_list);
493  MATCH_OR_FAIL_DBL(&test_list, "AD", buf);
494  AST_DLLIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, dbl_list) {
495  if (bogus == &d) {
497  MATCH_OR_FAIL_DBL(&test_list, "ABD", buf);
499  MATCH_OR_FAIL_DBL(&test_list, "ABCD", buf);
501  MATCH_OR_FAIL_DBL(&test_list, "ABC", buf);
502  }
503  }
505  MATCH_OR_FAIL_DBL(&test_list, "ABC", buf);
506  AST_DLLIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, dbl_list) {
508  }
510  if (!AST_DLLIST_EMPTY(&test_list)) {
511  ast_test_status_update(test, "List should be empty after traversing and removal. It wasn't.\n");
512  return AST_TEST_FAIL;
513  }
514 
515  AST_DLLIST_INSERT_HEAD(&test_list, &b, dbl_list);
516  MATCH_OR_FAIL_DBL(&test_list, "B", buf);
517  AST_DLLIST_INSERT_TAIL(&test_list, &d, dbl_list);
518  MATCH_OR_FAIL_DBL(&test_list, "BD", buf);
519  AST_DLLIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, dbl_list) {
520  if (bogus == &b) {
522  MATCH_OR_FAIL_DBL(&test_list, "ABD", buf);
524  MATCH_OR_FAIL_DBL(&test_list, "ABCD", buf);
526  MATCH_OR_FAIL_DBL(&test_list, "ACD", buf);
527  }
528  }
530  MATCH_OR_FAIL_DBL(&test_list, "ACD", buf);
531  AST_DLLIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, dbl_list) {
533  }
535  if (!AST_DLLIST_EMPTY(&test_list)) {
536  ast_test_status_update(test, "List should be empty after traversing and removal. It wasn't.\n");
537  return AST_TEST_FAIL;
538  }
539 
540  AST_DLLIST_INSERT_HEAD(&test_list, &b, dbl_list);
541  MATCH_OR_FAIL_DBL(&test_list, "B", buf);
542  AST_DLLIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, dbl_list) {
543  if (bogus == &b) {
545  MATCH_OR_FAIL_DBL(&test_list, "AB", buf);
547  MATCH_OR_FAIL_DBL(&test_list, "ABD", buf);
549  MATCH_OR_FAIL_DBL(&test_list, "ABCD", buf);
551  MATCH_OR_FAIL_DBL(&test_list, "ACD", buf);
552  }
553  }
555  MATCH_OR_FAIL_DBL(&test_list, "ACD", buf);
556  AST_DLLIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, dbl_list) {
558  }
560  if (!AST_DLLIST_EMPTY(&test_list)) {
561  ast_test_status_update(test, "List should be empty after traversing and removal. It wasn't.\n");
562  return AST_TEST_FAIL;
563  }
564 
565  /*
566  * Safe traversal list modification tests
567  * Traverse starting from last element
568  */
569 
570  AST_DLLIST_INSERT_HEAD(&test_list, &a, dbl_list);
571  MATCH_OR_FAIL_DBL(&test_list, "A", buf);
572  AST_DLLIST_INSERT_TAIL(&test_list, &d, dbl_list);
573  MATCH_OR_FAIL_DBL(&test_list, "AD", buf);
575  if (bogus == &d) {
577  MATCH_OR_FAIL_DBL(&test_list, "ABD", buf);
579  MATCH_OR_FAIL_DBL(&test_list, "ABCD", buf);
581  MATCH_OR_FAIL_DBL(&test_list, "ABC", buf);
582  }
583  }
585  MATCH_OR_FAIL_DBL(&test_list, "ABC", buf);
588  }
590  if (!AST_DLLIST_EMPTY(&test_list)) {
591  ast_test_status_update(test, "List should be empty after traversing and removal. It wasn't.\n");
592  return AST_TEST_FAIL;
593  }
594 
595  AST_DLLIST_INSERT_HEAD(&test_list, &b, dbl_list);
596  MATCH_OR_FAIL_DBL(&test_list, "B", buf);
597  AST_DLLIST_INSERT_TAIL(&test_list, &d, dbl_list);
598  MATCH_OR_FAIL_DBL(&test_list, "BD", buf);
600  if (bogus == &b) {
602  MATCH_OR_FAIL_DBL(&test_list, "ABD", buf);
604  MATCH_OR_FAIL_DBL(&test_list, "ABCD", buf);
606  MATCH_OR_FAIL_DBL(&test_list, "ACD", buf);
607  }
608  }
610  MATCH_OR_FAIL_DBL(&test_list, "ACD", buf);
611  AST_DLLIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, dbl_list) {
613  }
615  if (!AST_DLLIST_EMPTY(&test_list)) {
616  ast_test_status_update(test, "List should be empty after traversing and removal. It wasn't.\n");
617  return AST_TEST_FAIL;
618  }
619 
620  AST_DLLIST_INSERT_HEAD(&test_list, &b, dbl_list);
621  MATCH_OR_FAIL_DBL(&test_list, "B", buf);
623  if (bogus == &b) {
625  MATCH_OR_FAIL_DBL(&test_list, "AB", buf);
627  MATCH_OR_FAIL_DBL(&test_list, "ABD", buf);
629  MATCH_OR_FAIL_DBL(&test_list, "ABCD", buf);
631  MATCH_OR_FAIL_DBL(&test_list, "ACD", buf);
632  }
633  }
635  MATCH_OR_FAIL_DBL(&test_list, "ACD", buf);
636  AST_DLLIST_TRAVERSE_SAFE_BEGIN(&test_list, bogus, dbl_list) {
638  }
640  if (!AST_DLLIST_EMPTY(&test_list)) {
641  ast_test_status_update(test, "List should be empty after traversing and removal. It wasn't.\n");
642  return AST_TEST_FAIL;
643  }
644 
645  return AST_TEST_PASS;
646 }
647 
648 static int unload_module(void)
649 {
650  AST_TEST_UNREGISTER(single_ll_tests);
651  AST_TEST_UNREGISTER(double_ll_tests);
652  return 0;
653 }
654 
655 static int load_module(void)
656 {
657  AST_TEST_REGISTER(single_ll_tests);
658  AST_TEST_REGISTER(double_ll_tests);
660 }
661 
const char * str
Definition: app_jack.c:147
Asterisk main include file. File version handling, generic pbx functions.
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
#define ast_free(a)
Definition: astmm.h:180
A set of macros to manage doubly-linked lists.
#define AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: dlinkedlists.h:888
#define AST_DLLIST_INSERT_AFTER_CURRENT(elm, field)
Inserts a list node after the current node during a traversal.
Definition: dlinkedlists.h:723
#define AST_DLLIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: dlinkedlists.h:469
#define AST_DLLIST_ENTRY(type)
Declare previous/forward links inside a list entry.
Definition: dlinkedlists.h:413
#define AST_DLLIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: dlinkedlists.h:446
#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:618
#define AST_DLLIST_INSERT_AFTER(head, listelm, elm, field)
Inserts a list entry after a given entry.
#define AST_DLLIST_REMOVE_TAIL(head, field)
Removes and returns the tail node from a list.
#define AST_DLLIST_APPEND_DLLIST(head, list, field)
Appends a whole list to the tail of a list.
#define AST_DLLIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
#define AST_DLLIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
#define AST_DLLIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: dlinkedlists.h:849
#define AST_DLLIST_PREV(elm, field)
Returns the previous entry in the list before the given entry.
Definition: dlinkedlists.h:457
#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:212
#define AST_DLLIST_INSERT_BEFORE_CURRENT(elm, field)
Inserts a list node before the current node during a traversal.
Definition: dlinkedlists.h:696
#define AST_DLLIST_INSERT_BEFORE(head, listelm, elm, field)
Inserts a list entry before a given entry.
#define AST_DLLIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
#define AST_DLLIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: dlinkedlists.h:576
#define AST_DLLIST_REMOVE_VERIFY(head, elm, field)
Removes a specific node from a list if it is in the list.
#define AST_DLLIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: dlinkedlists.h:753
#define AST_DLLIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
#define AST_DLLIST_FIRST(head)
Returns the first entry contained in a list.
Definition: dlinkedlists.h:422
#define AST_DLLIST_LAST(head)
Returns the last entry contained in a list.
Definition: dlinkedlists.h:431
#define AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END
Closes a safe loop traversal block.
Definition: dlinkedlists.h:921
#define AST_DLLIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: dlinkedlists.h:913
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
A set of macros to manage forward-linked lists.
#define AST_LIST_LAST(head)
Returns the last entry contained in a list.
Definition: linkedlists.h:429
#define AST_LIST_INSERT_LIST_AFTER(head, list, elm, field)
Inserts a whole list after a specific entry in a list.
Definition: linkedlists.h:812
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:450
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:410
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_INSERT_BEFORE_CURRENT(elm, field)
Inserts a list entry before the current entry during a traversal.
Definition: linkedlists.h:599
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
Definition: linkedlists.h:856
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
#define AST_LIST_INSERT_AFTER(head, listelm, elm, field)
Inserts a list entry after a given entry.
Definition: linkedlists.h:695
#define AST_LIST_APPEND_LIST(head, list, field)
Appends a whole list to the tail of a list.
Definition: linkedlists.h:783
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:421
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:439
Support for logging to various files, console and syslog Configuration in file logger....
Asterisk module definitions.
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:567
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
def info(msg)
AST_LIST_HEAD_NOLOCK(contactliststruct, contact)
#define NULL
Definition: resample.c:96
String manipulation functions.
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:1115
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:737
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:672
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:638
Support for dynamic strings.
Definition: strings.h:602
struct test_val::@530 list
const char * name
struct test_val::@531 dbl_list
Test Framework API.
@ TEST_INIT
Definition: test.h:200
@ TEST_EXECUTE
Definition: test.h:201
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128
@ AST_TEST_PASS
Definition: test.h:195
@ AST_TEST_FAIL
Definition: test.h:196
@ AST_TEST_NOT_RUN
Definition: test.h:194
static struct test_val b
static struct test_val a
static struct test_val d
AST_TEST_DEFINE(single_ll_tests)
#define MATCH_OR_FAIL(list, val, retbuf)
#define MATCH_OR_FAIL_DBL(list, val, retbuf)
static int dbl_list_expect_forward(struct test_dbl_llist *test_list, const char *expect, struct ast_str **buf)
static int load_module(void)
static struct test_val c
static int unload_module(void)
#define ELEM_OR_FAIL(x, y)
static int list_expect(struct test_llist *test_list, const char *expect, struct ast_str **buf)
static int dbl_list_expect_reverse(struct test_dbl_llist *test_list, const char *expect, struct ast_str **buf)
#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:936