| /* Make sure macros only evaluate their args once. */ |
| #include <ccan/list/list.h> |
| #include <ccan/tap/tap.h> |
| #include <ccan/list/list.c> |
| |
| struct parent { |
| const char *name; |
| struct list_head children; |
| unsigned int num_children; |
| int eval_count; |
| }; |
| |
| struct child { |
| const char *name; |
| struct list_node list; |
| }; |
| |
| static LIST_HEAD(static_list); |
| |
| #define ref(obj, counter) ((counter)++, (obj)) |
| |
| int main(void) |
| { |
| struct parent parent; |
| struct child c1, c2, c3, *c, *n; |
| unsigned int i; |
| unsigned int static_count = 0, parent_count = 0, list_count = 0, |
| node_count = 0; |
| struct list_head list = LIST_HEAD_INIT(list); |
| |
| plan_tests(74); |
| /* Test LIST_HEAD, LIST_HEAD_INIT, list_empty and check_list */ |
| ok1(list_empty(ref(&static_list, static_count))); |
| ok1(static_count == 1); |
| ok1(list_check(ref(&static_list, static_count), NULL)); |
| ok1(static_count == 2); |
| ok1(list_empty(ref(&list, list_count))); |
| ok1(list_count == 1); |
| ok1(list_check(ref(&list, list_count), NULL)); |
| ok1(list_count == 2); |
| |
| parent.num_children = 0; |
| list_head_init(ref(&parent.children, parent_count)); |
| ok1(parent_count == 1); |
| /* Test list_head_init */ |
| ok1(list_empty(ref(&parent.children, parent_count))); |
| ok1(parent_count == 2); |
| ok1(list_check(ref(&parent.children, parent_count), NULL)); |
| ok1(parent_count == 3); |
| |
| c2.name = "c2"; |
| list_add(ref(&parent.children, parent_count), &c2.list); |
| ok1(parent_count == 4); |
| /* Test list_add and !list_empty. */ |
| ok1(!list_empty(ref(&parent.children, parent_count))); |
| ok1(parent_count == 5); |
| ok1(c2.list.next == &parent.children.n); |
| ok1(c2.list.prev == &parent.children.n); |
| ok1(parent.children.n.next == &c2.list); |
| ok1(parent.children.n.prev == &c2.list); |
| /* Test list_check */ |
| ok1(list_check(ref(&parent.children, parent_count), NULL)); |
| ok1(parent_count == 6); |
| |
| c1.name = "c1"; |
| list_add(ref(&parent.children, parent_count), &c1.list); |
| ok1(parent_count == 7); |
| /* Test list_add and !list_empty. */ |
| ok1(!list_empty(ref(&parent.children, parent_count))); |
| ok1(parent_count == 8); |
| ok1(c2.list.next == &parent.children.n); |
| ok1(c2.list.prev == &c1.list); |
| ok1(parent.children.n.next == &c1.list); |
| ok1(parent.children.n.prev == &c2.list); |
| ok1(c1.list.next == &c2.list); |
| ok1(c1.list.prev == &parent.children.n); |
| /* Test list_check */ |
| ok1(list_check(ref(&parent.children, parent_count), NULL)); |
| ok1(parent_count == 9); |
| |
| c3.name = "c3"; |
| list_add_tail(ref(&parent.children, parent_count), &c3.list); |
| ok1(parent_count == 10); |
| /* Test list_add_tail and !list_empty. */ |
| ok1(!list_empty(ref(&parent.children, parent_count))); |
| ok1(parent_count == 11); |
| ok1(parent.children.n.next == &c1.list); |
| ok1(parent.children.n.prev == &c3.list); |
| ok1(c1.list.next == &c2.list); |
| ok1(c1.list.prev == &parent.children.n); |
| ok1(c2.list.next == &c3.list); |
| ok1(c2.list.prev == &c1.list); |
| ok1(c3.list.next == &parent.children.n); |
| ok1(c3.list.prev == &c2.list); |
| /* Test list_check */ |
| ok1(list_check(ref(&parent.children, parent_count), NULL)); |
| ok1(parent_count == 12); |
| |
| /* Test list_check_node */ |
| ok1(list_check_node(&c1.list, NULL)); |
| ok1(list_check_node(&c2.list, NULL)); |
| ok1(list_check_node(&c3.list, NULL)); |
| |
| /* Test list_top */ |
| ok1(list_top(ref(&parent.children, parent_count), struct child, list) == &c1); |
| ok1(parent_count == 13); |
| |
| /* Test list_tail */ |
| ok1(list_tail(ref(&parent.children, parent_count), struct child, list) == &c3); |
| ok1(parent_count == 14); |
| |
| /* Test list_for_each. */ |
| i = 0; |
| list_for_each(&parent.children, c, list) { |
| switch (i++) { |
| case 0: |
| ok1(c == &c1); |
| break; |
| case 1: |
| ok1(c == &c2); |
| break; |
| case 2: |
| ok1(c == &c3); |
| break; |
| } |
| if (i > 2) |
| break; |
| } |
| ok1(i == 3); |
| |
| /* Test list_for_each_safe, list_del and list_del_from. */ |
| i = 0; |
| list_for_each_safe(&parent.children, c, n, list) { |
| switch (i++) { |
| case 0: |
| ok1(c == &c1); |
| list_del(ref(&c->list, node_count)); |
| ok1(node_count == 1); |
| break; |
| case 1: |
| ok1(c == &c2); |
| list_del_from(ref(&parent.children, parent_count), |
| ref(&c->list, node_count)); |
| ok1(node_count == 2); |
| break; |
| case 2: |
| ok1(c == &c3); |
| list_del_from(ref(&parent.children, parent_count), |
| ref(&c->list, node_count)); |
| ok1(node_count == 3); |
| break; |
| } |
| ok1(list_check(ref(&parent.children, parent_count), NULL)); |
| if (i > 2) |
| break; |
| } |
| ok1(i == 3); |
| ok1(parent_count == 19); |
| ok1(list_empty(ref(&parent.children, parent_count))); |
| ok1(parent_count == 20); |
| |
| /* Test list_top/list_tail on empty list. */ |
| ok1(list_top(ref(&parent.children, parent_count), struct child, list) == NULL); |
| ok1(parent_count == 21); |
| ok1(list_tail(ref(&parent.children, parent_count), struct child, list) == NULL); |
| ok1(parent_count == 22); |
| return exit_status(); |
| } |