#include #include "tupperware/list.h" TestSuite(list, .timeout = 15); struct int_list { int val; struct list_node list; }; Test(list, init_null) { list_init(NULL); } Test(list, init) { struct list l = { (void *)0x42 }; list_init(&l); cr_assert_null(l.head); } static void int_list_dtor(struct list_node *list, void *cookie) { size_t *count = cookie; struct int_list *l = CONTAINER_OF(struct int_list, list, list); cr_assert_eq(l->val, ++*count); } Test(list, clear_null) { size_t count = 0; list_clear(NULL, int_list_dtor, &count); cr_assert_eq(count, 0); struct list l = { NULL }; list_clear(&l, int_list_dtor, &count); cr_assert_eq(count, 0); } Test(list, clear_one) { struct int_list list = { 1, { &list.list, &list.list } }; struct list l = { &list.list }; size_t count = 0; list_clear(&l, int_list_dtor, &count); cr_assert_eq(count, 1); cr_assert_null(l.head); } static void init_list_arr(struct int_list *list_arr, size_t n, int offset) { for (size_t i = 0; i < n; ++i) { list_arr[i].val = i + 1 + offset; list_arr[i].list.next = &list_arr[(i + 1) % n].list; list_arr[(i + 1) % n].list.prev = &list_arr[i].list; } } static void assert_list(struct int_list *list_arr, size_t n, int offset) { for (size_t i = 0; i < n; ++i) { cr_assert_eq(list_arr[i]. val, i + 1 + offset); cr_assert_eq(list_arr[i].list.next, &list_arr[(i + 1) % n].list); cr_assert_eq(list_arr[(i + 1) % n].list.prev, &list_arr[i % n].list); } } #define ARR_SIZE(Arr) (sizeof(Arr) / sizeof(*Arr)) Test(list, clear_multiples) { struct int_list arr[10]; init_list_arr(arr, ARR_SIZE(arr), 0); struct list l = { &arr[0].list }; size_t count = 0; list_clear(&l, int_list_dtor, &count); cr_assert_eq(count, ARR_SIZE(arr)); cr_assert_null(l.head); } Test(list, node_insert_prev_null) { list_node_insert_prev(NULL, NULL); struct list_node l = { NULL, NULL }; list_node_insert_prev(&l, NULL); list_node_insert_prev(NULL, &l); } Test(list, node_insert_prev_one) { struct int_list arr[] = { { 1, { NULL, NULL, }, }, { 2, { NULL, NULL, }, }, }; init_list_arr(arr + 1, ARR_SIZE(arr) - 1, 1); list_node_insert_prev(&arr[1].list, &arr[0].list); assert_list(arr, ARR_SIZE(arr), 0); } Test(list, node_insert_prev) { struct int_list arr[] = { { 1, { NULL, NULL, }, }, { 2, { NULL, NULL, }, }, { 3, { NULL, NULL, }, }, }; init_list_arr(arr + 1, ARR_SIZE(arr) - 1, 1); list_node_insert_prev(&arr[1].list, &arr[0].list); assert_list(arr, ARR_SIZE(arr), 0); } Test(list, node_insert_next_null) { list_node_insert_next(NULL, NULL); struct list_node l; list_node_insert_next(&l, NULL); list_node_insert_next(NULL, &l); } Test(list, node_insert_next_one) { struct int_list arr[] = { { 1, { NULL, NULL, }, }, { 2, { NULL, NULL, }, }, }; init_list_arr(arr, ARR_SIZE(arr) - 1, 0); list_node_insert_next( &arr[ARR_SIZE(arr) - 2].list, &arr[ARR_SIZE(arr) - 1].list); assert_list(arr, ARR_SIZE(arr), 0); } Test(list, node_insert_next) { struct int_list arr[] = { { 1, { NULL, NULL, }, }, { 2, { NULL, NULL, }, }, { 3, { NULL, NULL, }, }, }; init_list_arr(arr, ARR_SIZE(arr) - 1, 0); list_node_insert_next( &arr[ARR_SIZE(arr) - 2].list, &arr[ARR_SIZE(arr) - 1].list); assert_list(arr, ARR_SIZE(arr), 0); } Test(list, node_detach_null) { cr_assert_null(list_node_detach(NULL)); } Test(list, node_detach_one) { struct int_list l = { 0, { &l.list, &l.list } }; struct list_node *n = list_node_detach(&l.list); cr_assert_eq(n, &l.list); cr_assert_eq(n->next, n); cr_assert_eq(n->prev, n); } Test(list, node_detach) { struct int_list arr[3]; init_list_arr(arr, ARR_SIZE(arr), 0); struct list_node *n = list_node_detach(&arr[0].list); cr_assert_eq(n, &arr[0].list); cr_assert_eq(n->next, n); cr_assert_eq(n->prev, n); assert_list(arr + 1, ARR_SIZE(arr) - 1, 1); } Test(list, node_detach_back) { struct int_list arr[3]; init_list_arr(arr, ARR_SIZE(arr), 0); struct list_node *n = list_node_detach(&arr[2].list); cr_assert_eq(n, &arr[2].list); cr_assert_eq(n->next, n); cr_assert_eq(n->prev, n); assert_list(arr, ARR_SIZE(arr) - 1, 0); } Test(list, node_safe_detach_null) { cr_assert_null(list_node_safe_detach(NULL)); } Test(list, node_safe_detach_null_pointed) { struct list_node *n = NULL; cr_assert_null(list_node_safe_detach(&n)); } Test(list, node_safe_detach_one) { struct int_list l = { 0, { &l.list, &l.list } }; struct list_node *n = &l.list; cr_assert_eq(list_node_safe_detach(&n), &l.list); cr_assert_null(n); } Test(list, node_safe_detach) { struct int_list arr[3]; init_list_arr(arr, ARR_SIZE(arr), 0); struct list_node *n = &arr[0].list; cr_assert_eq(list_node_safe_detach(&n), &arr[0].list); cr_assert_eq(n, &arr[1].list); assert_list(arr + 1, ARR_SIZE(arr) - 1, 1); } Test(list, pop_front_null) { cr_assert_null(list_pop_front(NULL)); struct list l = { NULL }; cr_assert_null(list_pop_front(&l)); } Test(list, pop_front_one) { struct int_list list = { 1, { &list.list, &list.list } }; struct list l = { &list.list }; cr_assert_eq(list_pop_front(&l), &list.list); cr_assert_null(l.head); } Test(list, pop_front) { struct int_list arr[5]; init_list_arr(arr, ARR_SIZE(arr), 0); struct list l = { &arr[0].list }; cr_assert_eq(list_pop_front(&l), &arr[0].list); assert_list(arr + 1, ARR_SIZE(arr) - 1, 1); } Test(list, pop_back_null) { cr_assert_null(list_pop_front(NULL)); struct list l = { NULL }; cr_assert_null(list_pop_front(&l)); } Test(list, pop_back_one) { struct int_list list = { 1, { &list.list, &list.list } }; struct list l = { &list.list }; cr_assert_eq(list_pop_back(&l), &list.list); cr_assert_null(l.head); } Test(list, pop_back) { struct int_list arr[5]; init_list_arr(arr, ARR_SIZE(arr), 0); struct list l = { &arr[0].list }; cr_assert_eq(list_pop_back(&l), &arr[ARR_SIZE(arr) - 1].list); assert_list(arr, ARR_SIZE(arr) - 1, 0); } Test(list, length_null) { cr_assert_eq(list_length(NULL), 0); } Test(list, length_one) { struct int_list l = { 0, { &l.list, &l.list } }; cr_assert_eq(list_length(&(struct list){ &l.list }), 1); } Test(list, length) { struct int_list arr[3]; init_list_arr(arr, ARR_SIZE(arr), 0); cr_assert_eq(list_length(&(struct list) { &arr[0].list }), ARR_SIZE(arr)); } Test(list, node_concat_null) { list_node_concat(NULL, NULL); struct int_list l = { 0, {&l.list, &l.list, } }; list_node_concat(&l.list, NULL); list_node_concat(NULL, &l.list); } Test(list, node_concat_one) { const size_t n = 1; struct int_list arr[n * 2]; init_list_arr(arr, n * 2 - n, 0); init_list_arr(arr + n, n * 2 - n, n); list_node_concat(&arr[0].list, &arr[n].list); assert_list(arr, n * 2, 0); } Test(list, node_concat) { const size_t n = 3; struct int_list arr[n * 2]; init_list_arr(arr, n * 2 - n, 0); init_list_arr(arr + n, n * 2 - n, n); list_node_concat(&arr[0].list, &arr[n].list); assert_list(arr, n * 2, 0); } static int int_list_cmp(const struct list_node *lhs, const struct list_node *rhs, void *cookie) { struct int_list *l = CONTAINER_OF(struct int_list, list, lhs); struct int_list *r = CONTAINER_OF(struct int_list, list, rhs); size_t *count = cookie; ++*count; if (l->val < r->val) return -1; return (l->val > r->val); } Test(list, insert_sorted_null) { list_insert_sorted(NULL, NULL, int_list_cmp, NULL); struct list l = { (void *)0x42 }; list_insert_sorted(&l, NULL, int_list_cmp, NULL); list_insert_sorted(NULL, l.head, int_list_cmp, NULL); } Test(list, insert_sorted_empty) { struct int_list list = { 0, {NULL, NULL } }; struct list l = { NULL }; list_insert_sorted(&l, &list.list, int_list_cmp, NULL); cr_assert_eq(l.head, &list.list); cr_assert_eq(list.list.next, &list.list); cr_assert_eq(list.list.prev, &list.list); } Test(list, insert_sorted_one_before) { struct int_list arr[5] = { { 1, { NULL, NULL } }, }; init_list_arr(arr + 1, ARR_SIZE(arr) - 1, 1); struct list l = { &arr[1].list }; size_t count = 0; list_insert_sorted(&l, &arr[0].list, int_list_cmp, &count); assert_list(arr, ARR_SIZE(arr), 0); cr_assert_eq(count, 1); cr_assert_eq(l.head, &arr[0].list); } Test(list, insert_sorted_one_after) { struct int_list arr[5]; init_list_arr(arr, ARR_SIZE(arr) - 1, 0); arr[ARR_SIZE(arr) - 1].val = ARR_SIZE(arr); struct list l = { &arr[0].list }; size_t count = 0; list_insert_sorted(&l, &arr[ARR_SIZE(arr) - 1].list, int_list_cmp, &count); assert_list(arr, ARR_SIZE(arr), 0); cr_assert_eq(count, ARR_SIZE(arr) - 1); } Test(list, sort_null) { size_t count = 0; list_sort(NULL, int_list_cmp, &count); cr_assert_eq(count, 0); } Test(list, sort_one) { struct int_list list = { 0, { &list.list, &list.list } }; struct list l = { &list.list }; size_t count = 0; list_sort(&l, int_list_cmp, &count); cr_assert_eq(count, 0); } Test(list, sort_sorted) { struct int_list arr[5]; init_list_arr(arr, ARR_SIZE(arr), 0); struct list l = { &arr[0].list }; size_t count = 0; list_sort(&l, int_list_cmp, &count); cr_assert_eq(l.head, &arr[0].list); assert_list(arr, ARR_SIZE(arr), 0); cr_assert_eq(count, ARR_SIZE(arr) * (ARR_SIZE(arr) - 1) / 2); } Test(list, sort_inverted) { struct int_list arr[5] = { { 1, { &arr[4].list, &arr[1].list } }, { 2, { &arr[0].list, &arr[2].list } }, { 3, { &arr[1].list, &arr[3].list } }, { 4, { &arr[2].list, &arr[4].list } }, { 5, { &arr[3].list, &arr[0].list } }, }; struct list l = { &arr[ARR_SIZE(arr) - 1].list }; size_t count = 0; list_sort(&l, int_list_cmp, &count); cr_assert_eq(l.head, &arr[0].list); assert_list(arr, ARR_SIZE(arr), 0); } Test(list, merge_sorted_null) { list_merge_sorted(NULL, NULL, int_list_cmp, NULL); struct list l = { (void *)0x42 }; list_merge_sorted(&l, NULL, int_list_cmp, NULL); list_merge_sorted(NULL, &l, int_list_cmp, NULL); } Test(list, merge_sorted) { struct int_list arr[5] = { { 1, { &arr[2].list, &arr[4].list } }, { 2, { &arr[3].list, &arr[3].list } }, { 3, { &arr[4].list, &arr[0].list } }, { 4, { &arr[1].list, &arr[1].list } }, { 5, { &arr[0].list, &arr[2].list } }, }; struct list odd = { &arr[0].list }; struct list even = { &arr[1].list }; size_t count = 0; list_merge_sorted(&odd, &even, int_list_cmp, &count); assert_list(arr, ARR_SIZE(arr), 0); cr_assert_eq(odd.head, &arr[0].list); cr_assert_null(even.head); } Test(list, merge_sorted_alternate) { struct int_list arr[5] = { { 1, { &arr[2].list, &arr[4].list } }, { 2, { &arr[3].list, &arr[3].list } }, { 3, { &arr[4].list, &arr[0].list } }, { 4, { &arr[1].list, &arr[1].list } }, { 5, { &arr[0].list, &arr[2].list } }, }; struct list odd = { &arr[0].list }; struct list even = { &arr[1].list }; size_t count = 0; list_merge_sorted(&even, &odd, int_list_cmp, &count); assert_list(arr, ARR_SIZE(arr), 0); cr_assert_eq(even.head, &arr[0].list); cr_assert_null(odd.head); } static void int_list_map(struct list_node *n, void *cookie) { size_t *count = cookie; struct int_list *node = CONTAINER_OF(struct int_list, list, n); node->val = ++*count; } Test(list, map_null) { size_t count = 0; list_map(NULL, int_list_map, &count); cr_assert_eq(count, 0); struct list l = { NULL }; list_map(&l, int_list_map, &count); cr_assert_eq(count, 0); } Test(list, map) { struct int_list arr[5] = { { 0, { &arr[1].list, &arr[4].list } }, { 0, { &arr[2].list, &arr[0].list } }, { 0, { &arr[3].list, &arr[1].list } }, { 0, { &arr[4].list, &arr[2].list } }, { 0, { &arr[0].list, &arr[3].list } }, }; struct list l = { &arr[0].list }; size_t count = 0; list_map(&l, int_list_map, &count); cr_assert_eq(count, ARR_SIZE(arr)); assert_list(arr, ARR_SIZE(arr), 0); } static bool int_list_is_even(struct list_node *n, void *cookie) { size_t *count = cookie; ++*count; struct int_list *node = CONTAINER_OF(struct int_list, list, n); return node->val % 2 == 0; } Test(list, filter_null) { size_t count = 0; list_filter(NULL, NULL, int_list_is_even, &count); cr_assert_eq(count, 0); struct list l = { (void *)0x42 }; list_filter(&l, NULL, int_list_is_even, &count); cr_assert_eq(count, 0); list_filter(NULL, &l, int_list_is_even, &count); cr_assert_eq(count, 0); l.head = NULL; list_filter(&l, &l, int_list_is_even, &count); cr_assert_eq(count, 0); } Test(list, filter) { struct int_list arr[5]; init_list_arr(arr, ARR_SIZE(arr), 0); struct list l = { &arr[0].list }; struct list res = { NULL }; size_t count = 0; list_filter(&res, &l, int_list_is_even, &count); cr_assert_eq(count, ARR_SIZE(arr)); size_t count_even = 0; LIST_FOREACH_ENTRY(const struct int_list, list, res, n) { cr_assert_eq(n->val, ++count_even * 2); } size_t count_odd = 0; LIST_FOREACH_ENTRY(const struct int_list, list, l, n) { cr_assert_eq(n->val, ++count_odd * 2 - 1); } cr_assert_eq(count_even + count_odd, ARR_SIZE(arr)); }