Add KUnit tests for list.h macros/functions that currently lack
test coverage but have non-trivial edge cases:

- list_next_entry_circular / list_prev_entry_circular: verify both
  normal traversal and the wraparound case where iteration crosses
  the list head boundary.

- list_prepare_entry: verify the NULL pos case, which is the primary
  use case for this macro -- it allows list_for_each_entry_continue()
  to start from the beginning of the list when no prior position
  exists.

- hlist_splice_init: verify that splicing one hlist onto another
  correctly chains the nodes and empties the source list.

Written with the assistance of Claude (Anthropic).

Signed-off-by: [email protected]
Co-developed-by: Claude (Anthropic)
---
 lib/tests/list-test.c | 115 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 115 insertions(+)

diff --git a/lib/tests/list-test.c b/lib/tests/list-test.c
index 6d9227a..9e0eec7 100644
--- a/lib/tests/list-test.c
+++ b/lib/tests/list-test.c
@@ -765,6 +765,83 @@ static void list_test_list_for_each_entry_reverse(struct 
kunit *test)
        KUNIT_EXPECT_EQ(test, i, -1);
 }
 
+static void list_test_list_next_entry_circular(struct kunit *test)
+{
+       struct list_test_struct entries[3], *cur;
+       LIST_HEAD(list);
+       int i;
+
+       for (i = 0; i < 3; ++i) {
+               entries[i].data = i;
+               list_add_tail(&entries[i].list, &list);
+       }
+
+       /* Normal advance */
+       cur = &entries[0];
+       cur = list_next_entry_circular(cur, &list, list);
+       KUNIT_EXPECT_PTR_EQ(test, cur, &entries[1]);
+
+       /* Wraparound: next from last entry should return first */
+       cur = &entries[2];
+       cur = list_next_entry_circular(cur, &list, list);
+       KUNIT_EXPECT_PTR_EQ(test, cur, &entries[0]);
+}
+
+static void list_test_list_prev_entry_circular(struct kunit *test)
+{
+       struct list_test_struct entries[3], *cur;
+       LIST_HEAD(list);
+       int i;
+
+       for (i = 0; i < 3; ++i) {
+               entries[i].data = i;
+               list_add_tail(&entries[i].list, &list);
+       }
+
+       /* Normal retreat */
+       cur = &entries[2];
+       cur = list_prev_entry_circular(cur, &list, list);
+       KUNIT_EXPECT_PTR_EQ(test, cur, &entries[1]);
+
+       /* Wraparound: prev from first entry should return last */
+       cur = &entries[0];
+       cur = list_prev_entry_circular(cur, &list, list);
+       KUNIT_EXPECT_PTR_EQ(test, cur, &entries[2]);
+}
+
+static void list_test_list_prepare_entry(struct kunit *test)
+{
+       struct list_test_struct entries[3], *cur;
+       LIST_HEAD(list);
+       int i;
+
+       for (i = 0; i < 3; ++i) {
+               entries[i].data = i;
+               list_add_tail(&entries[i].list, &list);
+       }
+
+       /* With a valid pos, prepare_entry returns it unchanged */
+       cur = &entries[1];
+       cur = list_prepare_entry(cur, &list, list);
+       KUNIT_EXPECT_PTR_EQ(test, cur, &entries[1]);
+
+       /*
+        * With NULL pos, prepare_entry returns the list head as an entry,
+        * so that a subsequent list_for_each_entry_continue() starts from
+        * the first real entry. This NULL case is the main reason the
+        * macro exists and is worth testing explicitly.
+        */
+       cur = NULL;
+       cur = list_prepare_entry(cur, &list, list);
+
+       i = 0;
+       list_for_each_entry_continue(cur, &list, list) {
+               KUNIT_EXPECT_EQ(test, cur->data, i);
+               i++;
+       }
+       KUNIT_EXPECT_EQ(test, i, 3);
+}
+
 static struct kunit_case list_test_cases[] = {
        KUNIT_CASE(list_test_list_init),
        KUNIT_CASE(list_test_list_add),
@@ -805,6 +882,9 @@ static struct kunit_case list_test_cases[] = {
        KUNIT_CASE(list_test_list_for_each_prev_safe),
        KUNIT_CASE(list_test_list_for_each_entry),
        KUNIT_CASE(list_test_list_for_each_entry_reverse),
+       KUNIT_CASE(list_test_list_next_entry_circular),
+       KUNIT_CASE(list_test_list_prev_entry_circular),
+       KUNIT_CASE(list_test_list_prepare_entry),
        {},
 };
 
@@ -1181,6 +1261,40 @@ static void hlist_test_for_each_entry_safe(struct kunit 
*test)
 }
 
 
+static void hlist_test_splice_init(struct kunit *test)
+{
+       struct hlist_node entries[4];
+       struct hlist_node *cur;
+       HLIST_HEAD(list1);
+       HLIST_HEAD(list2);
+       int count;
+
+       /* list1: entries[0] -> entries[1] */
+       hlist_add_head(&entries[0], &list1);
+       hlist_add_behind(&entries[1], &entries[0]);
+
+       /* list2: entries[2] -> entries[3] */
+       hlist_add_head(&entries[2], &list2);
+       hlist_add_behind(&entries[3], &entries[2]);
+
+       /*
+        * Splice list1 (up to and including entries[1]) onto the front
+        * of list2. list1 should be emptied.
+        */
+       hlist_splice_init(&list1, &entries[1], &list2);
+
+       KUNIT_EXPECT_TRUE(test, hlist_empty(&list1));
+
+       /* list2 should now be: entries[0] -> entries[1] -> entries[2] -> 
entries[3] */
+       KUNIT_EXPECT_PTR_EQ(test, list2.first, &entries[0]);
+       KUNIT_EXPECT_PTR_EQ(test, entries[1].next, &entries[2]);
+
+       count = 0;
+       hlist_for_each(cur, &list2)
+               count++;
+       KUNIT_EXPECT_EQ(test, count, 4);
+}
+
 static struct kunit_case hlist_test_cases[] = {
        KUNIT_CASE(hlist_test_init),
        KUNIT_CASE(hlist_test_unhashed),
@@ -1200,6 +1314,7 @@ static struct kunit_case hlist_test_cases[] = {
        KUNIT_CASE(hlist_test_for_each_entry_continue),
        KUNIT_CASE(hlist_test_for_each_entry_from),
        KUNIT_CASE(hlist_test_for_each_entry_safe),
+       KUNIT_CASE(hlist_test_splice_init),
        {},
 };
 
-- 
2.53.0

-- 
Rango
 [email protected]

Reply via email to