1 // SPDX-License-Identifier: GPL-2.0
3 * KUnit test for the Kernel Hashtable structures.
5 * Copyright (C) 2022, Google LLC.
6 * Author: Rae Moar <rmoar@google.com>
8 #include <kunit/test.h>
10 #include <linux/hashtable.h>
12 struct hashtable_test_entry
{
15 struct hlist_node node
;
19 static void hashtable_test_hash_init(struct kunit
*test
)
21 /* Test the different ways of initialising a hashtable. */
22 DEFINE_HASHTABLE(hash1
, 2);
23 DECLARE_HASHTABLE(hash2
, 3);
25 /* When using DECLARE_HASHTABLE, must use hash_init to
26 * initialize the hashtable.
30 KUNIT_EXPECT_TRUE(test
, hash_empty(hash1
));
31 KUNIT_EXPECT_TRUE(test
, hash_empty(hash2
));
34 static void hashtable_test_hash_empty(struct kunit
*test
)
36 struct hashtable_test_entry a
;
37 DEFINE_HASHTABLE(hash
, 1);
39 KUNIT_EXPECT_TRUE(test
, hash_empty(hash
));
43 hash_add(hash
, &a
.node
, a
.key
);
45 /* Hashtable should no longer be empty. */
46 KUNIT_EXPECT_FALSE(test
, hash_empty(hash
));
49 static void hashtable_test_hash_hashed(struct kunit
*test
)
51 struct hashtable_test_entry a
, b
;
52 DEFINE_HASHTABLE(hash
, 4);
56 hash_add(hash
, &a
.node
, a
.key
);
59 hash_add(hash
, &b
.node
, b
.key
);
61 KUNIT_EXPECT_TRUE(test
, hash_hashed(&a
.node
));
62 KUNIT_EXPECT_TRUE(test
, hash_hashed(&b
.node
));
65 static void hashtable_test_hash_add(struct kunit
*test
)
67 struct hashtable_test_entry a
, b
, *x
;
69 DEFINE_HASHTABLE(hash
, 3);
74 hash_add(hash
, &a
.node
, a
.key
);
78 hash_add(hash
, &b
.node
, b
.key
);
80 hash_for_each(hash
, bkt
, x
, node
) {
83 KUNIT_EXPECT_EQ(test
, x
->data
, 13);
84 else if (x
->key
== b
.key
)
85 KUNIT_EXPECT_EQ(test
, x
->data
, 10);
87 KUNIT_FAIL(test
, "Unexpected key in hashtable.");
90 /* Both entries should have been visited exactly once. */
91 KUNIT_EXPECT_EQ(test
, a
.visited
, 1);
92 KUNIT_EXPECT_EQ(test
, b
.visited
, 1);
95 static void hashtable_test_hash_del(struct kunit
*test
)
97 struct hashtable_test_entry a
, b
, *x
;
98 DEFINE_HASHTABLE(hash
, 6);
102 hash_add(hash
, &a
.node
, a
.key
);
106 hash_add(hash
, &b
.node
, b
.key
);
109 hash_for_each_possible(hash
, x
, node
, b
.key
) {
111 KUNIT_EXPECT_NE(test
, x
->key
, b
.key
);
114 /* The deleted entry should not have been visited. */
115 KUNIT_EXPECT_EQ(test
, b
.visited
, 0);
119 /* The hashtable should be empty. */
120 KUNIT_EXPECT_TRUE(test
, hash_empty(hash
));
123 static void hashtable_test_hash_for_each(struct kunit
*test
)
125 struct hashtable_test_entry entries
[3];
126 struct hashtable_test_entry
*x
;
127 int bkt
, i
, j
, count
;
128 DEFINE_HASHTABLE(hash
, 3);
130 /* Add three entries to the hashtable. */
131 for (i
= 0; i
< 3; i
++) {
133 entries
[i
].data
= i
+ 10;
134 entries
[i
].visited
= 0;
135 hash_add(hash
, &entries
[i
].node
, entries
[i
].key
);
139 hash_for_each(hash
, bkt
, x
, node
) {
141 KUNIT_ASSERT_GE_MSG(test
, x
->key
, 0, "Unexpected key in hashtable.");
142 KUNIT_ASSERT_LT_MSG(test
, x
->key
, 3, "Unexpected key in hashtable.");
146 /* Should have visited each entry exactly once. */
147 KUNIT_EXPECT_EQ(test
, count
, 3);
148 for (j
= 0; j
< 3; j
++)
149 KUNIT_EXPECT_EQ(test
, entries
[j
].visited
, 1);
152 static void hashtable_test_hash_for_each_safe(struct kunit
*test
)
154 struct hashtable_test_entry entries
[3];
155 struct hashtable_test_entry
*x
;
156 struct hlist_node
*tmp
;
157 int bkt
, i
, j
, count
;
158 DEFINE_HASHTABLE(hash
, 3);
160 /* Add three entries to the hashtable. */
161 for (i
= 0; i
< 3; i
++) {
163 entries
[i
].data
= i
+ 10;
164 entries
[i
].visited
= 0;
165 hash_add(hash
, &entries
[i
].node
, entries
[i
].key
);
169 hash_for_each_safe(hash
, bkt
, tmp
, x
, node
) {
171 KUNIT_ASSERT_GE_MSG(test
, x
->key
, 0, "Unexpected key in hashtable.");
172 KUNIT_ASSERT_LT_MSG(test
, x
->key
, 3, "Unexpected key in hashtable.");
175 /* Delete entry during loop. */
179 /* Should have visited each entry exactly once. */
180 KUNIT_EXPECT_EQ(test
, count
, 3);
181 for (j
= 0; j
< 3; j
++)
182 KUNIT_EXPECT_EQ(test
, entries
[j
].visited
, 1);
185 static void hashtable_test_hash_for_each_possible(struct kunit
*test
)
187 struct hashtable_test_entry entries
[4];
188 struct hashtable_test_entry
*x
, *y
;
190 int bkt
, i
, j
, count
;
191 DEFINE_HASHTABLE(hash
, 5);
193 /* Add three entries with key = 0 to the hashtable. */
194 for (i
= 0; i
< 3; i
++) {
197 entries
[i
].visited
= 0;
198 hash_add(hash
, &entries
[i
].node
, entries
[i
].key
);
201 /* Add an entry with key = 1. */
204 entries
[3].visited
= 0;
205 hash_add(hash
, &entries
[3].node
, entries
[3].key
);
208 hash_for_each_possible(hash
, x
, node
, 0) {
210 KUNIT_ASSERT_GE_MSG(test
, x
->data
, 0, "Unexpected data in hashtable.");
211 KUNIT_ASSERT_LT_MSG(test
, x
->data
, 4, "Unexpected data in hashtable.");
215 /* Should have visited each entry with key = 0 exactly once. */
216 for (j
= 0; j
< 3; j
++)
217 KUNIT_EXPECT_EQ(test
, entries
[j
].visited
, 1);
219 /* Save the buckets for the different keys. */
220 hash_for_each(hash
, bkt
, y
, node
) {
221 KUNIT_ASSERT_GE_MSG(test
, y
->key
, 0, "Unexpected key in hashtable.");
222 KUNIT_ASSERT_LE_MSG(test
, y
->key
, 1, "Unexpected key in hashtable.");
223 buckets
[y
->key
] = bkt
;
226 /* If entry with key = 1 is in the same bucket as the entries with
227 * key = 0, check it was visited. Otherwise ensure that only three
228 * entries were visited.
230 if (buckets
[0] == buckets
[1]) {
231 KUNIT_EXPECT_EQ(test
, count
, 4);
232 KUNIT_EXPECT_EQ(test
, entries
[3].visited
, 1);
234 KUNIT_EXPECT_EQ(test
, count
, 3);
235 KUNIT_EXPECT_EQ(test
, entries
[3].visited
, 0);
239 static void hashtable_test_hash_for_each_possible_safe(struct kunit
*test
)
241 struct hashtable_test_entry entries
[4];
242 struct hashtable_test_entry
*x
, *y
;
243 struct hlist_node
*tmp
;
245 int bkt
, i
, j
, count
;
246 DEFINE_HASHTABLE(hash
, 5);
248 /* Add three entries with key = 0 to the hashtable. */
249 for (i
= 0; i
< 3; i
++) {
252 entries
[i
].visited
= 0;
253 hash_add(hash
, &entries
[i
].node
, entries
[i
].key
);
256 /* Add an entry with key = 1. */
259 entries
[3].visited
= 0;
260 hash_add(hash
, &entries
[3].node
, entries
[3].key
);
263 hash_for_each_possible_safe(hash
, x
, tmp
, node
, 0) {
265 KUNIT_ASSERT_GE_MSG(test
, x
->data
, 0, "Unexpected data in hashtable.");
266 KUNIT_ASSERT_LT_MSG(test
, x
->data
, 4, "Unexpected data in hashtable.");
269 /* Delete entry during loop. */
273 /* Should have visited each entry with key = 0 exactly once. */
274 for (j
= 0; j
< 3; j
++)
275 KUNIT_EXPECT_EQ(test
, entries
[j
].visited
, 1);
277 /* Save the buckets for the different keys. */
278 hash_for_each(hash
, bkt
, y
, node
) {
279 KUNIT_ASSERT_GE_MSG(test
, y
->key
, 0, "Unexpected key in hashtable.");
280 KUNIT_ASSERT_LE_MSG(test
, y
->key
, 1, "Unexpected key in hashtable.");
281 buckets
[y
->key
] = bkt
;
284 /* If entry with key = 1 is in the same bucket as the entries with
285 * key = 0, check it was visited. Otherwise ensure that only three
286 * entries were visited.
288 if (buckets
[0] == buckets
[1]) {
289 KUNIT_EXPECT_EQ(test
, count
, 4);
290 KUNIT_EXPECT_EQ(test
, entries
[3].visited
, 1);
292 KUNIT_EXPECT_EQ(test
, count
, 3);
293 KUNIT_EXPECT_EQ(test
, entries
[3].visited
, 0);
297 static struct kunit_case hashtable_test_cases
[] = {
298 KUNIT_CASE(hashtable_test_hash_init
),
299 KUNIT_CASE(hashtable_test_hash_empty
),
300 KUNIT_CASE(hashtable_test_hash_hashed
),
301 KUNIT_CASE(hashtable_test_hash_add
),
302 KUNIT_CASE(hashtable_test_hash_del
),
303 KUNIT_CASE(hashtable_test_hash_for_each
),
304 KUNIT_CASE(hashtable_test_hash_for_each_safe
),
305 KUNIT_CASE(hashtable_test_hash_for_each_possible
),
306 KUNIT_CASE(hashtable_test_hash_for_each_possible_safe
),
310 static struct kunit_suite hashtable_test_module
= {
312 .test_cases
= hashtable_test_cases
,
315 kunit_test_suites(&hashtable_test_module
);
317 MODULE_DESCRIPTION("KUnit test for the Kernel Hashtable structures");
318 MODULE_LICENSE("GPL");