The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
dcursor_tests.c
Go to the documentation of this file.
1 #include <freeradius-devel/util/acutest.h>
2 
3 #include "dcursor.c"
4 
5 typedef struct {
6  char const *name;
9 
10 typedef struct {
13 
14 static void *test_iter(fr_dlist_head_t *list, void *current, UNUSED void *uctx)
15 {
16  return fr_dlist_next(list, current);
17 }
18 
19 /** @hidecallergraph */
20 static void test_list_init(test_item_list_t *list)
21 {
22  fr_dlist_talloc_init(&list->head, test_item_t, entry);
23 }
24 
25 /** Verify internal state is initialised correctly
26  *
27  */
28 static void test_init_null_item(void)
29 {
30  fr_dcursor_t cursor;
31  test_item_t *item_p;
32  test_item_list_t list;
33 
34  test_list_init(&list);
35 
36  item_p = fr_dcursor_iter_init(&cursor, &list.head, test_iter, NULL, &cursor);
37  TEST_CHECK(!item_p);
38  TEST_CHECK((cursor.dlist) == &list.head);
39  TEST_CHECK(!fr_dcursor_current(&cursor));
41  TEST_CHECK(cursor.iter_uctx == &cursor);
42 }
43 
44 static void test_init_1i_start(void)
45 {
46  fr_dcursor_t cursor;
47  test_item_t item1 = { "item1", { NULL, NULL} };
48  test_item_t *item_p;
49  test_item_list_t list;
50 
51  test_list_init(&list);
52  fr_dlist_insert_tail(&list.head, &item1);
53 
54  item_p = fr_dcursor_init(&cursor, &list.head);
55  TEST_CHECK(item_p == &item1);
56  TEST_CHECK((cursor.dlist) == &list.head);
57  TEST_CHECK(fr_dcursor_current(&cursor) == &item1);
58 }
59 
60 static void test_init_2i_start(void)
61 {
62  fr_dcursor_t cursor;
63  test_item_t item1 = { "item1", { NULL, NULL } };
64  test_item_t item2 = { "item2", { NULL, NULL } };
65  test_item_t *item_p;
66  test_item_list_t list;
67 
68  test_list_init(&list);
69  fr_dlist_insert_tail(&list.head, &item1);
70  fr_dlist_insert_tail(&list.head, &item2);
71 
72  item_p = fr_dcursor_init(&cursor, &list.head);
73  TEST_CHECK(item_p == &item1);
74  TEST_CHECK(fr_dcursor_current(&cursor) == &item1);
75 }
76 
77 static void test_next(void)
78 {
79  fr_dcursor_t cursor;
80  test_item_t item1 = { "item1", { NULL, NULL } };
81  test_item_t item2 = { "item2", { NULL, NULL } };
82  test_item_t *item_p;
83  test_item_list_t list;
84 
85  test_list_init(&list);
86  fr_dlist_insert_tail(&list.head, &item1);
87  fr_dlist_insert_tail(&list.head, &item2);
88 
89  fr_dcursor_init(&cursor, &list.head);
90  TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item2);
91 
92  item_p = fr_dcursor_next(&cursor);
93  TEST_CHECK(item_p == &item2);
94  TEST_CHECK(fr_dcursor_current(&cursor) == &item2);
96 }
97 
98 static void test_next_wrap(void)
99 {
100  fr_dcursor_t cursor;
101  test_item_t item1 = { "item1", { NULL, NULL } };
102  test_item_t item2 = { "item2", { NULL, NULL } };
103  test_item_t *item_p;
104  test_item_list_t list;
105 
106  test_list_init(&list);
107  fr_dlist_insert_tail(&list.head, &item1);
108  fr_dlist_insert_tail(&list.head, &item2);
109 
110  fr_dcursor_init(&cursor, &list.head);
111  fr_dcursor_next(&cursor);
112  item_p = fr_dcursor_next(&cursor);
113  TEST_CHECK(!item_p);
114  TEST_CHECK(!fr_dcursor_current(&cursor));
115  TEST_CHECK(!fr_dcursor_next_peek(&cursor));
116 
117  item_p = fr_dcursor_next(&cursor);
118  TEST_CHECK(!item_p);
119  TEST_CHECK(!fr_dcursor_current(&cursor));
120  TEST_CHECK(!fr_dcursor_next_peek(&cursor));
121 }
122 
124 {
125  fr_dcursor_t cursor;
126  test_item_list_t list;
127 
128  test_list_init(&list);
129 
130  fr_dcursor_init(&cursor, &list.head);
131  TEST_CHECK(!fr_dcursor_current(&cursor));
132  TEST_CHECK(!fr_dcursor_head(&cursor));
133  TEST_CHECK(!fr_dcursor_tail(&cursor));
134 }
135 
136 static void test_dcursor_head(void)
137 {
138  fr_dcursor_t cursor;
139  test_item_t item1 = { "item1", { NULL, NULL } };
140  test_item_t item2 = { "item2", { NULL, NULL } };
141  test_item_t item3 = { "item3", { NULL, NULL } };
142  test_item_t *item_p;
143  test_item_list_t list;
144 
145  test_list_init(&list);
146  fr_dlist_insert_tail(&list.head, &item1);
147  fr_dlist_insert_tail(&list.head, &item2);
148  fr_dlist_insert_tail(&list.head, &item3);
149 
150  fr_dcursor_init(&cursor, &list.head);
151  item_p = fr_dcursor_head(&cursor);
152  TEST_CHECK(item_p == &item1);
153 }
154 
155 static void test_dcursor_head_reset(void)
156 {
157  fr_dcursor_t cursor;
158  test_item_t item1 = { "item1", { NULL, NULL } };
159  test_item_t item2 = { "item2", { NULL, NULL } };
160  test_item_t *item_p;
161  test_item_list_t list;
162 
163  test_list_init(&list);
164  fr_dlist_insert_tail(&list.head, &item1);
165  fr_dlist_insert_tail(&list.head, &item2);
166 
167  fr_dcursor_init(&cursor, &list.head);
168 
169  item_p = fr_dcursor_head(&cursor);
170  TEST_CHECK(item_p == &item1);
171 
172  item_p = fr_dcursor_next(&cursor);
173  TEST_CHECK(item_p == &item2);
174 
175  item_p = fr_dcursor_next(&cursor);
176  TEST_CHECK(item_p == NULL);
177 
178  item_p = fr_dcursor_head(&cursor);
179  TEST_CHECK(item_p == &item1);
180 }
181 
183 {
184  fr_dcursor_t cursor;
185  test_item_t item1 = { "item1", { NULL, NULL } };
186  test_item_t item2 = { "item2", { NULL, NULL } };
187  test_item_t *item_p;
188  test_item_list_t list;
189 
190  test_list_init(&list);
191  fr_dlist_insert_tail(&list.head, &item1);
192  fr_dlist_insert_tail(&list.head, &item2);
193 
194  item_p = fr_dcursor_iter_init(&cursor, &list.head, test_iter, NULL, &cursor);
195  TEST_CHECK(item_p == &item1);
196 
197  item_p = fr_dcursor_next(&cursor);
198  TEST_CHECK(item_p == &item2);
199 
200  item_p = fr_dcursor_next(&cursor);
201  TEST_CHECK(item_p == NULL);
202 
203  item_p = fr_dcursor_head(&cursor);
204  TEST_CHECK(item_p == &item1);
205 }
206 
208 {
209  fr_dcursor_t cursor;
210  test_item_t item1 = { "item1", { NULL, NULL } };
211  test_item_t item2 = { "item2", { NULL, NULL } };
212  test_item_t item3 = { "item3", { NULL, NULL } };
213  test_item_t *item_p;
214  test_item_list_t list;
215 
216  test_list_init(&list);
217  fr_dlist_insert_tail(&list.head, &item1);
218  fr_dlist_insert_tail(&list.head, &item2);
219  fr_dlist_insert_tail(&list.head, &item3);
220 
221  fr_dcursor_init(&cursor, &list.head);
222  fr_dcursor_next(&cursor);
223  item_p = fr_dcursor_head(&cursor);
224  TEST_CHECK(item_p == &item1);
225 }
226 
227 static void test_dcursor_tail(void)
228 {
229  fr_dcursor_t cursor;
230  test_item_t item1 = { "item1", { NULL, NULL } };
231  test_item_t item2 = { "item2", { NULL, NULL } };
232  test_item_t item3 = { "item3", { NULL, NULL } };
233  test_item_t *item_p;
234  test_item_list_t list;
235 
236  test_list_init(&list);
237  fr_dlist_insert_tail(&list.head, &item1);
238  fr_dlist_insert_tail(&list.head, &item2);
239  fr_dlist_insert_tail(&list.head, &item3);
240 
241  fr_dcursor_init(&cursor, &list.head);
242  fr_dcursor_next(&cursor);
243  item_p = fr_dcursor_tail(&cursor);
244  TEST_CHECK(item_p == &item3);
245 }
246 
248 {
249  fr_dcursor_t cursor;
250  test_item_t item1 = { "item1", { NULL, NULL } };
251  test_item_t item2 = { "item2", { NULL, NULL } };
252  test_item_t item3 = { "item3", { NULL, NULL } };
253  test_item_t *item_p;
254  test_item_list_t list;
255 
256  test_list_init(&list);
257  fr_dlist_insert_tail(&list.head, &item1);
258  fr_dlist_insert_tail(&list.head, &item2);
259  fr_dlist_insert_tail(&list.head, &item3);
260 
261  fr_dcursor_init(&cursor, &list.head);
262  fr_dcursor_tail(&cursor);
263  item_p = fr_dcursor_head(&cursor);
264  TEST_CHECK(item_p == &item1);
265 }
266 
268 {
269  fr_dcursor_t cursor;
270  test_item_t item1 = { "item1", { NULL, NULL } };
271  test_item_t item2 = { "item2", { NULL, NULL } };
272  test_item_t item3 = { "item3", { NULL, NULL } };
273  test_item_t *item_p;
274  test_item_list_t list;
275 
276  test_list_init(&list);
277  fr_dlist_insert_tail(&list.head, &item1);
278  fr_dlist_insert_tail(&list.head, &item2);
279  fr_dlist_insert_tail(&list.head, &item3);
280 
281  fr_dcursor_init(&cursor, &list.head);
282  fr_dcursor_tail(&cursor);
283  item_p = fr_dcursor_next(&cursor);
284  TEST_CHECK(!item_p);
285 
286  item_p = fr_dcursor_next(&cursor);
287  TEST_CHECK(!item_p);
288 }
289 
291 {
292  fr_dcursor_t cursor;
293  test_item_t item1 = { "item1", { NULL, NULL } };
294  test_item_t item2 = { "item2", { NULL, NULL } };
295  test_item_t item3 = { "item3", { NULL, NULL } };
296  test_item_t *item_p;
297  test_item_list_t list;
298 
299  test_list_init(&list);
300  fr_dlist_insert_tail(&list.head, &item1);
301  fr_dlist_insert_tail(&list.head, &item2);
302  fr_dlist_insert_tail(&list.head, &item3);
303 
304  fr_dcursor_init(&cursor, &list.head);
305  fr_dcursor_head(&cursor);
306  TEST_CHECK(fr_dcursor_current(&cursor) == &item1);
307 
308  item_p = fr_dcursor_set_current(&cursor, &item2);
309  TEST_CHECK(item_p == &item2);
310  TEST_CHECK(fr_dcursor_current(&cursor) == &item2);
311  TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item3);
312 }
313 
315 {
316  fr_dcursor_t cursor;
317  test_item_t item1 = { "item1", { NULL, NULL } };
318  test_item_t item2 = { "item2", { NULL, NULL } };
319  test_item_t item3 = { "item3", { NULL, NULL } };
320  test_item_t *item_p;
321  test_item_list_t list;
322 
323  test_list_init(&list);
324  fr_dlist_insert_tail(&list.head, &item1);
325  fr_dlist_insert_tail(&list.head, &item2);
326 
327  fr_dcursor_init(&cursor, &list.head);
328  fr_dcursor_head(&cursor);
329  TEST_CHECK(fr_dcursor_current(&cursor) == &item1);
330 
331  item_p = fr_dcursor_set_current(&cursor, &item3);
332  TEST_CHECK(item_p == NULL);
333  TEST_CHECK(fr_dcursor_current(&cursor) == &item1);
334  TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item2);
335 }
336 
337 static void test_dcursor_append_empty(void)
338 {
339  fr_dcursor_t cursor;
340  test_item_t *item_p;
341  test_item_t item1 = { "item1", { NULL, NULL } };
342  test_item_list_t list;
343 
344  test_list_init(&list);
345 
346  fr_dcursor_init(&cursor, &list.head);
347  fr_dcursor_append(&cursor, &item1);
348 
349  item_p = fr_dcursor_current(&cursor);
350  TEST_CHECK(!item_p);
351  TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item1);
352 }
353 
355 {
356  fr_dcursor_t cursor;
357  test_item_t *item_p;
358  test_item_t item1 = { "item1", { NULL, NULL } };
359  test_item_t item2 = { "item2", { NULL, NULL } };
360  test_item_t item3 = { "item3", { NULL, NULL } };
361  test_item_list_t list;
362 
363  test_list_init(&list);
364 
365  fr_dcursor_init(&cursor, &list.head);
366  fr_dcursor_append(&cursor, &item1);
367  fr_dcursor_append(&cursor, &item2);
368  fr_dcursor_append(&cursor, &item3);
369 
370  item_p = fr_dcursor_current(&cursor);
371  TEST_CHECK(!item_p);
372  TEST_CHECK(fr_dcursor_next(&cursor) == &item1);
373  TEST_CHECK(fr_dcursor_next(&cursor) == &item2);
374  TEST_CHECK(fr_dcursor_tail(&cursor) == &item3);
375 }
376 
377 static void test_dcursor_prepend_empty(void)
378 {
379  fr_dcursor_t cursor;
380  test_item_t *item_p;
381  test_item_t item1 = { "item1", { NULL, NULL } };
382  test_item_list_t list;
383 
384  test_list_init(&list);
385 
386  fr_dcursor_init(&cursor, &list.head);
387  fr_dcursor_prepend(&cursor, &item1);
388 
389  item_p = fr_dcursor_current(&cursor);
390  TEST_CHECK(!item_p);
391  TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item1);
392 }
393 
395 {
396  fr_dcursor_t cursor;
397  test_item_t *item_p;
398  test_item_t item1 = { "item1", { NULL, NULL } };
399  test_item_list_t list;
400 
401  test_list_init(&list);
402 
403  fr_dcursor_init(&cursor, &list.head);
404  fr_dcursor_insert(&cursor, &item1);
405 
406  item_p = fr_dcursor_current(&cursor);
407  TEST_CHECK(!item_p);
408  TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item1);
409 }
410 
412 {
413  fr_dcursor_t cursor;
414  test_item_t *item_p;
415  test_item_t item1 = { "item1", { NULL, NULL } };
416  test_item_t item2 = { "item2", { NULL, NULL } };
417  test_item_t item3 = { "item3", { NULL, NULL } };
418  test_item_list_t list;
419 
420  test_list_init(&list);
421 
422  fr_dcursor_init(&cursor, &list.head);
423  fr_dcursor_insert(&cursor, &item1);
424  fr_dcursor_insert(&cursor, &item2);
425  fr_dcursor_insert(&cursor, &item3);
426 
427  item_p = fr_dcursor_current(&cursor);
428  TEST_CHECK(!item_p);
429  TEST_CHECK(fr_dcursor_next(&cursor) == &item1);
430  TEST_CHECK(fr_dcursor_next(&cursor) == &item2);
431  TEST_CHECK(fr_dcursor_tail(&cursor) == &item3);
432 }
433 
435 {
436  fr_dcursor_t cursor;
437  test_item_t *item_p;
438  test_item_t item1 = { "item1", { NULL, NULL } };
439  test_item_list_t list;
440 
441  test_list_init(&list);
442 
443  fr_dcursor_init(&cursor, &list.head);
444  TEST_CHECK(!fr_dcursor_replace(&cursor, &item1));
445 
446  item_p = fr_dcursor_current(&cursor);
447  TEST_CHECK(!item_p);
448  TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item1);
449 }
450 
452 {
453  fr_dcursor_t cursor;
454  test_item_t item1 = { "item1", { NULL, NULL } };
455  test_item_t item2 = { "item2", { NULL, NULL } };
456  test_item_t *item_p;
457  test_item_list_t list;
458 
459  test_list_init(&list);
460  fr_dlist_insert_tail(&list.head, &item1);
461 
462  fr_dcursor_init(&cursor, &list.head);
463  fr_dcursor_prepend(&cursor, &item2);
464 
465  TEST_CHECK(fr_dcursor_current(&cursor) == &item1);
466  TEST_CHECK(!fr_dcursor_next_peek(&cursor));
467 
468  item_p = fr_dcursor_next(&cursor);
469  TEST_CHECK(!item_p);
470 
471  item_p = fr_dcursor_head(&cursor);
472  TEST_CHECK(item_p == &item2);
473 
474  item_p = fr_dcursor_tail(&cursor);
475  TEST_CHECK(item_p == &item1);
476 }
477 
479 {
480  fr_dcursor_t cursor;
481  test_item_t item1 = { "item1", { NULL, NULL } };
482  test_item_t item2 = { "item2", { NULL, NULL } };
483  test_item_t *item_p;
484  test_item_list_t list;
485 
486  test_list_init(&list);
487  fr_dlist_insert_tail(&list.head, &item1);
488 
489  fr_dcursor_init(&cursor, &list.head);
490  fr_dcursor_append(&cursor, &item2);
491 
492  TEST_CHECK(fr_dcursor_current(&cursor) == &item1);
493  TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item2);
494 
495  item_p = fr_dcursor_next(&cursor);
496  TEST_CHECK(item_p == &item2);
497 
498  item_p = fr_dcursor_head(&cursor);
499  TEST_CHECK(item_p == &item1);
500 
501  item_p = fr_dcursor_tail(&cursor);
502  TEST_CHECK(item_p == &item2);
503 }
504 
506 {
507  fr_dcursor_t cursor;
508  test_item_t item1 = { "item1", { NULL, NULL } };
509  test_item_t item2 = { "item2", { NULL, NULL } };
510  test_item_t *item_p;
511  test_item_list_t list;
512 
513  test_list_init(&list);
514  fr_dlist_insert_tail(&list.head, &item1);
515 
516  fr_dcursor_init(&cursor, &list.head);
517  fr_dcursor_insert(&cursor, &item2);
518 
519  TEST_CHECK(fr_dcursor_current(&cursor) == &item1);
520  TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item2);
521 
522  item_p = fr_dcursor_next(&cursor);
523  TEST_CHECK(item_p == &item2);
524 
525  item_p = fr_dcursor_head(&cursor);
526  TEST_CHECK(item_p == &item1);
527 
528  item_p = fr_dcursor_tail(&cursor);
529  TEST_CHECK(item_p == &item2);
530 }
531 
533 {
534  fr_dcursor_t cursor;
535  test_item_t item1 = { "item1", { NULL, NULL } };
536  test_item_t item2 = { "item2", { NULL, NULL } };
537  test_item_t *item_p;
538  test_item_list_t list;
539 
540  test_list_init(&list);
541  fr_dlist_insert_tail(&list.head, &item1);
542 
543  fr_dcursor_init(&cursor, &list.head);
544  item_p = fr_dcursor_replace(&cursor, &item2);
545  TEST_CHECK(item_p == &item1);
546 
547  item_p = fr_dcursor_current(&cursor);
548  TEST_CHECK(item_p == &item2);
549 
550  item_p = fr_dcursor_head(&cursor);
551  TEST_CHECK(item_p == &item2);
552 
553  item_p = fr_dcursor_tail(&cursor);
554  TEST_CHECK(item_p == &item2);
555 }
556 
558 {
559  fr_dcursor_t cursor;
560  test_item_t item1 = { "item1", { NULL, NULL } };
561  test_item_t item2 = { "item2", { NULL, NULL } };
562  test_item_t item3 = { "item3", { NULL, NULL } };
563  test_item_t *item_p;
564  test_item_list_t list;
565 
566  test_list_init(&list);
567  fr_dlist_insert_tail(&list.head, &item1);
568  fr_dlist_insert_tail(&list.head, &item2);
569 
570  fr_dcursor_init(&cursor, &list.head);
571  fr_dcursor_prepend(&cursor, &item3);
572 
573  TEST_CHECK(fr_dcursor_current(&cursor) == &item1);
574  TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item2);
575 
576  item_p = fr_dcursor_next(&cursor);
577  TEST_CHECK(item_p == &item2);
578 
579  item_p = fr_dcursor_next(&cursor);
580  TEST_CHECK(!item_p);
581 
582  item_p = fr_dcursor_head(&cursor);
583  TEST_CHECK(item_p == &item3);
584 
585  item_p = fr_dcursor_tail(&cursor);
586  TEST_CHECK(item_p == &item2);
587 }
588 
590 {
591  fr_dcursor_t cursor;
592  test_item_t item1 = { "item1", { NULL, NULL } };
593  test_item_t item2 = { "item2", { NULL, NULL } };
594  test_item_t item3 = { "item3", { NULL, NULL } };
595  test_item_t *item_p;
596  test_item_list_t list;
597 
598  test_list_init(&list);
599  fr_dlist_insert_tail(&list.head, &item1);
600  fr_dlist_insert_tail(&list.head, &item2);
601 
602  fr_dcursor_init(&cursor, &list.head);
603  fr_dcursor_append(&cursor, &item3);
604 
605  TEST_CHECK(fr_dcursor_current(&cursor) == &item1);
606  TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item2);
607 
608  item_p = fr_dcursor_next(&cursor);
609  TEST_CHECK(item_p == &item2);
610 
611  item_p = fr_dcursor_head(&cursor);
612  TEST_CHECK(item_p == &item1);
613 
614  item_p = fr_dcursor_tail(&cursor);
615  TEST_CHECK(item_p == &item3);
616 }
617 
619 {
620  fr_dcursor_t cursor;
621  test_item_t item1 = { "item1", { NULL, NULL } };
622  test_item_t item2 = { "item2", { NULL, NULL } };
623  test_item_t item3 = { "item3", { NULL, NULL } };
624  test_item_t *item_p;
625  test_item_list_t list;
626 
627  test_list_init(&list);
628  fr_dlist_insert_tail(&list.head, &item1);
629  fr_dlist_insert_tail(&list.head, &item2);
630 
631  fr_dcursor_init(&cursor, &list.head);
632  fr_dcursor_insert(&cursor, &item3);
633 
634  /*
635  * Order should be
636  *
637  * item1 - HEAD
638  * item3
639  * item2 - TAIL
640  */
641  TEST_CHECK(fr_dcursor_current(&cursor) == &item1);
642  TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item3);
643 
644  item_p = fr_dcursor_next(&cursor);
645  TEST_CHECK(item_p == &item3);
646 
647  item_p = fr_dcursor_next(&cursor);
648  TEST_CHECK(item_p == &item2);
649 
650  item_p = fr_dcursor_head(&cursor);
651  TEST_CHECK(item_p == &item1);
652 
653  item_p = fr_dcursor_tail(&cursor);
654  TEST_CHECK(item_p == &item2);
655 }
656 
658 {
659  fr_dcursor_t cursor;
660  test_item_t item1 = { "item1", { NULL, NULL } };
661  test_item_t item2 = { "item2", { NULL, NULL } };
662  test_item_t item3 = { "item3", { NULL, NULL } };
663  test_item_t *item_p;
664  test_item_list_t list;
665 
666  test_list_init(&list);
667  fr_dlist_insert_tail(&list.head, &item1);
668  fr_dlist_insert_tail(&list.head, &item2);
669 
670  /*
671  * Order should be
672  *
673  * item3 - HEAD
674  * item2 - TAIL
675  */
676  fr_dcursor_init(&cursor, &list.head);
677  item_p = fr_dcursor_replace(&cursor, &item3);
678  TEST_CHECK(item_p == &item1);
679 
680  item_p = fr_dcursor_current(&cursor);
681  TEST_CHECK(item_p == &item3);
682 
683  item_p = fr_dcursor_head(&cursor);
684  TEST_CHECK(item_p == &item3);
685 
686  item_p = fr_dcursor_tail(&cursor);
687  TEST_CHECK(item_p == &item2);
688 }
689 
691 {
692  fr_dcursor_t cursor;
693  test_item_t item1 = { "item1", { NULL, NULL } };
694  test_item_t item2 = { "item2", { NULL, NULL } };
695  test_item_t item3 = { "item3", { NULL, NULL } };
696  test_item_t item4 = { "item4", { NULL, NULL } };
697  test_item_t *item_p;
698  test_item_list_t list;
699 
700  test_list_init(&list);
701  fr_dlist_insert_tail(&list.head, &item1);
702  fr_dlist_insert_tail(&list.head, &item2);
703  fr_dlist_insert_tail(&list.head, &item3);
704 
705  fr_dcursor_init(&cursor, &list.head);
706  fr_dcursor_next(&cursor);
707  fr_dcursor_prepend(&cursor, &item4);
708 
709  TEST_CHECK(fr_dcursor_current(&cursor) == &item2);
710  TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item3);
711 
712  item_p = fr_dcursor_next(&cursor);
713  TEST_CHECK(item_p == &item3);
714 
715  item_p = fr_dcursor_next(&cursor);
716  TEST_CHECK(!item_p);
717 
718  item_p = fr_dcursor_head(&cursor);
719  TEST_CHECK(item_p == &item4);
720 
721  item_p = fr_dcursor_tail(&cursor);
722  TEST_CHECK(item_p == &item3);
723 }
724 
725 static void test_dcursor_append_3i_mid(void)
726 {
727  fr_dcursor_t cursor;
728  test_item_t item1 = { "item1", { NULL, NULL } };
729  test_item_t item2 = { "item2", { NULL, NULL } };
730  test_item_t item3 = { "item3", { NULL, NULL } };
731  test_item_t item4 = { "item4", { NULL, NULL } };
732  test_item_t *item_p;
733  test_item_list_t list;
734 
735  test_list_init(&list);
736  fr_dlist_insert_tail(&list.head, &item1);
737  fr_dlist_insert_tail(&list.head, &item2);
738  fr_dlist_insert_tail(&list.head, &item3);
739 
740  fr_dcursor_init(&cursor, &list.head);
741  fr_dcursor_next(&cursor);
742  fr_dcursor_append(&cursor, &item4);
743 
744  TEST_CHECK(fr_dcursor_current(&cursor) == &item2);
745  TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item3);
746 
747  item_p = fr_dcursor_next(&cursor);
748  TEST_CHECK(item_p == &item3);
749 
750  item_p = fr_dcursor_head(&cursor);
751  TEST_CHECK(item_p == &item1);
752 
753  item_p = fr_dcursor_tail(&cursor);
754  TEST_CHECK(item_p == &item4);
755 }
756 
757 static void test_dcursor_insert_3i_mid(void)
758 {
759  fr_dcursor_t cursor;
760  test_item_t item1 = { "item1", { NULL, NULL } };
761  test_item_t item2 = { "item2", { NULL, NULL } };
762  test_item_t item3 = { "item3", { NULL, NULL } };
763  test_item_t item4 = { "item4", { NULL, NULL } };
764  test_item_t *item_p;
765  test_item_list_t list;
766 
767  test_list_init(&list);
768  fr_dlist_insert_tail(&list.head, &item1);
769  fr_dlist_insert_tail(&list.head, &item2);
770  fr_dlist_insert_tail(&list.head, &item3);
771 
772  fr_dcursor_init(&cursor, &list.head);
773  fr_dcursor_next(&cursor);
774  fr_dcursor_insert(&cursor, &item4);
775 
776  TEST_CHECK(fr_dcursor_current(&cursor) == &item2);
777  TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item4);
778 
779  item_p = fr_dcursor_next(&cursor);
780  TEST_CHECK(item_p == &item4);
781 
782  item_p = fr_dcursor_next(&cursor);
783  TEST_CHECK(item_p == &item3);
784 
785  item_p = fr_dcursor_head(&cursor);
786  TEST_CHECK(item_p == &item1);
787 
788  item_p = fr_dcursor_tail(&cursor);
789  TEST_CHECK(item_p == &item3);
790 }
791 
793 {
794  fr_dcursor_t cursor;
795  test_item_t item1 = { "item1", { NULL, NULL } };
796  test_item_t item2 = { "item2", { NULL, NULL } };
797  test_item_t item3 = { "item3", { NULL, NULL } };
798  test_item_t item4 = { "item4", { NULL, NULL } };
799  test_item_t *item_p;
800  test_item_list_t list;
801 
802  test_list_init(&list);
803  fr_dlist_insert_tail(&list.head, &item1);
804  fr_dlist_insert_tail(&list.head, &item2);
805  fr_dlist_insert_tail(&list.head, &item3);
806 
807  fr_dcursor_init(&cursor, &list.head);
808  fr_dcursor_next(&cursor);
809  item_p = fr_dcursor_replace(&cursor, &item4);
810  TEST_CHECK(item_p == &item2);
811 
812  item_p = fr_dcursor_current(&cursor);
813  TEST_CHECK(item_p == &item4);
814 
815  TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item3);
816 
817  item_p = fr_dcursor_head(&cursor);
818  TEST_CHECK(item_p == &item1);
819 
820  item_p = fr_dcursor_tail(&cursor);
821  TEST_CHECK(item_p == &item3);
822 }
823 
825 {
826  fr_dcursor_t cursor;
827  test_item_t item1 = { "item1", { NULL, NULL } };
828  test_item_t item2 = { "item2", { NULL, NULL } };
829  test_item_t item3 = { "item3", { NULL, NULL } };
830  test_item_t item4 = { "item4", { NULL, NULL } };
831  test_item_t *item_p;
832  test_item_list_t list;
833 
834  test_list_init(&list);
835  fr_dlist_insert_tail(&list.head, &item1);
836  fr_dlist_insert_tail(&list.head, &item2);
837  fr_dlist_insert_tail(&list.head, &item3);
838 
839  fr_dcursor_init(&cursor, &list.head);
840  fr_dcursor_next(&cursor);
841  fr_dcursor_next(&cursor);
842  fr_dcursor_prepend(&cursor, &item4);
843 
844  TEST_CHECK(fr_dcursor_current(&cursor) == &item3);
845  TEST_CHECK(!fr_dcursor_next_peek(&cursor));
846 
847  item_p = fr_dcursor_next(&cursor);
848  TEST_CHECK(!item_p);
849 
850  item_p = fr_dcursor_head(&cursor);
851  TEST_CHECK(item_p == &item4);
852 
853  item_p = fr_dcursor_tail(&cursor);
854  TEST_CHECK(item_p == &item3);
855 }
856 
857 static void test_dcursor_append_3i_end(void)
858 {
859  fr_dcursor_t cursor;
860  test_item_t item1 = { "item1", { NULL, NULL } };
861  test_item_t item2 = { "item2", { NULL, NULL } };
862  test_item_t item3 = { "item3", { NULL, NULL } };
863  test_item_t item4 = { "item4", { NULL, NULL } };
864  test_item_t *item_p;
865  test_item_list_t list;
866 
867  test_list_init(&list);
868  fr_dlist_insert_tail(&list.head, &item1);
869  fr_dlist_insert_tail(&list.head, &item2);
870  fr_dlist_insert_tail(&list.head, &item3);
871 
872  fr_dcursor_init(&cursor, &list.head);
873  fr_dcursor_next(&cursor);
874  fr_dcursor_next(&cursor);
875  fr_dcursor_append(&cursor, &item4);
876 
877  TEST_CHECK(fr_dcursor_current(&cursor) == &item3);
878  TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item4);
879 
880  item_p = fr_dcursor_next(&cursor);
881  TEST_CHECK(item_p == &item4);
882 
883  item_p = fr_dcursor_head(&cursor);
884  TEST_CHECK(item_p == &item1);
885 
886  item_p = fr_dcursor_tail(&cursor);
887  TEST_CHECK(item_p == &item4);
888 }
889 
890 static void test_dcursor_insert_3i_end(void)
891 {
892  fr_dcursor_t cursor;
893  test_item_t item1 = { "item1", { NULL, NULL } };
894  test_item_t item2 = { "item2", { NULL, NULL } };
895  test_item_t item3 = { "item3", { NULL, NULL } };
896  test_item_t item4 = { "item4", { NULL, NULL } };
897  test_item_t *item_p;
898  test_item_list_t list;
899 
900  test_list_init(&list);
901  fr_dlist_insert_tail(&list.head, &item1);
902  fr_dlist_insert_tail(&list.head, &item2);
903  fr_dlist_insert_tail(&list.head, &item3);
904 
905  fr_dcursor_init(&cursor, &list.head);
906  fr_dcursor_next(&cursor);
907  fr_dcursor_next(&cursor);
908  fr_dcursor_insert(&cursor, &item4);
909 
910  TEST_CHECK(fr_dcursor_current(&cursor) == &item3);
911  TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item4);
912 
913  item_p = fr_dcursor_next(&cursor);
914  TEST_CHECK(item_p == &item4);
915 
916  item_p = fr_dcursor_next(&cursor);
917  TEST_CHECK(!item_p);
918 
919  item_p = fr_dcursor_head(&cursor);
920  TEST_CHECK(item_p == &item1);
921 
922  item_p = fr_dcursor_tail(&cursor);
923  TEST_CHECK(item_p == &item4);
924 }
925 
927 {
928  fr_dcursor_t cursor;
929  test_item_t item1 = { "item1", { NULL, NULL } };
930  test_item_t item2 = { "item2", { NULL, NULL } };
931  test_item_t item3 = { "item3", { NULL, NULL } };
932  test_item_t item4 = { "item4", { NULL, NULL } };
933  test_item_t *item_p;
934  test_item_list_t list;
935 
936  test_list_init(&list);
937  fr_dlist_insert_tail(&list.head, &item1);
938  fr_dlist_insert_tail(&list.head, &item2);
939  fr_dlist_insert_tail(&list.head, &item3);
940 
941  fr_dcursor_init(&cursor, &list.head);
942  fr_dcursor_next(&cursor);
943  fr_dcursor_next(&cursor);
944  item_p = fr_dcursor_replace(&cursor, &item4);
945  TEST_CHECK(item_p == &item3);
946 
947  item_p = fr_dcursor_current(&cursor);
948  TEST_CHECK(item_p == &item4);
949 
950  TEST_CHECK(!fr_dcursor_next_peek(&cursor));
951 
952  item_p = fr_dcursor_head(&cursor);
953  TEST_CHECK(item_p == &item1);
954 
955  item_p = fr_dcursor_tail(&cursor);
956  TEST_CHECK(item_p == &item4);
957 }
958 
959 static void test_dcursor_remove_empty(void)
960 {
961  fr_dcursor_t cursor;
962  test_item_list_t list;
963 
964  test_list_init(&list);
965 
966  _fr_dcursor_init(&cursor, (fr_dlist_head_t *)&list, test_iter, NULL, NULL, NULL, NULL, NULL, false);
967  TEST_CHECK(!fr_dcursor_remove(&cursor));
968 }
969 
970 static void test_dcursor_remove_1i(void)
971 {
972  fr_dcursor_t cursor;
973  test_item_t item1 = { "item1", { NULL, NULL } };
974  test_item_t *item_p;
975  test_item_list_t list;
976 
977  test_list_init(&list);
978  fr_dlist_insert_tail(&list.head, &item1);
979 
980  fr_dcursor_init(&cursor, &list.head);
981 
982  item_p = fr_dcursor_remove(&cursor);
983  TEST_CHECK(item_p == &item1);
984 
985  TEST_CHECK(!fr_dcursor_current(&cursor));
986  TEST_CHECK(!fr_dcursor_next(&cursor));
987  TEST_CHECK(!fr_dcursor_tail(&cursor));
988  TEST_CHECK(!fr_dcursor_head(&cursor));
989 }
990 
991 static void test_dcursor_remove_2i(void)
992 {
993  fr_dcursor_t cursor;
994  test_item_t item1 = { "item1", { NULL, NULL } };
995  test_item_t item2 = { "item2", { NULL, NULL } };
996  test_item_t *item_p;
997  test_item_list_t list;
998 
999  test_list_init(&list);
1000  fr_dlist_insert_tail(&list.head, &item1);
1001  fr_dlist_insert_tail(&list.head, &item2);
1002 
1003  fr_dcursor_init(&cursor, &list.head);
1004  item_p = fr_dcursor_remove(&cursor);
1005 
1006  TEST_CHECK(item_p == &item1);
1007  TEST_CHECK(fr_dcursor_current(&cursor) == &item2);
1008  TEST_CHECK(!fr_dcursor_next(&cursor));
1009  TEST_CHECK(fr_dcursor_tail(&cursor) == &item2);
1010  TEST_CHECK(fr_dcursor_head(&cursor) == &item2);
1011 
1012  item_p = fr_dcursor_remove(&cursor);
1013  TEST_CHECK(item_p == &item2);
1014 
1015  TEST_CHECK(!fr_dcursor_current(&cursor));
1016  TEST_CHECK(!fr_dcursor_next(&cursor));
1017  TEST_CHECK(!fr_dcursor_tail(&cursor));
1018  TEST_CHECK(!fr_dcursor_head(&cursor));
1019 }
1020 
1022 {
1023  fr_dcursor_t cursor;
1024  test_item_t item1 = { "item1", { NULL, NULL } };
1025  test_item_t item2 = { "item2", { NULL, NULL } };
1026  test_item_t item3 = { "item3", { NULL, NULL } };
1027  test_item_t *item_p;
1028  test_item_list_t list;
1029 
1030  test_list_init(&list);
1031  fr_dlist_insert_tail(&list.head, &item1);
1032  fr_dlist_insert_tail(&list.head, &item2);
1033  fr_dlist_insert_tail(&list.head, &item3);
1034 
1035  fr_dcursor_init(&cursor, &list.head);
1036  item_p = fr_dcursor_remove(&cursor);
1037  TEST_CHECK(item_p == &item1);
1038  TEST_CHECK(fr_dcursor_current(&cursor) == &item2);
1039  TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item3);
1040 
1041  item_p = fr_dcursor_remove(&cursor);
1042  TEST_CHECK(item_p == &item2);
1043  TEST_CHECK(fr_dcursor_current(&cursor) == &item3);
1044  TEST_CHECK(!fr_dcursor_next_peek(&cursor));
1045 
1046  item_p = fr_dcursor_remove(&cursor);
1047  TEST_CHECK(item_p == &item3);
1048 
1049  TEST_CHECK(!fr_dcursor_tail(&cursor));
1050  TEST_CHECK(!fr_dcursor_head(&cursor));
1051 }
1052 
1054 {
1055  fr_dcursor_t cursor;
1056  test_item_t item1 = { "item1", { NULL, NULL } };
1057  test_item_t item2 = { "item2", { NULL, NULL } };
1058  test_item_t item3 = { "item3", { NULL, NULL } };
1059  test_item_t *item_p;
1060  test_item_list_t list;
1061 
1062  test_list_init(&list);
1063  fr_dlist_insert_tail(&list.head, &item1);
1064  fr_dlist_insert_tail(&list.head, &item2);
1065  fr_dlist_insert_tail(&list.head, &item3);
1066 
1067  fr_dcursor_init(&cursor, &list.head);
1068  fr_dcursor_next(&cursor);
1069 
1070  item_p = fr_dcursor_remove(&cursor);
1071  TEST_CHECK(item_p == &item2);
1072  TEST_CHECK(fr_dcursor_current(&cursor) == &item3);
1073  TEST_CHECK(!fr_dcursor_next_peek(&cursor));
1074 
1075  item_p = fr_dcursor_remove(&cursor);
1076  TEST_CHECK(item_p == &item3);
1077 
1078  /*
1079  * We just removed the end of the list
1080  * so current is now NULL.
1081  *
1082  * We don't implicitly start moving backwards.
1083  */
1084  TEST_CHECK(!fr_dcursor_current(&cursor));
1085  TEST_CHECK(!fr_dcursor_next_peek(&cursor));
1086 
1087  item_p = fr_dcursor_remove(&cursor);
1088  TEST_CHECK(!item_p);
1089 
1090  TEST_CHECK(fr_dcursor_tail(&cursor) == &item1);
1091  TEST_CHECK(fr_dcursor_head(&cursor) == &item1);
1092 }
1093 
1095 {
1096  fr_dcursor_t cursor;
1097  test_item_t item1 = { "item1", { NULL, NULL } };
1098  test_item_t item2 = { "item2", { NULL, NULL } };
1099  test_item_t item3 = { "item3", { NULL, NULL } };
1100  test_item_t *item_p;
1101  test_item_list_t list;
1102 
1103  test_list_init(&list);
1104  fr_dlist_insert_tail(&list.head, &item1);
1105  fr_dlist_insert_tail(&list.head, &item2);
1106  fr_dlist_insert_tail(&list.head, &item3);
1107 
1108  fr_dcursor_init(&cursor, &list.head);
1109  fr_dcursor_tail(&cursor);
1110 
1111  item_p = fr_dcursor_remove(&cursor);
1112  TEST_CHECK(item_p == &item3);
1113  TEST_CHECK(!fr_dcursor_current(&cursor));
1114  TEST_CHECK(!fr_dcursor_next_peek(&cursor));
1115 
1116  item_p = fr_dcursor_remove(&cursor);
1117  TEST_CHECK(!item_p);
1118 
1119  TEST_CHECK(!fr_dcursor_current(&cursor));
1120  TEST_CHECK(!fr_dcursor_next_peek(&cursor));
1121 }
1122 
1124 {
1125  fr_dcursor_t cursor_a, cursor_b;
1126 
1127  test_item_t item1a = { "item1a", { NULL, NULL } };
1128  test_item_t item2a = { "item2a", { NULL, NULL } };
1129  test_item_t item3a = { "item3a", { NULL, NULL } };
1130 
1131  test_item_t item1b = { "item1b", { NULL, NULL } };
1132  test_item_t item2b = { "item2b", { NULL, NULL } };
1133  test_item_t item3b = { "item3b", { NULL, NULL } };
1134 
1135  test_item_list_t list_a;
1136  test_item_list_t list_b;
1137 
1138  test_list_init(&list_a);
1139  fr_dlist_insert_tail(&list_a.head, &item1a);
1140  fr_dlist_insert_tail(&list_a.head, &item2a);
1141  fr_dlist_insert_tail(&list_a.head, &item3a);
1142 
1143  test_list_init(&list_b);
1144  fr_dlist_insert_tail(&list_b.head, &item1b);
1145  fr_dlist_insert_tail(&list_b.head, &item2b);
1146  fr_dlist_insert_tail(&list_b.head, &item3b);
1147 
1148  fr_dcursor_init(&cursor_a, &list_a.head);
1149  fr_dcursor_init(&cursor_b, &list_b.head);
1150  fr_dcursor_merge(&cursor_a, &cursor_b);
1151 
1152  /*
1153  * First item in cursor_a remains unchanged
1154  *
1155  * The insertion point into cursor_a is
1156  * directly after the current item.
1157  */
1158  TEST_CHECK(fr_dcursor_current(&cursor_a) == &item1a);
1159  TEST_MSG("Expected %s", item1a.name);
1160  TEST_MSG("Got %s", ((test_item_t *)fr_dcursor_current(&cursor_a))->name);
1161 
1162  /*
1163  * Next three items should be from cursor_b
1164  */
1165  TEST_CHECK(fr_dcursor_next(&cursor_a) == &item1b);
1166  TEST_MSG("Expected %s", item1b.name);
1167  TEST_MSG("Got %s", ((test_item_t *)fr_dcursor_current(&cursor_a))->name);
1168  TEST_CHECK(fr_dcursor_next(&cursor_a) == &item2b);
1169  TEST_MSG("Expected %s", item2b.name);
1170  TEST_MSG("Got %s", ((test_item_t *)fr_dcursor_current(&cursor_a))->name);
1171  TEST_CHECK(fr_dcursor_next(&cursor_a) == &item3b);
1172  TEST_MSG("Expected %s", item3b.name);
1173  TEST_MSG("Got %s", ((test_item_t *)fr_dcursor_current(&cursor_a))->name);
1174 
1175  /*
1176  * With the final two from cursor_a
1177  */
1178  TEST_CHECK(fr_dcursor_next(&cursor_a) == &item2a);
1179  TEST_MSG("Expected %s", item2a.name);
1180  TEST_MSG("Got %s", ((test_item_t *)fr_dcursor_current(&cursor_a))->name);
1181  TEST_CHECK(fr_dcursor_next(&cursor_a) == &item3a);
1182  TEST_MSG("Expected %s", item3a.name);
1183  TEST_MSG("Got %s", ((test_item_t *)fr_dcursor_current(&cursor_a))->name);
1184  TEST_CHECK(!fr_dcursor_next(&cursor_a));
1185 
1186  TEST_CHECK(!fr_dcursor_current(&cursor_b));
1188 }
1189 
1190 static void test_dcursor_merge_mid_a(void)
1191 {
1192  fr_dcursor_t cursor_a, cursor_b;
1193 
1194  test_item_t item1a = { "item1a", { NULL, NULL } };
1195  test_item_t item2a = { "item2a", { NULL, NULL } };
1196  test_item_t item3a = { "item3a", { NULL, NULL } };
1197 
1198  test_item_t item1b = { "item1b", { NULL, NULL } };
1199  test_item_t item2b = { "item2b", { NULL, NULL } };
1200  test_item_t item3b = { "item3b", { NULL, NULL } };
1201 
1202  test_item_list_t list_a;
1203  test_item_list_t list_b;
1204 
1205  test_list_init(&list_a);
1206  fr_dlist_insert_tail(&list_a.head, &item1a);
1207  fr_dlist_insert_tail(&list_a.head, &item2a);
1208  fr_dlist_insert_tail(&list_a.head, &item3a);
1209 
1210  test_list_init(&list_b);
1211  fr_dlist_insert_tail(&list_b.head, &item1b);
1212  fr_dlist_insert_tail(&list_b.head, &item2b);
1213  fr_dlist_insert_tail(&list_b.head, &item3b);
1214 
1215  fr_dcursor_init(&cursor_a, &list_a.head);
1216  fr_dcursor_init(&cursor_b, &list_b.head);
1217  fr_dcursor_next(&cursor_a);
1218  fr_dcursor_merge(&cursor_a, &cursor_b);
1219 
1220  /*
1221  * Should be second item in cursor a
1222  */
1223  TEST_CHECK(fr_dcursor_current(&cursor_a) == &item2a);
1224  TEST_MSG("Expected %s", item2a.name);
1225  TEST_MSG("Got %s", ((test_item_t *)fr_dcursor_current(&cursor_a))->name);
1226 
1227  /*
1228  * Next three items should be from cursor_b
1229  */
1230  TEST_CHECK(fr_dcursor_next(&cursor_a) == &item1b);
1231  TEST_MSG("Expected %s", item1b.name);
1232  TEST_MSG("Got %s", ((test_item_t *)fr_dcursor_current(&cursor_a))->name);
1233  TEST_CHECK(fr_dcursor_next(&cursor_a) == &item2b);
1234  TEST_MSG("Expected %s", item2b.name);
1235  TEST_MSG("Got %s", ((test_item_t *)fr_dcursor_current(&cursor_a))->name);
1236  TEST_CHECK(fr_dcursor_next(&cursor_a) == &item3b);
1237  TEST_MSG("Expected %s", item3b.name);
1238  TEST_MSG("Got %s", ((test_item_t *)fr_dcursor_current(&cursor_a))->name);
1239 
1240  /*
1241  * Final item should be from cursor a
1242  */
1243  TEST_CHECK(fr_dcursor_next(&cursor_a) == &item3a);
1244  TEST_MSG("Expected %s", item3a.name);
1245  TEST_MSG("Got %s", ((test_item_t *)fr_dcursor_current(&cursor_a))->name);
1246  TEST_CHECK(!fr_dcursor_next(&cursor_a));
1247 
1248  TEST_CHECK(!fr_dcursor_current(&cursor_b));
1250 }
1251 
1252 static void test_dcursor_merge_end_a(void)
1253 {
1254  fr_dcursor_t cursor_a, cursor_b;
1255 
1256  test_item_t item1a = { "item1a", { NULL, NULL } };
1257  test_item_t item2a = { "item2a", { NULL, NULL } };
1258  test_item_t item3a = { "item3a", { NULL, NULL } };
1259 
1260  test_item_t item1b = { "item1b", { NULL, NULL } };
1261  test_item_t item2b = { "item2b", { NULL, NULL } };
1262  test_item_t item3b = { "item3b", { NULL, NULL } };
1263 
1264  test_item_list_t list_a;
1265  test_item_list_t list_b;
1266 
1267  test_list_init(&list_a);
1268  fr_dlist_insert_tail(&list_a.head, &item1a);
1269  fr_dlist_insert_tail(&list_a.head, &item2a);
1270  fr_dlist_insert_tail(&list_a.head, &item3a);
1271 
1272  test_list_init(&list_b);
1273  fr_dlist_insert_tail(&list_b.head, &item1b);
1274  fr_dlist_insert_tail(&list_b.head, &item2b);
1275  fr_dlist_insert_tail(&list_b.head, &item3b);
1276 
1277  fr_dcursor_init(&cursor_a, &list_a.head);
1278  fr_dcursor_init(&cursor_b, &list_b.head);
1279  fr_dcursor_tail(&cursor_a);
1280  fr_dcursor_merge(&cursor_a, &cursor_b);
1281 
1282  /*
1283  * Should be final item in cursor_a
1284  */
1285  TEST_CHECK(fr_dcursor_current(&cursor_a) == &item3a);
1286  TEST_MSG("Expected %s", item3a.name);
1287  TEST_MSG("Got %s", ((test_item_t *)fr_dcursor_current(&cursor_a))->name);
1288 
1289  /*
1290  * Next three items should be from cursor_b
1291  */
1292  TEST_CHECK(fr_dcursor_next(&cursor_a) == &item1b);
1293  TEST_MSG("Expected %s", item1b.name);
1294  TEST_MSG("Got %s", ((test_item_t *)fr_dcursor_current(&cursor_a))->name);
1295  TEST_CHECK(fr_dcursor_next(&cursor_a) == &item2b);
1296  TEST_MSG("Expected %s", item2b.name);
1297  TEST_MSG("Got %s", ((test_item_t *)fr_dcursor_current(&cursor_a))->name);
1298  TEST_CHECK(fr_dcursor_next(&cursor_a) == &item3b);
1299  TEST_MSG("Expected %s", item3b.name);
1300  TEST_MSG("Got %s", ((test_item_t *)fr_dcursor_current(&cursor_a))->name);
1301 
1302  /*
1303  * Should be no more items...
1304  */
1306  TEST_CHECK(!fr_dcursor_current(&cursor_b));
1308 }
1309 
1310 static void test_dcursor_merge_mid_b(void)
1311 {
1312  fr_dcursor_t cursor_a, cursor_b;
1313 
1314  test_item_t item1a = { "item1a", { NULL, NULL } };
1315  test_item_t item2a = { "item2a", { NULL, NULL } };
1316  test_item_t item3a = { "item3a", { NULL, NULL } };
1317 
1318  test_item_t item1b = { "item1b", { NULL, NULL } };
1319  test_item_t item2b = { "item2b", { NULL, NULL } };
1320  test_item_t item3b = { "item3b", { NULL, NULL } };
1321 
1322  test_item_list_t list_a;
1323  test_item_list_t list_b;
1324 
1325  test_list_init(&list_a);
1326  fr_dlist_insert_tail(&list_a.head, &item1a);
1327  fr_dlist_insert_tail(&list_a.head, &item2a);
1328  fr_dlist_insert_tail(&list_a.head, &item3a);
1329 
1330  test_list_init(&list_b);
1331  fr_dlist_insert_tail(&list_b.head, &item1b);
1332  fr_dlist_insert_tail(&list_b.head, &item2b);
1333  fr_dlist_insert_tail(&list_b.head, &item3b);
1334 
1335  fr_dcursor_init(&cursor_a, &list_a.head);
1336  fr_dcursor_init(&cursor_b, &list_b.head);
1337  fr_dcursor_next(&cursor_b);
1338  fr_dcursor_merge(&cursor_a, &cursor_b);
1339 
1340  /*
1341  * First item in cursor_a remains unchanged
1342  *
1343  * The insertion point into cursor_a is
1344  * directly after the current item.
1345  */
1346  TEST_CHECK(fr_dcursor_current(&cursor_a) == &item1a);
1347  TEST_MSG("Expected %s", item1a.name);
1348  TEST_MSG("Got %s", ((test_item_t *)fr_dcursor_current(&cursor_a))->name);
1349 
1350  /*
1351  * Next two items should be from cursor_b
1352  */
1353  TEST_CHECK(fr_dcursor_next(&cursor_a) == &item2b);
1354  TEST_MSG("Expected %s", item2b.name);
1355  TEST_MSG("Got %s", ((test_item_t *)fr_dcursor_current(&cursor_a))->name);
1356  TEST_CHECK(fr_dcursor_next(&cursor_a) == &item3b);
1357  TEST_MSG("Expected %s", item3b.name);
1358  TEST_MSG("Got %s", ((test_item_t *)fr_dcursor_current(&cursor_a))->name);
1359 
1360  /*
1361  * Next two items should be from cursor_a
1362  */
1363  TEST_CHECK(fr_dcursor_next(&cursor_a) == &item2a);
1364  TEST_MSG("Expected %s", item2a.name);
1365  TEST_MSG("Got %s", ((test_item_t *)fr_dcursor_current(&cursor_a))->name);
1366  TEST_CHECK(fr_dcursor_next(&cursor_a) == &item3a);
1367  TEST_MSG("Expected %s", item3a.name);
1368  TEST_MSG("Got %s", ((test_item_t *)fr_dcursor_current(&cursor_a))->name);
1369  TEST_CHECK(!fr_dcursor_next(&cursor_a));
1370 
1371  TEST_CHECK(!fr_dcursor_current(&cursor_b));
1373 }
1374 
1375 static void test_dcursor_merge_end_b(void)
1376 {
1377  fr_dcursor_t cursor_a, cursor_b;
1378 
1379  test_item_t item1a = { "item1a", { NULL, NULL } };
1380  test_item_t item2a = { "item2a", { NULL, NULL } };
1381  test_item_t item3a = { "item3a", { NULL, NULL } };
1382 
1383  test_item_t item1b = { "item1b", { NULL, NULL } };
1384  test_item_t item2b = { "item2b", { NULL, NULL } };
1385  test_item_t item3b = { "item3b", { NULL, NULL } };
1386 
1387  test_item_list_t list_a;
1388  test_item_list_t list_b;
1389 
1390  test_list_init(&list_a);
1391  fr_dlist_insert_tail(&list_a.head, &item1a);
1392  fr_dlist_insert_tail(&list_a.head, &item2a);
1393  fr_dlist_insert_tail(&list_a.head, &item3a);
1394 
1395  test_list_init(&list_b);
1396  fr_dlist_insert_tail(&list_b.head, &item1b);
1397  fr_dlist_insert_tail(&list_b.head, &item2b);
1398  fr_dlist_insert_tail(&list_b.head, &item3b);
1399 
1400  fr_dcursor_init(&cursor_a, &list_a.head);
1401  fr_dcursor_init(&cursor_b, &list_b.head);
1402  fr_dcursor_next(&cursor_b);
1403  fr_dcursor_next(&cursor_b);
1404  fr_dcursor_merge(&cursor_a, &cursor_b);
1405 
1406  /*
1407  * First item in cursor_a remains unchanged
1408  *
1409  * The insertion point into cursor_a is
1410  * directly after the current item.
1411  */
1412  TEST_CHECK(fr_dcursor_current(&cursor_a) == &item1a);
1413  TEST_MSG("Expected %s", item1a.name);
1414  TEST_MSG("Got %s", ((test_item_t *)fr_dcursor_current(&cursor_a))->name);
1415 
1416  /*
1417  * Next item should be from cursor_b
1418  */
1419  TEST_CHECK(fr_dcursor_next(&cursor_a) == &item3b);
1420  TEST_MSG("Expected %s", item3b.name);
1421 
1422  /*
1423  * Next two items should be from cursor_a
1424  */
1425  TEST_MSG("Got %s", ((test_item_t *)fr_dcursor_current(&cursor_a))->name);
1426  TEST_CHECK(fr_dcursor_next(&cursor_a) == &item2a);
1427  TEST_MSG("Expected %s", item2a.name);
1428  TEST_MSG("Got %s", ((test_item_t *)fr_dcursor_current(&cursor_a))->name);
1429  TEST_CHECK(fr_dcursor_next(&cursor_a) == &item3a);
1430  TEST_MSG("Expected %s", item3a.name);
1431  TEST_MSG("Got %s", ((test_item_t *)fr_dcursor_current(&cursor_a))->name);
1432  TEST_CHECK(!fr_dcursor_next(&cursor_a));
1433 
1434  TEST_CHECK(!fr_dcursor_current(&cursor_b));
1435  TEST_CHECK(fr_dcursor_head(&cursor_b) == &item1b);
1436 }
1437 
1439 {
1440  fr_dcursor_t cursor_a, cursor_b;
1441 
1442  test_item_t item1b = { "item1b", { NULL, NULL } };
1443  test_item_t item2b = { "item2b", { NULL, NULL } };
1444  test_item_t item3b = { "item3b", { NULL, NULL } };
1445 
1446  test_item_list_t list_a;
1447  test_item_list_t list_b;
1448 
1449  test_list_init(&list_a);
1450  test_list_init(&list_b);
1451  fr_dlist_insert_tail(&list_b.head, &item1b);
1452  fr_dlist_insert_tail(&list_b.head, &item2b);
1453  fr_dlist_insert_tail(&list_b.head, &item3b);
1454 
1455  fr_dcursor_init(&cursor_a, &list_a.head);
1456  fr_dcursor_init(&cursor_b, &list_b.head);
1457  fr_dcursor_merge(&cursor_a, &cursor_b);
1458 
1459  TEST_CHECK(fr_dcursor_head(&cursor_a) == &item1b);
1460  TEST_CHECK(fr_dcursor_next(&cursor_a) == &item2b);
1461  TEST_CHECK(fr_dcursor_next(&cursor_a) == &item3b);
1462 
1463  TEST_CHECK(!fr_dcursor_current(&cursor_b));
1465 }
1466 
1467 static void test_dcursor_merge_empty(void)
1468 {
1469  fr_dcursor_t cursor_a, cursor_b;
1470 
1471  test_item_t item1a = { "item1a", { NULL, NULL } };
1472  test_item_t item2a = { "item2a", { NULL, NULL } };
1473  test_item_t item3a = { "item3a", { NULL, NULL } };
1474 
1475  test_item_list_t list_a;
1476  test_item_list_t list_b;
1477 
1478  test_list_init(&list_a);
1479  fr_dlist_insert_tail(&list_a.head, &item1a);
1480  fr_dlist_insert_tail(&list_a.head, &item2a);
1481  fr_dlist_insert_tail(&list_a.head, &item3a);
1482  test_list_init(&list_b);
1483 
1484  fr_dcursor_init(&cursor_a, &list_a.head);
1485  fr_dcursor_init(&cursor_b, &list_b.head);
1486  fr_dcursor_merge(&cursor_a, &cursor_b);
1487 
1488  TEST_CHECK(fr_dcursor_head(&cursor_a) == &item1a);
1489  TEST_CHECK(fr_dcursor_next(&cursor_a) == &item2a);
1490  TEST_CHECK(fr_dcursor_next(&cursor_a) == &item3a);
1491 }
1492 
1493 static void test_dcursor_copy(void)
1494 {
1495  fr_dcursor_t cursor_a, cursor_b;
1496 
1497  test_item_t item1 = { "item1", { NULL, NULL } };
1498  test_item_t item2 = { "item2", { NULL, NULL } };
1499  test_item_t item3 = { "item3", { NULL, NULL } };
1500 
1501  test_item_list_t list;
1502 
1503  test_list_init(&list);
1504  fr_dlist_insert_tail(&list.head, &item1);
1505  fr_dlist_insert_tail(&list.head, &item2);
1506  fr_dlist_insert_tail(&list.head, &item3);
1507 
1508  fr_dcursor_init(&cursor_a, &list.head);
1509  fr_dcursor_copy(&cursor_b, &cursor_a);
1510 
1511  TEST_CHECK(fr_dcursor_head(&cursor_b) == &item1);
1512  TEST_CHECK(fr_dcursor_next(&cursor_b) == &item2);
1513  TEST_CHECK(fr_dcursor_next(&cursor_b) == &item3);
1514 }
1515 
1516 static void test_dcursor_free(void)
1517 {
1518  test_item_t *item1, *item2, *item3;
1519  test_item_list_t list;
1520  fr_dcursor_t cursor;
1521  void *item_p;
1522 
1523  test_list_init(&list);
1524 
1525  item1 = talloc_zero(NULL, test_item_t);
1526  item2 = talloc_zero(NULL, test_item_t);
1527  item3 = talloc_zero(NULL, test_item_t);
1528 
1529  fr_dcursor_init(&cursor, &list.head);
1530  fr_dcursor_append(&cursor, item1);
1531  fr_dcursor_append(&cursor, item2);
1532  fr_dcursor_append(&cursor, item3);
1533 
1534  fr_dcursor_next(&cursor);
1535  fr_dcursor_free_list(&cursor);
1536 
1537  TEST_CHECK(fr_dcursor_current(&cursor) == NULL);
1538  TEST_CHECK(!fr_dcursor_tail(&cursor));
1539  TEST_CHECK(!fr_dcursor_head(&cursor));
1540 
1541  item_p = fr_dcursor_remove(&cursor);
1542  talloc_free(item_p);
1543 }
1544 
1545 static void test_dcursor_free_item(void)
1546 {
1547  test_item_t *item1, *item2, *item3;
1548  test_item_list_t list;
1549  fr_dcursor_t cursor;
1550 
1551  test_list_init(&list);
1552 
1553  item1 = talloc_zero(NULL, test_item_t);
1554  item2 = talloc_zero(NULL, test_item_t);
1555  item3 = talloc_zero(NULL, test_item_t);
1556 
1557  fr_dcursor_init(&cursor, &list.head);
1558  fr_dcursor_append(&cursor, item1);
1559  fr_dcursor_append(&cursor, item2);
1560  fr_dcursor_append(&cursor, item3);
1561 
1562  fr_dcursor_head(&cursor);
1563  fr_dcursor_free_item(&cursor);
1564 
1565  TEST_CHECK(fr_dcursor_current(&cursor) == item2);
1566  TEST_CHECK(fr_dcursor_tail(&cursor) == item3);
1567  TEST_CHECK(fr_dcursor_head(&cursor) == item2);
1568 
1569  fr_dcursor_free_item(&cursor);
1570  fr_dcursor_free_item(&cursor);
1571 
1572  TEST_CHECK(fr_dcursor_current(&cursor) == NULL);
1573  TEST_CHECK(!fr_dcursor_tail(&cursor));
1574  TEST_CHECK(!fr_dcursor_head(&cursor));
1575 }
1576 
1577 
1578 typedef struct {
1579  int pos;
1580  char val;
1581 } item_filter;
1582 
1583 static void *iter_name_check(fr_dlist_head_t *list, void *current, void *uctx)
1584 {
1585  test_item_t *c = current;
1586  item_filter *f = uctx;
1587 
1588  while((c = fr_dlist_next(list, c))) {
1589  if (c->name[f->pos] == f->val) break;
1590  }
1591 
1592  return c;
1593 }
1594 
1596 {
1597  fr_dcursor_t cursor_a, cursor_b;
1598 
1599  test_item_t item1 = {"item1", { NULL, NULL } };
1600  test_item_t item2 = {"item2", { NULL, NULL } };
1601  test_item_list_t list_a;
1602  test_item_list_t list_b;
1603 
1604  test_list_init(&list_a);
1605  fr_dlist_insert_tail(&list_a.head, &item1);
1606  test_list_init(&list_b);
1607  fr_dlist_insert_tail(&list_b.head, &item2);
1608 
1609  fr_dcursor_init(&cursor_a, &list_a.head);
1610  fr_dcursor_init(&cursor_b, &list_b.head);
1611 
1612  TEST_CHECK(fr_dcursor_intersect_head(&cursor_a, &cursor_b) == NULL);
1613 }
1614 
1616 {
1617  fr_dcursor_t cursor_a, cursor_b;
1618 
1619  test_item_t item1 = { "item1", { NULL, NULL } };
1620  test_item_t item2 = { "item2", { NULL, NULL } };
1621  test_item_t item3 = { "item3", { NULL, NULL } };
1622  test_item_t *item4 = NULL;
1623  test_item_list_t list;
1624 
1625  test_list_init(&list);
1626  fr_dlist_insert_tail(&list.head, &item1);
1627  fr_dlist_insert_tail(&list.head, &item2);
1628  fr_dlist_insert_tail(&list.head, &item3);
1629 
1630  fr_dcursor_init(&cursor_a, &list.head);
1631  fr_dcursor_init(&cursor_b, &list.head);
1632 
1633  item4 = fr_dcursor_intersect_head(&cursor_a, &cursor_b);
1634  TEST_CHECK(item4 == &item1);
1635  // TEST_CHECK(fr_dcursor_intersect_head(&cursor_a, &cursor_b) == &item1);
1636  TEST_CHECK(fr_dcursor_intersect_next(&cursor_a, &cursor_b) == &item2);
1637  TEST_CHECK(fr_dcursor_intersect_next(&cursor_a, &cursor_b) == &item3);
1638  TEST_CHECK(fr_dcursor_intersect_next(&cursor_a, &cursor_b) == NULL);
1639 }
1640 
1641 static void test_intersect_iterator_a(void)
1642 {
1643  fr_dcursor_t cursor_a, cursor_b;
1644 
1645  test_item_t item1 = { "actor", { NULL, NULL } };
1646  test_item_t item2 = { "alter", { NULL, NULL } };
1647  test_item_t item3 = { "extra", { NULL, NULL } };
1648  test_item_t item4 = { "after", { NULL, NULL } };
1649  test_item_list_t list;
1650  item_filter filter_a = { 0, 'a' };
1651 
1652  test_list_init(&list);
1653  fr_dlist_insert_tail(&list.head, &item1);
1654  fr_dlist_insert_tail(&list.head, &item2);
1655  fr_dlist_insert_tail(&list.head, &item3);
1656  fr_dlist_insert_tail(&list.head, &item4);
1657 
1658  fr_dcursor_iter_init(&cursor_a, &list.head, iter_name_check, NULL, &filter_a);
1659  fr_dcursor_init(&cursor_b, &list.head);
1660 
1661  TEST_CHECK(fr_dcursor_intersect_head(&cursor_a, &cursor_b) == &item1);
1662  TEST_CHECK(fr_dcursor_intersect_next(&cursor_a, &cursor_b) == &item2);
1663  TEST_CHECK(fr_dcursor_intersect_next(&cursor_a, &cursor_b) == &item4);
1664  TEST_CHECK(fr_dcursor_intersect_next(&cursor_a, &cursor_b) == NULL);
1665 }
1666 
1667 static void test_intersect_iterator_b(void)
1668 {
1669  fr_dcursor_t cursor_a, cursor_b;
1670 
1671  test_item_t item1 = { "blink", { NULL, NULL } };
1672  test_item_t item2 = { "alter", { NULL, NULL } };
1673  test_item_t item3 = { "basic", { NULL, NULL } };
1674  test_item_t item4 = { "bland", { NULL, NULL } };
1675  test_item_list_t list;
1676  item_filter filter_b = { 0, 'b'};
1677 
1678  test_list_init(&list);
1679  fr_dlist_insert_tail(&list.head, &item1);
1680  fr_dlist_insert_tail(&list.head, &item2);
1681  fr_dlist_insert_tail(&list.head, &item3);
1682  fr_dlist_insert_tail(&list.head, &item4);
1683 
1684  fr_dcursor_init(&cursor_a, &list.head);
1685  fr_dcursor_iter_init(&cursor_b, &list.head, iter_name_check, NULL, &filter_b);
1686 
1687  TEST_CHECK(fr_dcursor_intersect_head(&cursor_a, &cursor_b) == &item1);
1688  TEST_CHECK(fr_dcursor_intersect_next(&cursor_a, &cursor_b) == &item3);
1689  TEST_CHECK(fr_dcursor_intersect_next(&cursor_a, &cursor_b) == &item4);
1690 }
1691 
1693 {
1694  fr_dcursor_t cursor_a, cursor_b;
1695 
1696  test_item_t item1 = { "baits", { NULL, NULL } };
1697  test_item_t item2 = { "alter", { NULL, NULL } };
1698  test_item_t item3 = { "basic", { NULL, NULL } };
1699  test_item_t item4 = { "cavil", { NULL, NULL } };
1700  test_item_t item5 = { "bland", { NULL, NULL } };
1701  test_item_list_t list;
1702  item_filter filter_a = { 1, 'a' };
1703  item_filter filter_b = { 0, 'b' };
1704 
1705  test_list_init(&list);
1706  fr_dlist_insert_tail(&list.head, &item1);
1707  fr_dlist_insert_tail(&list.head, &item2);
1708  fr_dlist_insert_tail(&list.head, &item3);
1709  fr_dlist_insert_tail(&list.head, &item4);
1710  fr_dlist_insert_tail(&list.head, &item5);
1711 
1712  fr_dcursor_iter_init(&cursor_a, &list.head, iter_name_check, NULL, &filter_a);
1713  fr_dcursor_iter_init(&cursor_b, &list.head, iter_name_check, NULL, &filter_b);
1714 
1715  TEST_CHECK(fr_dcursor_intersect_head(&cursor_a, &cursor_b) == &item1);
1716  TEST_CHECK(fr_dcursor_intersect_next(&cursor_a, &cursor_b) == &item3);
1717  TEST_MSG("Expected %s", item3.name);
1718  TEST_MSG("Current %p", fr_dcursor_current(&cursor_a));
1719  TEST_CHECK(fr_dcursor_intersect_next(&cursor_a, &cursor_b) == NULL);
1720 }
1721 
1723 {
1724  fr_dcursor_t cursor_a, cursor_b;
1725 
1726  test_item_t item1 = { "baits", { NULL, NULL } };
1727  test_item_t item2 = { "alter", { NULL, NULL } };
1728  test_item_t item3 = { "basic", { NULL, NULL } };
1729  test_item_t item4 = { "cavil", { NULL, NULL } };
1730  test_item_t item5 = { "bland", { NULL, NULL } };
1731  test_item_list_t list;
1732  item_filter filter_a = { 0, 'a' };
1733  item_filter filter_b = { 0, 'b' };
1734 
1735  test_list_init(&list);
1736  fr_dlist_insert_tail(&list.head, &item1);
1737  fr_dlist_insert_tail(&list.head, &item2);
1738  fr_dlist_insert_tail(&list.head, &item3);
1739  fr_dlist_insert_tail(&list.head, &item4);
1740  fr_dlist_insert_tail(&list.head, &item5);
1741 
1742  fr_dcursor_iter_init(&cursor_a, &list.head, iter_name_check, NULL, &filter_a);
1743  fr_dcursor_iter_init(&cursor_b, &list.head, iter_name_check, NULL, &filter_b);
1744 
1745  TEST_CHECK(fr_dcursor_intersect_head(&cursor_a, &cursor_b) == NULL);
1746 }
1747 
1748 static bool eval_eq(void const *item, void const *uctx)
1749 {
1750  test_item_t const *t = item;
1751  char const *s = uctx;
1752 
1753  return strcmp(t->name, s) == 0;
1754 }
1755 
1756 static void test_filter_head_next(void)
1757 {
1758  fr_dcursor_t cursor;
1759 
1760  test_item_t item1 = { "yes", { NULL, NULL } };
1761  test_item_t item2 = { "no", { NULL, NULL } };
1762  test_item_t item3 = { "yes", { NULL, NULL } };
1763  test_item_t item4 = { "no", { NULL, NULL } };
1764  test_item_t item5 = { "yes", { NULL, NULL } };
1765  test_item_t item6 = { "no", { NULL, NULL } };
1766  test_item_list_t list;
1767 
1768  test_list_init(&list);
1769  fr_dlist_insert_tail(&list.head, &item1);
1770  fr_dlist_insert_tail(&list.head, &item2);
1771  fr_dlist_insert_tail(&list.head, &item3);
1772  fr_dlist_insert_tail(&list.head, &item4);
1773  fr_dlist_insert_tail(&list.head, &item5);
1774  fr_dlist_insert_tail(&list.head, &item6);
1775 
1776  fr_dcursor_init(&cursor, &list.head);
1777 
1778  TEST_CHECK(fr_dcursor_filter_head(&cursor, eval_eq, "yes") == &item1);
1779  TEST_CHECK(fr_dcursor_filter_next(&cursor, eval_eq, "yes") == &item3);
1780  TEST_CHECK(fr_dcursor_filter_next(&cursor, eval_eq, "yes") == &item5);
1781  TEST_CHECK(fr_dcursor_filter_next(&cursor, eval_eq, "yes") == NULL);
1782 }
1783 
1784 static void test_filter_current(void)
1785 {
1786  fr_dcursor_t cursor;
1787 
1788  test_item_t item1 = { "yes", { NULL, NULL } };
1789  test_item_t item2 = { "no", { NULL, NULL } };
1790  test_item_t item3 = { "yes", { NULL, NULL } };
1791  test_item_t item4 = { "no", { NULL, NULL } };
1792  test_item_t item5 = { "yes", { NULL, NULL } };
1793  test_item_t item6 = { "no", { NULL, NULL } };
1794  test_item_list_t list;
1795 
1796  test_list_init(&list);
1797  fr_dlist_insert_tail(&list.head, &item1);
1798  fr_dlist_insert_tail(&list.head, &item2);
1799  fr_dlist_insert_tail(&list.head, &item3);
1800  fr_dlist_insert_tail(&list.head, &item4);
1801  fr_dlist_insert_tail(&list.head, &item5);
1802  fr_dlist_insert_tail(&list.head, &item6);
1803 
1804  fr_dcursor_init(&cursor, &list.head);
1805 
1806  TEST_CHECK(fr_dcursor_filter_current(&cursor, eval_eq, "yes") == &item1);
1807  fr_dcursor_next(&cursor);
1808  TEST_CHECK(fr_dcursor_filter_current(&cursor, eval_eq, "yes") == &item3);
1809  fr_dcursor_next(&cursor);
1810  TEST_CHECK(fr_dcursor_filter_current(&cursor, eval_eq, "yes") == &item5);
1811  fr_dcursor_next(&cursor);
1812  TEST_CHECK(fr_dcursor_filter_current(&cursor, eval_eq, "yes") == NULL);
1813 }
1814 
1815 static void test_filter_no_match(void)
1816 {
1817  fr_dcursor_t cursor;
1818 
1819  test_item_t item1 = { "yes", { NULL, NULL } };
1820  test_item_t item2 = { "no", { NULL, NULL } };
1821  test_item_t item3 = { "yes", { NULL, NULL } };
1822  test_item_t item4 = { "no", { NULL, NULL } };
1823  test_item_t item5 = { "yes", { NULL, NULL } };
1824  test_item_t item6 = { "no", { NULL, NULL } };
1825  test_item_list_t list;
1826 
1827  test_list_init(&list);
1828  fr_dlist_insert_tail(&list.head, &item1);
1829  fr_dlist_insert_tail(&list.head, &item2);
1830  fr_dlist_insert_tail(&list.head, &item3);
1831  fr_dlist_insert_tail(&list.head, &item4);
1832  fr_dlist_insert_tail(&list.head, &item5);
1833  fr_dlist_insert_tail(&list.head, &item6);
1834 
1835  fr_dcursor_init(&cursor, &list.head);
1836 
1837  TEST_CHECK(fr_dcursor_filter_current(&cursor, eval_eq, "maybe") == NULL);
1838 }
1839 
1841  /*
1842  * Initialisation
1843  */
1844  { "init_null", test_init_null_item },
1845  { "init_one", test_init_1i_start },
1846  { "init_two", test_init_2i_start },
1847 
1848  /*
1849  * Normal iteration
1850  */
1851  { "next", test_next },
1852  { "next_wrap", test_next_wrap }, /* should not wrap */
1853 
1854  /*
1855  * Jump to head/tail
1856  */
1857  { "head_tail_null", test_dcursor_head_tail_null },
1858  { "head", test_dcursor_head },
1859  { "head_reset", test_dcursor_head_reset },
1860  { "head_iter_reset", test_dcursor_iter_head_reset },
1861  { "head_after_next", test_dcursor_head_after_next },
1862  { "tail", test_dcursor_tail },
1863  { "head_after_tail", test_dcursor_head_after_tail },
1864  { "wrap_after_tail", test_dcursor_wrap_after_tail },
1865 
1866  /*
1867  * Set current
1868  */
1869  { "current_valid", test_dcursor_current_set_valid },
1870  { "current_invalid", test_dcursor_current_set_invalid },
1871 
1872  /*
1873  * Insert with empty list
1874  */
1875  { "prepend_empty", test_dcursor_prepend_empty },
1876  { "append_empty", test_dcursor_append_empty },
1877  { "append_empty_3", test_dcursor_append_empty_3 },
1878  { "insert_into_empty", test_dcursor_insert_into_empty },
1879  { "insert_into_empty_3", test_dcursor_insert_into_empty_3 },
1880  { "replace_in_empty", test_dcursor_replace_in_empty },
1881 
1882  /*
1883  * Insert with one item list
1884  */
1885  { "prepend_1i_start", test_dcursor_prepend_1i_start},
1886  { "append_1i_start", test_dcursor_append_1i_start },
1887  { "insert_1i_start", test_dcursor_insert_1i_start },
1888  { "replace_1i_start", test_dcursor_replace_1i_start },
1889 
1890  /*
1891  * Insert with two item list
1892  */
1893  { "prepend_2i_start", test_dcursor_prepend_2i_start },
1894  { "append_2i_start", test_dcursor_append_2i_start },
1895  { "insert_2i_start", test_dcursor_insert_2i_start },
1896  { "replace_2i_start", test_dcursor_replace_2i_start },
1897 
1898  /*
1899  * Insert with three item list (with cursor on item2)
1900  */
1901  { "prepend_3i_mid", test_dcursor_prepend_3i_mid },
1902  { "append_3i_mid", test_dcursor_append_3i_mid },
1903  { "insert_3i_mid", test_dcursor_insert_3i_mid },
1904  { "replace_3i_mid", test_dcursor_replace_3i_mid },
1905 
1906  /*
1907  * Insert with three item list (with cursor on item3)
1908  */
1909  { "prepend_3i_end", test_dcursor_prepend_3i_end },
1910  { "append_3i_end", test_dcursor_append_3i_end },
1911  { "insert_3i_end", test_dcursor_insert_3i_end },
1912  { "replace_3i_end", test_dcursor_replace_3i_end },
1913 
1914  /*
1915  * Remove
1916  */
1917  { "remove_empty", test_dcursor_remove_empty },
1918  { "remove_1i", test_dcursor_remove_1i },
1919  { "remove_2i", test_dcursor_remove_2i },
1920  { "remove_3i_start", test_dcursor_remove_3i_start },
1921  { "remove_3i_mid", test_dcursor_remove_3i_mid },
1922  { "remove_3i_end", test_dcursor_remove_3i_end },
1923 
1924  /*
1925  * Merge
1926  */
1927  { "merge_start_a_b", test_dcursor_merge_start_a_b },
1928  { "merge_mid_a", test_dcursor_merge_mid_a },
1929  { "merge_end_a", test_dcursor_merge_end_a },
1930  { "merge_mid_b", test_dcursor_merge_mid_b },
1931  { "merge_end_b", test_dcursor_merge_end_b },
1932  { "merge_with_empty", test_dcursor_merge_with_empty },
1933  { "merge_empty", test_dcursor_merge_empty },
1934 
1935  /*
1936  * Copy
1937  */
1938  { "copy", test_dcursor_copy },
1939 
1940  /*
1941  * Free
1942  */
1943  { "free", test_dcursor_free },
1944  { "free_item", test_dcursor_free_item },
1945  /*
1946  * Intersect
1947  */
1948  { "differing_lists", test_intersect_differing_lists },
1949  { "no_iterators", test_intersect_no_iterators },
1950  { "iterator_a", test_intersect_iterator_a },
1951  { "iterator_b", test_intersect_iterator_b },
1952  { "iterator_ab", test_intersect_iterator_ab },
1953  { "iterator_disjoint", test_intersect_iterator_disjoint },
1954  /*
1955  * Filter
1956  */
1957  { "head_next", test_filter_head_next },
1958  { "current", test_filter_current },
1959  { "no_match", test_filter_no_match },
1960 
1961  { NULL }
1962 };
#define TEST_CHECK(cond)
Definition: acutest.h:85
#define TEST_MSG(...)
Definition: acutest.h:215
#define UNUSED
Definition: build.h:313
Functions to iterate over a sets and subsets of items in dlists.
void * fr_dcursor_intersect_next(fr_dcursor_t *a, fr_dcursor_t *b)
Return the next item matching the iterator in cursor a and cursor b.
Definition: dcursor.c:76
void * fr_dcursor_intersect_head(fr_dcursor_t *a, fr_dcursor_t *b)
Return the first item matching the iterator in cursor a and cursor b.
Definition: dcursor.c:47
static void * fr_dcursor_remove(fr_dcursor_t *cursor)
Remove the current item.
Definition: dcursor.h:480
static void * fr_dcursor_list_next_peek(fr_dcursor_t *cursor)
Returns the next list item without advancing the cursor.
Definition: dcursor.h:322
static void * _fr_dcursor_init(fr_dcursor_t *cursor, fr_dlist_head_t const *head, fr_dcursor_iter_t iter, fr_dcursor_iter_t peek, void const *iter_uctx, fr_dcursor_insert_t insert, fr_dcursor_remove_t remove, void const *mod_uctx, bool is_const)
Setup a cursor to iterate over attribute items in dlists.
Definition: dcursor.h:759
return fr_dcursor_filter_next(cursor, eval, uctx)
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
Definition: dcursor.h:406
static void fr_dcursor_copy(fr_dcursor_t *out, fr_dcursor_t const *in)
Copy cursor parameters and state.
Definition: dcursor.h:192
static void fr_dcursor_merge(fr_dcursor_t *cursor, fr_dcursor_t *to_append)
Moves items from one cursor to another.
Definition: dcursor.h:520
static void * fr_dcursor_tail(fr_dcursor_t *cursor)
Wind cursor to the tail item in the list.
Definition: dcursor.h:259
#define fr_dcursor_iter_init(_cursor, _head, _iter, _peek, _uctx)
Initialise a cursor with a custom iterator.
Definition: dcursor.h:713
static int fr_dcursor_insert(fr_dcursor_t *cursor, void *v)
Insert directly after the current item.
Definition: dcursor.h:435
static void * fr_dcursor_next_peek(fr_dcursor_t *cursor)
Return the next iterator item without advancing the cursor.
Definition: dcursor.h:303
#define fr_dcursor_init(_cursor, _head)
Initialise a cursor.
Definition: dcursor.h:732
static void fr_dcursor_free_item(fr_dcursor_t *cursor)
talloc_free the current item
Definition: dcursor.h:805
static void * fr_dcursor_set_current(fr_dcursor_t *cursor, void *item)
Set the cursor to a specified item.
Definition: dcursor.h:353
static void fr_dcursor_free_list(fr_dcursor_t *cursor)
Free the current item and all items after it.
Definition: dcursor.h:663
fr_dcursor_eval_t void const * uctx
Definition: dcursor.h:546
fr_dcursor_iter_t void * current
Definition: dcursor.h:148
fr_dlist_head_t * dlist
Head of the doubly linked list being iterated over.
Definition: dcursor.h:94
static int fr_dcursor_prepend(fr_dcursor_t *cursor, void *v)
Insert a single item at the start of the list.
Definition: dcursor.h:376
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition: dcursor.h:288
static void * fr_dcursor_replace(fr_dcursor_t *cursor, void *r)
Replace the current item.
Definition: dcursor.h:610
void * iter_uctx
to pass to iterator function.
Definition: dcursor.h:100
return item
Definition: dcursor.h:553
static void * fr_dcursor_head(fr_dcursor_t *cursor)
Rewind cursor to the start of the list.
Definition: dcursor.h:234
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
Definition: dcursor.h:337
static void test_dcursor_append_3i_end(void)
static void test_intersect_iterator_b(void)
static void * iter_name_check(fr_dlist_head_t *list, void *current, void *uctx)
static void test_dcursor_replace_3i_mid(void)
static void test_dcursor_free(void)
TEST_LIST
static void test_intersect_iterator_a(void)
static void test_dcursor_merge_empty(void)
static void test_dcursor_prepend_empty(void)
static void test_dcursor_merge_end_b(void)
static void test_dcursor_append_empty(void)
static void test_dcursor_replace_2i_start(void)
static void test_dcursor_free_item(void)
static void test_dcursor_head_tail_null(void)
static void test_dcursor_replace_1i_start(void)
static void test_dcursor_prepend_3i_end(void)
static void test_dcursor_remove_3i_mid(void)
static void test_dcursor_insert_2i_start(void)
static void test_dcursor_copy(void)
static void test_init_2i_start(void)
Definition: dcursor_tests.c:60
static void test_dcursor_remove_3i_start(void)
static void test_dcursor_merge_mid_a(void)
static void test_dcursor_wrap_after_tail(void)
static void test_dcursor_append_3i_mid(void)
static void test_filter_no_match(void)
static void test_dcursor_append_1i_start(void)
static void test_dcursor_prepend_2i_start(void)
static void test_intersect_iterator_disjoint(void)
static void test_dcursor_iter_head_reset(void)
static void test_dcursor_tail(void)
static void test_dcursor_head(void)
static void test_dcursor_current_set_invalid(void)
static void test_next(void)
Definition: dcursor_tests.c:77
static void test_dcursor_remove_2i(void)
static void test_dcursor_current_set_valid(void)
static void test_dcursor_remove_empty(void)
static void test_intersect_no_iterators(void)
static void test_dcursor_replace_in_empty(void)
static void test_dcursor_insert_1i_start(void)
static bool eval_eq(void const *item, void const *uctx)
static void test_dcursor_head_after_next(void)
static void test_dcursor_merge_start_a_b(void)
static void test_dcursor_head_reset(void)
static void test_dcursor_merge_with_empty(void)
static void test_dcursor_append_2i_start(void)
static void test_dcursor_prepend_3i_mid(void)
static void test_next_wrap(void)
Definition: dcursor_tests.c:98
static void test_dcursor_merge_mid_b(void)
static void test_dcursor_replace_3i_end(void)
static void test_init_null_item(void)
Verify internal state is initialised correctly.
Definition: dcursor_tests.c:28
static void test_dcursor_insert_into_empty_3(void)
static void test_intersect_differing_lists(void)
static void test_filter_head_next(void)
static void test_dcursor_head_after_tail(void)
static void test_dcursor_prepend_1i_start(void)
static void test_dcursor_append_empty_3(void)
static void test_dcursor_insert_into_empty(void)
static void test_dcursor_remove_1i(void)
static void test_filter_current(void)
static void test_intersect_iterator_ab(void)
static void test_dcursor_insert_3i_mid(void)
static void test_dcursor_insert_3i_end(void)
static void * test_iter(fr_dlist_head_t *list, void *current, UNUSED void *uctx)
Definition: dcursor_tests.c:14
static void test_list_init(test_item_list_t *list)
Definition: dcursor_tests.c:20
fr_dlist_head_t head
Definition: dcursor_tests.c:11
static void test_init_1i_start(void)
Definition: dcursor_tests.c:44
static void test_dcursor_merge_end_a(void)
static void test_dcursor_remove_3i_end(void)
char const * name
Definition: dcursor_tests.c:6
fr_dlist_t entry
Definition: dcursor_tests.c:7
static void * fr_dlist_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
Definition: dlist.h:555
static int fr_dlist_insert_tail(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the tail of a list.
Definition: dlist.h:378
#define fr_dlist_talloc_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
Definition: dlist.h:275
Head of a doubly linked list.
Definition: dlist.h:51
Entry in a doubly linked list.
Definition: dlist.h:41
talloc_free(reap)
static char const * name