xref: /linux/lib/test_list_sort.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2ebd09577SDaniel Latypov #include <kunit/test.h>
3e327fd7cSGeert Uytterhoeven 
4e327fd7cSGeert Uytterhoeven #include <linux/kernel.h>
5e327fd7cSGeert Uytterhoeven #include <linux/list_sort.h>
6e327fd7cSGeert Uytterhoeven #include <linux/list.h>
7e327fd7cSGeert Uytterhoeven #include <linux/module.h>
8e327fd7cSGeert Uytterhoeven #include <linux/printk.h>
9e327fd7cSGeert Uytterhoeven #include <linux/slab.h>
10e327fd7cSGeert Uytterhoeven #include <linux/random.h>
11e327fd7cSGeert Uytterhoeven 
12e327fd7cSGeert Uytterhoeven /*
13e327fd7cSGeert Uytterhoeven  * The pattern of set bits in the list length determines which cases
14e327fd7cSGeert Uytterhoeven  * are hit in list_sort().
15e327fd7cSGeert Uytterhoeven  */
16e327fd7cSGeert Uytterhoeven #define TEST_LIST_LEN (512+128+2) /* not including head */
17e327fd7cSGeert Uytterhoeven 
18e327fd7cSGeert Uytterhoeven #define TEST_POISON1 0xDEADBEEF
19e327fd7cSGeert Uytterhoeven #define TEST_POISON2 0xA324354C
20e327fd7cSGeert Uytterhoeven 
21e327fd7cSGeert Uytterhoeven struct debug_el {
22e327fd7cSGeert Uytterhoeven 	unsigned int poison1;
23e327fd7cSGeert Uytterhoeven 	struct list_head list;
24e327fd7cSGeert Uytterhoeven 	unsigned int poison2;
25e327fd7cSGeert Uytterhoeven 	int value;
26ebd09577SDaniel Latypov 	unsigned int serial;
27e327fd7cSGeert Uytterhoeven };
28e327fd7cSGeert Uytterhoeven 
check(struct kunit * test,struct debug_el * ela,struct debug_el * elb)29ebd09577SDaniel Latypov static void check(struct kunit *test, struct debug_el *ela, struct debug_el *elb)
30e327fd7cSGeert Uytterhoeven {
31ebd09577SDaniel Latypov 	struct debug_el **elts = test->priv;
32ebd09577SDaniel Latypov 
33ebd09577SDaniel Latypov 	KUNIT_EXPECT_LT_MSG(test, ela->serial, (unsigned int)TEST_LIST_LEN, "incorrect serial");
34ebd09577SDaniel Latypov 	KUNIT_EXPECT_LT_MSG(test, elb->serial, (unsigned int)TEST_LIST_LEN, "incorrect serial");
35ebd09577SDaniel Latypov 
36ebd09577SDaniel Latypov 	KUNIT_EXPECT_PTR_EQ_MSG(test, elts[ela->serial], ela, "phantom element");
37ebd09577SDaniel Latypov 	KUNIT_EXPECT_PTR_EQ_MSG(test, elts[elb->serial], elb, "phantom element");
38ebd09577SDaniel Latypov 
39ebd09577SDaniel Latypov 	KUNIT_EXPECT_EQ_MSG(test, ela->poison1, TEST_POISON1, "bad poison");
40ebd09577SDaniel Latypov 	KUNIT_EXPECT_EQ_MSG(test, ela->poison2, TEST_POISON2, "bad poison");
41ebd09577SDaniel Latypov 
42ebd09577SDaniel Latypov 	KUNIT_EXPECT_EQ_MSG(test, elb->poison1, TEST_POISON1, "bad poison");
43ebd09577SDaniel Latypov 	KUNIT_EXPECT_EQ_MSG(test, elb->poison2, TEST_POISON2, "bad poison");
44e327fd7cSGeert Uytterhoeven }
45e327fd7cSGeert Uytterhoeven 
46ebd09577SDaniel Latypov /* `priv` is the test pointer so check() can fail the test if the list is invalid. */
cmp(void * priv,const struct list_head * a,const struct list_head * b)47ebd09577SDaniel Latypov static int cmp(void *priv, const struct list_head *a, const struct list_head *b)
48e327fd7cSGeert Uytterhoeven {
49e327fd7cSGeert Uytterhoeven 	struct debug_el *ela, *elb;
50e327fd7cSGeert Uytterhoeven 
51e327fd7cSGeert Uytterhoeven 	ela = container_of(a, struct debug_el, list);
52e327fd7cSGeert Uytterhoeven 	elb = container_of(b, struct debug_el, list);
53e327fd7cSGeert Uytterhoeven 
54ebd09577SDaniel Latypov 	check(priv, ela, elb);
55e327fd7cSGeert Uytterhoeven 	return ela->value - elb->value;
56e327fd7cSGeert Uytterhoeven }
57e327fd7cSGeert Uytterhoeven 
list_sort_test(struct kunit * test)58ebd09577SDaniel Latypov static void list_sort_test(struct kunit *test)
59e327fd7cSGeert Uytterhoeven {
60ebd09577SDaniel Latypov 	int i, count = 1;
61ebd09577SDaniel Latypov 	struct debug_el *el, **elts;
62e327fd7cSGeert Uytterhoeven 	struct list_head *cur;
63e327fd7cSGeert Uytterhoeven 	LIST_HEAD(head);
64e327fd7cSGeert Uytterhoeven 
65ebd09577SDaniel Latypov 	elts = kunit_kcalloc(test, TEST_LIST_LEN, sizeof(*elts), GFP_KERNEL);
66ebd09577SDaniel Latypov 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, elts);
67ebd09577SDaniel Latypov 	test->priv = elts;
68e327fd7cSGeert Uytterhoeven 
69e327fd7cSGeert Uytterhoeven 	for (i = 0; i < TEST_LIST_LEN; i++) {
70ebd09577SDaniel Latypov 		el = kunit_kmalloc(test, sizeof(*el), GFP_KERNEL);
71ebd09577SDaniel Latypov 		KUNIT_ASSERT_NOT_ERR_OR_NULL(test, el);
72dc2bf000SMarkus Elfring 
73e327fd7cSGeert Uytterhoeven 		 /* force some equivalencies */
748032bf12SJason A. Donenfeld 		el->value = get_random_u32_below(TEST_LIST_LEN / 3);
75e327fd7cSGeert Uytterhoeven 		el->serial = i;
76e327fd7cSGeert Uytterhoeven 		el->poison1 = TEST_POISON1;
77e327fd7cSGeert Uytterhoeven 		el->poison2 = TEST_POISON2;
78e327fd7cSGeert Uytterhoeven 		elts[i] = el;
79e327fd7cSGeert Uytterhoeven 		list_add_tail(&el->list, &head);
80e327fd7cSGeert Uytterhoeven 	}
81e327fd7cSGeert Uytterhoeven 
82ebd09577SDaniel Latypov 	list_sort(test, &head, cmp);
83e327fd7cSGeert Uytterhoeven 
84e327fd7cSGeert Uytterhoeven 	for (cur = head.next; cur->next != &head; cur = cur->next) {
85e327fd7cSGeert Uytterhoeven 		struct debug_el *el1;
86e327fd7cSGeert Uytterhoeven 		int cmp_result;
87e327fd7cSGeert Uytterhoeven 
88ebd09577SDaniel Latypov 		KUNIT_ASSERT_PTR_EQ_MSG(test, cur->next->prev, cur,
89ebd09577SDaniel Latypov 					"list is corrupted");
90e327fd7cSGeert Uytterhoeven 
91ebd09577SDaniel Latypov 		cmp_result = cmp(test, cur, cur->next);
92ebd09577SDaniel Latypov 		KUNIT_ASSERT_LE_MSG(test, cmp_result, 0, "list is not sorted");
93e327fd7cSGeert Uytterhoeven 
94e327fd7cSGeert Uytterhoeven 		el = container_of(cur, struct debug_el, list);
95e327fd7cSGeert Uytterhoeven 		el1 = container_of(cur->next, struct debug_el, list);
96ebd09577SDaniel Latypov 		if (cmp_result == 0) {
97ebd09577SDaniel Latypov 			KUNIT_ASSERT_LE_MSG(test, el->serial, el1->serial,
98ebd09577SDaniel Latypov 					    "order of equivalent elements not preserved");
99e327fd7cSGeert Uytterhoeven 		}
100e327fd7cSGeert Uytterhoeven 
101ebd09577SDaniel Latypov 		check(test, el, el1);
102e327fd7cSGeert Uytterhoeven 		count++;
103e327fd7cSGeert Uytterhoeven 	}
104ebd09577SDaniel Latypov 	KUNIT_EXPECT_PTR_EQ_MSG(test, head.prev, cur, "list is corrupted");
105ebd09577SDaniel Latypov 
106ebd09577SDaniel Latypov 	KUNIT_EXPECT_EQ_MSG(test, count, TEST_LIST_LEN,
107ebd09577SDaniel Latypov 			    "list length changed after sorting!");
108e327fd7cSGeert Uytterhoeven }
109e327fd7cSGeert Uytterhoeven 
110ebd09577SDaniel Latypov static struct kunit_case list_sort_cases[] = {
111ebd09577SDaniel Latypov 	KUNIT_CASE(list_sort_test),
112ebd09577SDaniel Latypov 	{}
113ebd09577SDaniel Latypov };
114e327fd7cSGeert Uytterhoeven 
115ebd09577SDaniel Latypov static struct kunit_suite list_sort_suite = {
116ebd09577SDaniel Latypov 	.name = "list_sort",
117ebd09577SDaniel Latypov 	.test_cases = list_sort_cases,
118ebd09577SDaniel Latypov };
119e327fd7cSGeert Uytterhoeven 
120ebd09577SDaniel Latypov kunit_test_suites(&list_sort_suite);
121ebd09577SDaniel Latypov 
122*30347491SJeff Johnson MODULE_DESCRIPTION("list_sort() KUnit test suite");
123e327fd7cSGeert Uytterhoeven MODULE_LICENSE("GPL");
124