/* * Copyright © 2025 Imagination Technologies Ltd. * * SPDX-License-Identifier: MIT */ #include #include "util/macros.h" #include "util/list.h" struct test_node { struct list_head link; }; /* node count must be even or some tests may try deleting the head */ #define NODE_COUNT (8) struct test_ctx { struct list_head list; struct test_node nodes[NODE_COUNT]; }; static void init_test_ctx(struct test_ctx *ctx) { list_inithead(&ctx->list); for (unsigned i = 0; i < ARRAY_SIZE(ctx->nodes); i++) { list_addtail(&ctx->nodes[i].link, &ctx->list); } } #define LIST_LAST_EQ_TEST(name, iterator, node, stmt, index) \ TEST(list, name) { \ struct test_ctx ctx = {}; \ init_test_ctx(&ctx); \ struct test_node *__last_node = NULL; \ iterator (struct test_node, node, &ctx.list, link) { \ __last_node = node; \ stmt; \ } \ EXPECT_EQ(__last_node, &ctx.nodes[index]); \ } #define LIST_DEATH_TEST(name, iterator, node, stmt, msg) \ TEST(list, name) { \ struct test_ctx ctx = {}; \ init_test_ctx(&ctx); \ EXPECT_DEATH({ \ iterator (struct test_node, node, &ctx.list, link) { \ stmt; \ } \ }, msg); \ } LIST_LAST_EQ_TEST(del_node_safe, list_for_each_entry_safe, node, { list_del(&node->link); }, NODE_COUNT - 1) LIST_LAST_EQ_TEST(delinit_node_safe, list_for_each_entry_safe, node, { list_delinit(&node->link); }, NODE_COUNT - 1) LIST_LAST_EQ_TEST(del_next, list_for_each_entry, node, { list_del(node->link.next); }, NODE_COUNT - 2) LIST_LAST_EQ_TEST(delinit_next, list_for_each_entry, node, { list_delinit(node->link.next); }, NODE_COUNT - 2) LIST_LAST_EQ_TEST(del_node_safe_rev, list_for_each_entry_safe_rev, node, { list_del(&node->link); }, 0) LIST_LAST_EQ_TEST(delinit_node_safe_rev, list_for_each_entry_safe_rev, node, { list_delinit(&node->link); }, 0) LIST_LAST_EQ_TEST(del_prev_rev, list_for_each_entry_rev, node, { list_del(node->link.prev); }, 1) LIST_LAST_EQ_TEST(delinit_prev_rev, list_for_each_entry_rev, node, { list_delinit(node->link.prev); }, 1) #ifndef NDEBUG LIST_DEATH_TEST(del_node, list_for_each_entry, node, { list_del(&node->link); }, "use _safe iterator") LIST_DEATH_TEST(delinit_node, list_for_each_entry, node, { list_delinit(&node->link); }, "use _safe iterator") LIST_DEATH_TEST(del_next_safe, list_for_each_entry_safe, node, { list_del(node->link.next); }, "use non _safe iterator") LIST_DEATH_TEST(delinit_next_safe, list_for_each_entry_safe, node, { list_delinit(node->link.next); }, "use non _safe iterator") LIST_DEATH_TEST(del_node_rev, list_for_each_entry_rev, node, { list_del(&node->link); }, "use _safe iterator") LIST_DEATH_TEST(delinit_node_rev, list_for_each_entry_rev, node, { list_delinit(&node->link); }, "use _safe iterator") LIST_DEATH_TEST(del_prev_safe_rev, list_for_each_entry_safe_rev, node, { list_del(node->link.prev); }, "use non _safe iterator") LIST_DEATH_TEST(delinit_prev_safe_rev, list_for_each_entry_safe_rev, node, { list_delinit(node->link.prev); }, "use non _safe iterator") #endif