| /* |
| * Copyright (c) 2016 Intel Corporation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <zephyr/ztest.h> |
| #include <zephyr/sys/slist.h> |
| |
| static sys_slist_t test_list; |
| static sys_slist_t append_list; |
| |
| struct container_node { |
| sys_snode_t node; |
| int unused; |
| }; |
| |
| static struct container_node test_node_1; |
| static struct container_node test_node_2; |
| static struct container_node test_node_3; |
| static struct container_node test_node_4; |
| |
| static inline bool verify_emptyness(sys_slist_t *list) |
| { |
| sys_snode_t *node; |
| sys_snode_t *s_node; |
| struct container_node *cnode; |
| struct container_node *s_cnode; |
| int count; |
| |
| if (!sys_slist_is_empty(list)) { |
| return false; |
| } |
| |
| if (sys_slist_peek_head(list)) { |
| return false; |
| } |
| |
| if (sys_slist_peek_tail(list)) { |
| return false; |
| } |
| |
| if (sys_slist_len(list) != 0) { |
| return false; |
| } |
| |
| count = 0; |
| SYS_SLIST_FOR_EACH_NODE(list, node) { |
| count++; |
| } |
| |
| if (count) { |
| return false; |
| } |
| |
| SYS_SLIST_FOR_EACH_NODE_SAFE(list, node, s_node) { |
| count++; |
| } |
| |
| if (count) { |
| return false; |
| } |
| |
| count = 0; |
| SYS_SLIST_FOR_EACH_CONTAINER(list, cnode, node) { |
| count++; |
| } |
| |
| if (count) { |
| return false; |
| } |
| |
| count = 0; |
| SYS_SLIST_FOR_EACH_CONTAINER_SAFE(list, cnode, s_cnode, node) { |
| count++; |
| } |
| |
| if (count) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| static inline bool verify_content_amount(sys_slist_t *list, int amount) |
| { |
| sys_snode_t *node; |
| sys_snode_t *s_node; |
| struct container_node *cnode; |
| struct container_node *s_cnode; |
| int count; |
| |
| if (sys_slist_is_empty(list)) { |
| return false; |
| } |
| |
| if (!sys_slist_peek_head(list)) { |
| return false; |
| } |
| |
| if (!sys_slist_peek_tail(list)) { |
| return false; |
| } |
| |
| if (sys_slist_len(list) != amount) { |
| return false; |
| } |
| |
| count = 0; |
| SYS_SLIST_FOR_EACH_NODE(list, node) { |
| count++; |
| } |
| |
| if (count != amount) { |
| return false; |
| } |
| |
| count = 0; |
| SYS_SLIST_FOR_EACH_NODE_SAFE(list, node, s_node) { |
| count++; |
| } |
| |
| if (count != amount) { |
| return false; |
| } |
| |
| count = 0; |
| SYS_SLIST_FOR_EACH_CONTAINER(list, cnode, node) { |
| count++; |
| } |
| |
| if (count != amount) { |
| return false; |
| } |
| |
| count = 0; |
| SYS_SLIST_FOR_EACH_CONTAINER_SAFE(list, cnode, s_cnode, node) { |
| count++; |
| } |
| |
| if (count != amount) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| static inline bool verify_tail_head(sys_slist_t *list, |
| sys_snode_t *head, |
| sys_snode_t *tail, |
| bool same) |
| { |
| if (sys_slist_peek_head(list) != head) { |
| return false; |
| } |
| |
| if (sys_slist_peek_tail(list) != tail) { |
| return false; |
| } |
| |
| if (same) { |
| if (sys_slist_peek_head(list) != sys_slist_peek_tail(list)) { |
| return false; |
| } |
| } else { |
| if (sys_slist_peek_head(list) == sys_slist_peek_tail(list)) { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| /** |
| * @addtogroup kernel_common_tests |
| * @{ |
| */ |
| |
| /** |
| * @brief Test singly linked list functionalities |
| * |
| * @details Test list initialization, append item to the list, |
| * find and remove item, prepend, append, remove list |
| * |
| * @see sys_slist_init(), sys_slist_append(), |
| * sys_slist_find_and_remove(), sys_slist_prepend(), |
| * sys_slist_remove(), sys_slist_get(), sys_slist_get_not_empty(), |
| * sys_slist_append_list(), sys_slist_merge_list(), sys_slist_find() |
| */ |
| ZTEST(dlist_api, test_slist) |
| { |
| sys_slist_init(&test_list); |
| |
| zassert_true((verify_emptyness(&test_list)), |
| "test_list should be empty"); |
| |
| /* Appending node 1 */ |
| sys_slist_append(&test_list, &test_node_1.node); |
| zassert_true((verify_content_amount(&test_list, 1)), |
| "test_list has wrong content"); |
| |
| zassert_true((verify_tail_head(&test_list, &test_node_1.node, |
| &test_node_1.node, true)), |
| "test_list head/tail are wrong"); |
| |
| /* Find the node 1, previous node should be null */ |
| sys_snode_t *test_node_1_prev = &test_node_1.node; |
| |
| zassert_true(sys_slist_find(&test_list, &test_node_1.node, &test_node_1_prev), |
| "test_list did not find node "); |
| zassert_is_null(test_node_1_prev, "test_list previous node not null "); |
| |
| /* Finding and removing node 1 */ |
| sys_slist_find_and_remove(&test_list, &test_node_1.node); |
| zassert_true((verify_emptyness(&test_list)), |
| "test_list should be empty"); |
| |
| /* Prepending node 1 */ |
| sys_slist_prepend(&test_list, &test_node_1.node); |
| zassert_true((verify_content_amount(&test_list, 1)), |
| "test_list has wrong content"); |
| |
| zassert_true((verify_tail_head(&test_list, &test_node_1.node, |
| &test_node_1.node, true)), |
| "test_list head/tail are wrong"); |
| |
| /* Removing node 1 */ |
| sys_slist_remove(&test_list, NULL, &test_node_1.node); |
| zassert_true((verify_emptyness(&test_list)), |
| "test_list should be empty"); |
| |
| /* Appending node 1 */ |
| sys_slist_append(&test_list, &test_node_1.node); |
| /* Prepending node 2 */ |
| sys_slist_prepend(&test_list, &test_node_2.node); |
| |
| zassert_true((verify_content_amount(&test_list, 2)), |
| "test_list has wrong content"); |
| |
| zassert_true((verify_tail_head(&test_list, &test_node_2.node, |
| &test_node_1.node, false)), |
| "test_list head/tail are wrong"); |
| |
| /* Appending node 3 */ |
| sys_slist_append(&test_list, &test_node_3.node); |
| |
| zassert_true((verify_content_amount(&test_list, 3)), |
| "test_list has wrong content"); |
| |
| zassert_true((verify_tail_head(&test_list, &test_node_2.node, |
| &test_node_3.node, false)), |
| "test_list head/tail are wrong"); |
| |
| zassert_true((sys_slist_peek_next(&test_node_2.node) == |
| &test_node_1.node), |
| "test_list node links are wrong"); |
| |
| /* Inserting node 4 after node 2, peek with nocheck variant */ |
| sys_slist_insert(&test_list, &test_node_2.node, &test_node_4.node); |
| |
| zassert_true((verify_tail_head(&test_list, &test_node_2.node, |
| &test_node_3.node, false)), |
| "test_list head/tail are wrong"); |
| |
| zassert_true((sys_slist_peek_next_no_check(&test_node_2.node) == |
| &test_node_4.node), |
| "test_list node links are wrong"); |
| |
| /* Find the node 4 and get the previous node*/ |
| sys_snode_t *test_node_4_prev = NULL; |
| |
| zassert_true(sys_slist_find(&test_list, &test_node_4.node, &test_node_4_prev), |
| "test_list did not find node"); |
| zassert_equal(&test_node_2.node, test_node_4_prev, |
| "test_list previous node wrong "); |
| |
| /* Finding and removing node 1 */ |
| sys_slist_find_and_remove(&test_list, &test_node_1.node); |
| zassert_true((verify_content_amount(&test_list, 3)), |
| "test_list has wrong content"); |
| |
| zassert_true((verify_tail_head(&test_list, &test_node_2.node, |
| &test_node_3.node, false)), |
| "test_list head/tail are wrong"); |
| |
| /* Removing node 3 */ |
| sys_slist_remove(&test_list, &test_node_4.node, &test_node_3.node); |
| zassert_true((verify_content_amount(&test_list, 2)), |
| "test_list has wrong content"); |
| |
| zassert_true((verify_tail_head(&test_list, &test_node_2.node, |
| &test_node_4.node, false)), |
| "test_list head/tail are wrong"); |
| |
| /* Removing node 4 */ |
| sys_slist_remove(&test_list, &test_node_2.node, &test_node_4.node); |
| zassert_true((verify_content_amount(&test_list, 1)), |
| "test_list has wrong content"); |
| |
| zassert_true((verify_tail_head(&test_list, &test_node_2.node, |
| &test_node_2.node, true)), |
| "test_list head/tail are wrong"); |
| |
| /* Removing node 2 */ |
| sys_slist_remove(&test_list, NULL, &test_node_2.node); |
| zassert_true((verify_emptyness(&test_list)), |
| "test_list should be empty"); |
| |
| /* test iterator from a node */ |
| struct data_node { |
| sys_snode_t node; |
| int data; |
| } data_node[6] = { |
| { .data = 0 }, |
| { .data = 1 }, |
| { .data = 2 }, |
| { .data = 3 }, |
| { .data = 4 }, |
| { .data = 5 }, |
| }; |
| sys_snode_t *node = NULL; |
| int ii; |
| |
| sys_slist_init(&test_list); |
| |
| for (ii = 0; ii < 6; ii++) { |
| sys_slist_append(&test_list, &data_node[ii].node); |
| } |
| |
| ii = 0; |
| SYS_SLIST_ITERATE_FROM_NODE(&test_list, node) { |
| ii++; |
| if (((struct data_node *)node)->data == 2) { |
| break; |
| } |
| } |
| zassert_equal(ii, 3, ""); |
| |
| ii = 0; |
| SYS_SLIST_ITERATE_FROM_NODE(&test_list, node) { |
| ii++; |
| if (((struct data_node *)node)->data == 3) { |
| break; |
| } |
| } |
| zassert_equal(ii, 1, ""); |
| |
| ii = 0; |
| SYS_SLIST_ITERATE_FROM_NODE(&test_list, node) { |
| ii++; |
| } |
| zassert_equal(ii, 2, ""); |
| |
| /* test sys_slist_remove and sys_slist_append inside safe node iteration */ |
| sys_snode_t *s_node, *prev, *removed; |
| sys_snode_t append; |
| |
| removed = NULL; |
| SYS_SLIST_FOR_EACH_NODE_SAFE(&test_list, node, s_node) { |
| /* Remove first node under iteration */ |
| if (removed == NULL) { |
| sys_slist_remove(&test_list, NULL, node); |
| removed = node; |
| } |
| } |
| zassert_not_null(removed); |
| zassert_true((verify_content_amount(&test_list, 5)), "test_list has wrong content"); |
| sys_slist_prepend(&test_list, removed); |
| |
| removed = NULL; |
| SYS_SLIST_FOR_EACH_NODE_SAFE(&test_list, node, s_node) { |
| /* Remove last node under iteration */ |
| if (node->next == NULL) { |
| sys_slist_remove(&test_list, prev, node); |
| removed = node; |
| } |
| prev = node; |
| } |
| zassert_not_null(removed); |
| zassert_true((verify_content_amount(&test_list, 5)), "test_list has wrong content"); |
| sys_slist_append(&test_list, removed); |
| |
| SYS_SLIST_FOR_EACH_NODE_SAFE(&test_list, node, s_node) { |
| /* Append on first iteration */ |
| if (test_list.head == node) { |
| sys_slist_append(&test_list, &append); |
| } |
| } |
| zassert_true((verify_content_amount(&test_list, 7)), "test_list has wrong content"); |
| sys_slist_find_and_remove(&test_list, &append); |
| |
| SYS_SLIST_FOR_EACH_NODE_SAFE(&test_list, node, s_node) { |
| /* Append on last iteration */ |
| if (node->next == NULL) { |
| sys_slist_append(&test_list, &append); |
| } |
| } |
| zassert_true((verify_content_amount(&test_list, 7)), "test_list has wrong content"); |
| sys_slist_find_and_remove(&test_list, &append); |
| |
| /* test sys_slist_remove and sys_slist_append inside safe container iteration */ |
| struct container_node *cnode, *s_cnode, *cprev, *cremoved; |
| struct container_node cappend; |
| |
| cremoved = NULL; |
| SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&test_list, cnode, s_cnode, node) { |
| /* Remove on first iteration */ |
| if (cremoved == NULL) { |
| sys_slist_remove(&test_list, NULL, &cnode->node); |
| cremoved = cnode; |
| } |
| } |
| zassert_not_null(cremoved); |
| zassert_true((verify_content_amount(&test_list, 5)), "test_list has wrong content"); |
| sys_slist_prepend(&test_list, &cremoved->node); |
| |
| cremoved = NULL; |
| SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&test_list, cnode, s_cnode, node) { |
| /* Remove on last iteration */ |
| if (cnode->node.next == NULL) { |
| sys_slist_remove(&test_list, &cprev->node, &cnode->node); |
| cremoved = cnode; |
| } |
| cprev = cnode; |
| } |
| zassert_not_null(cremoved); |
| zassert_true((verify_content_amount(&test_list, 5)), "test_list has wrong content"); |
| sys_slist_append(&test_list, &cremoved->node); |
| |
| SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&test_list, cnode, s_cnode, node) { |
| /* Append on first iteration */ |
| if (test_list.head == &cnode->node) { |
| sys_slist_append(&test_list, &cappend.node); |
| } |
| } |
| zassert_true((verify_content_amount(&test_list, 7)), "test_list has wrong content"); |
| sys_slist_find_and_remove(&test_list, &cappend.node); |
| |
| SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&test_list, cnode, s_cnode, node) { |
| /* Append on last iteration */ |
| if (cnode->node.next == NULL) { |
| sys_slist_append(&test_list, &cappend.node); |
| } |
| } |
| zassert_true((verify_content_amount(&test_list, 7)), "test_list has wrong content"); |
| sys_slist_find_and_remove(&test_list, &cappend.node); |
| |
| /* test sys_slist_get_not_empty() and sys_slist_get() APIs */ |
| for (ii = 0; ii < 6; ii++) { |
| node = sys_slist_get_not_empty(&test_list); |
| zassert_equal(((struct data_node *)node)->data, ii, ""); |
| } |
| for (ii = 0; ii < 6; ii++) { |
| /* regenerate test_list since we just emptied it */ |
| sys_slist_append(&test_list, &data_node[ii].node); |
| } |
| for (ii = 0; ii < 6; ii++) { |
| node = sys_slist_get(&test_list); |
| zassert_equal(((struct data_node *)node)->data, ii, ""); |
| } |
| node = sys_slist_get(&test_list); |
| zassert_equal(node, NULL, ""); |
| |
| /* test sys_slist_append_list() */ |
| sys_slist_init(&append_list); |
| struct data_node data_node_append[6] = { |
| { .data = 6 }, |
| { .data = 7 }, |
| { .data = 8 }, |
| { .data = 9 }, |
| { .data = 10 }, |
| { .data = 11 }, |
| }; |
| for (ii = 0; ii < 6; ii++) { |
| /* regenerate test_list, which we just emptied */ |
| sys_slist_append(&test_list, &data_node[ii].node); |
| /* Build append_list so that the node pointers are correct */ |
| sys_slist_append(&append_list, &data_node_append[ii].node); |
| } |
| sys_slist_append_list(&test_list, &data_node_append[0].node, |
| &data_node_append[5].node); |
| for (ii = 0; ii < 12; ii++) { |
| node = sys_slist_get(&test_list); |
| zassert_equal(((struct data_node *)node)->data, ii, |
| "expected %d got %d", ii, |
| ((struct data_node *)node)->data); |
| } |
| |
| /* test sys_slist_append_list with empty list */ |
| sys_slist_init(&test_list); |
| sys_slist_init(&append_list); |
| for (ii = 0; ii < 6; ii++) { |
| /* regenerate test_list only */ |
| sys_slist_append(&test_list, &data_node[ii].node); |
| } |
| sys_slist_append_list(&test_list, append_list.head, append_list.tail); |
| node = sys_slist_peek_tail(&test_list); |
| zassert_equal(((struct data_node *)node)->data, data_node[5].data, "expected %d got %d", |
| data_node[5].data, ((struct data_node *)node)->data); |
| |
| /* test sys_slist_merge_slist */ |
| sys_slist_init(&test_list); |
| sys_slist_init(&append_list); |
| for (ii = 0; ii < 6; ii++) { |
| /* regenerate both lists */ |
| sys_slist_append(&test_list, &data_node[ii].node); |
| sys_slist_append(&append_list, &data_node_append[ii].node); |
| } |
| sys_slist_merge_slist(&test_list, &append_list); |
| for (ii = 0; ii < 12; ii++) { |
| node = sys_slist_get(&test_list); |
| zassert_equal(((struct data_node *)node)->data, ii, |
| "expected %d got %d", ii, |
| ((struct data_node *)node)->data); |
| } |
| zassert_true(sys_slist_is_empty(&append_list), |
| "merged list is not empty"); |
| |
| /* test sys_slist_merge_slist with empty list */ |
| sys_slist_init(&test_list); |
| sys_slist_init(&append_list); |
| for (ii = 0; ii < 6; ii++) { |
| /* regenerate test_list only */ |
| sys_slist_append(&test_list, &data_node[ii].node); |
| } |
| |
| sys_slist_merge_slist(&test_list, &append_list); |
| node = sys_slist_peek_tail(&test_list); |
| zassert_equal(((struct data_node *)node)->data, data_node[5].data, "expected %d got %d", |
| data_node[5].data, ((struct data_node *)node)->data); |
| } |
| |
| /** |
| * @} |
| */ |