blob: 76dbeea8d1a3bb3a7bac0fdf3a280049579e9c1b [file] [log] [blame]
/*
* 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);
}
/**
* @}
*/