1 /*
2  * Copyright (c) 2016 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/ztest.h>
8 #include <zephyr/sys/slist.h>
9 
10 static sys_slist_t test_list;
11 static sys_slist_t append_list;
12 
13 struct container_node {
14 	sys_snode_t node;
15 	int unused;
16 };
17 
18 static struct container_node test_node_1;
19 static struct container_node test_node_2;
20 static struct container_node test_node_3;
21 static struct container_node test_node_4;
22 
verify_emptyness(sys_slist_t * list)23 static inline bool verify_emptyness(sys_slist_t *list)
24 {
25 	sys_snode_t *node;
26 	sys_snode_t *s_node;
27 	struct container_node *cnode;
28 	struct container_node *s_cnode;
29 	int count;
30 
31 	if (!sys_slist_is_empty(list)) {
32 		return false;
33 	}
34 
35 	if (sys_slist_peek_head(list)) {
36 		return false;
37 	}
38 
39 	if (sys_slist_peek_tail(list)) {
40 		return false;
41 	}
42 
43 	if (sys_slist_len(list) != 0) {
44 		return false;
45 	}
46 
47 	count = 0;
48 	SYS_SLIST_FOR_EACH_NODE(list, node) {
49 		count++;
50 	}
51 
52 	if (count) {
53 		return false;
54 	}
55 
56 	SYS_SLIST_FOR_EACH_NODE_SAFE(list, node, s_node) {
57 		count++;
58 	}
59 
60 	if (count) {
61 		return false;
62 	}
63 
64 	count = 0;
65 	SYS_SLIST_FOR_EACH_CONTAINER(list, cnode, node) {
66 		count++;
67 	}
68 
69 	if (count) {
70 		return false;
71 	}
72 
73 	count = 0;
74 	SYS_SLIST_FOR_EACH_CONTAINER_SAFE(list, cnode, s_cnode, node) {
75 		count++;
76 	}
77 
78 	if (count) {
79 		return false;
80 	}
81 
82 	return true;
83 }
84 
verify_content_amount(sys_slist_t * list,int amount)85 static inline bool verify_content_amount(sys_slist_t *list, int amount)
86 {
87 	sys_snode_t *node;
88 	sys_snode_t *s_node;
89 	struct container_node *cnode;
90 	struct container_node *s_cnode;
91 	int count;
92 
93 	if (sys_slist_is_empty(list)) {
94 		return false;
95 	}
96 
97 	if (!sys_slist_peek_head(list)) {
98 		return false;
99 	}
100 
101 	if (!sys_slist_peek_tail(list)) {
102 		return false;
103 	}
104 
105 	if (sys_slist_len(list) != amount) {
106 		return false;
107 	}
108 
109 	count = 0;
110 	SYS_SLIST_FOR_EACH_NODE(list, node) {
111 		count++;
112 	}
113 
114 	if (count != amount) {
115 		return false;
116 	}
117 
118 	count = 0;
119 	SYS_SLIST_FOR_EACH_NODE_SAFE(list, node, s_node) {
120 		count++;
121 	}
122 
123 	if (count != amount) {
124 		return false;
125 	}
126 
127 	count = 0;
128 	SYS_SLIST_FOR_EACH_CONTAINER(list, cnode, node) {
129 		count++;
130 	}
131 
132 	if (count != amount) {
133 		return false;
134 	}
135 
136 	count = 0;
137 	SYS_SLIST_FOR_EACH_CONTAINER_SAFE(list, cnode, s_cnode, node) {
138 		count++;
139 	}
140 
141 	if (count != amount) {
142 		return false;
143 	}
144 
145 	return true;
146 }
147 
verify_tail_head(sys_slist_t * list,sys_snode_t * head,sys_snode_t * tail,bool same)148 static inline bool verify_tail_head(sys_slist_t *list,
149 				    sys_snode_t *head,
150 				    sys_snode_t *tail,
151 				    bool same)
152 {
153 	if (sys_slist_peek_head(list) != head) {
154 		return false;
155 	}
156 
157 	if (sys_slist_peek_tail(list) != tail) {
158 		return false;
159 	}
160 
161 	if (same) {
162 		if (sys_slist_peek_head(list) != sys_slist_peek_tail(list)) {
163 			return false;
164 		}
165 	} else {
166 		if (sys_slist_peek_head(list) == sys_slist_peek_tail(list)) {
167 			return false;
168 		}
169 	}
170 
171 	return true;
172 }
173 /**
174  * @addtogroup kernel_common_tests
175  * @{
176  */
177 
178 /**
179  * @brief Test singly linked list functionalities
180  *
181  * @details Test list initialization, append item to the list,
182  * find and remove item, prepend, append, remove list
183  *
184  * @see sys_slist_init(), sys_slist_append(),
185  * sys_slist_find_and_remove(), sys_slist_prepend(),
186  * sys_slist_remove(), sys_slist_get(), sys_slist_get_not_empty(),
187  * sys_slist_append_list(), sys_slist_merge_list(), sys_slist_find()
188  */
ZTEST(dlist_api,test_slist)189 ZTEST(dlist_api, test_slist)
190 {
191 	sys_slist_init(&test_list);
192 
193 	zassert_true((verify_emptyness(&test_list)),
194 		      "test_list should be empty");
195 
196 	/* Appending node 1 */
197 	sys_slist_append(&test_list, &test_node_1.node);
198 	zassert_true((verify_content_amount(&test_list, 1)),
199 		     "test_list has wrong content");
200 
201 	zassert_true((verify_tail_head(&test_list, &test_node_1.node,
202 				       &test_node_1.node, true)),
203 		     "test_list head/tail are wrong");
204 
205 	/* Find the node 1, previous node should be null */
206 	sys_snode_t *test_node_1_prev = &test_node_1.node;
207 
208 	zassert_true(sys_slist_find(&test_list, &test_node_1.node, &test_node_1_prev),
209 		     "test_list did not find node ");
210 	zassert_is_null(test_node_1_prev, "test_list previous node not null ");
211 
212 	/* Finding and removing node 1 */
213 	sys_slist_find_and_remove(&test_list, &test_node_1.node);
214 	zassert_true((verify_emptyness(&test_list)),
215 		     "test_list should be empty");
216 
217 	/* Prepending node 1 */
218 	sys_slist_prepend(&test_list, &test_node_1.node);
219 	zassert_true((verify_content_amount(&test_list, 1)),
220 		     "test_list has wrong content");
221 
222 	zassert_true((verify_tail_head(&test_list, &test_node_1.node,
223 				       &test_node_1.node, true)),
224 		     "test_list head/tail are wrong");
225 
226 	/* Removing node 1 */
227 	sys_slist_remove(&test_list, NULL, &test_node_1.node);
228 	zassert_true((verify_emptyness(&test_list)),
229 		     "test_list should be empty");
230 
231 	/* Appending node 1 */
232 	sys_slist_append(&test_list, &test_node_1.node);
233 	/* Prepending node 2 */
234 	sys_slist_prepend(&test_list, &test_node_2.node);
235 
236 	zassert_true((verify_content_amount(&test_list, 2)),
237 		     "test_list has wrong content");
238 
239 	zassert_true((verify_tail_head(&test_list, &test_node_2.node,
240 				       &test_node_1.node, false)),
241 		     "test_list head/tail are wrong");
242 
243 	/* Appending node 3 */
244 	sys_slist_append(&test_list, &test_node_3.node);
245 
246 	zassert_true((verify_content_amount(&test_list, 3)),
247 		     "test_list has wrong content");
248 
249 	zassert_true((verify_tail_head(&test_list, &test_node_2.node,
250 				       &test_node_3.node, false)),
251 		     "test_list head/tail are wrong");
252 
253 	zassert_true((sys_slist_peek_next(&test_node_2.node) ==
254 		      &test_node_1.node),
255 		     "test_list node links are wrong");
256 
257 	/* Inserting node 4 after node 2, peek with nocheck variant */
258 	sys_slist_insert(&test_list, &test_node_2.node, &test_node_4.node);
259 
260 	zassert_true((verify_tail_head(&test_list, &test_node_2.node,
261 				       &test_node_3.node, false)),
262 		     "test_list head/tail are wrong");
263 
264 	zassert_true((sys_slist_peek_next_no_check(&test_node_2.node) ==
265 		      &test_node_4.node),
266 		     "test_list node links are wrong");
267 
268 	/* Find the node 4 and get the previous node*/
269 	sys_snode_t *test_node_4_prev = NULL;
270 
271 	zassert_true(sys_slist_find(&test_list, &test_node_4.node, &test_node_4_prev),
272 		     "test_list did not find node");
273 	zassert_equal(&test_node_2.node, test_node_4_prev,
274 		     "test_list previous node wrong ");
275 
276 	/* Finding and removing node 1 */
277 	sys_slist_find_and_remove(&test_list, &test_node_1.node);
278 	zassert_true((verify_content_amount(&test_list, 3)),
279 		     "test_list has wrong content");
280 
281 	zassert_true((verify_tail_head(&test_list, &test_node_2.node,
282 				       &test_node_3.node, false)),
283 		     "test_list head/tail are wrong");
284 
285 	/* Removing node 3 */
286 	sys_slist_remove(&test_list, &test_node_4.node, &test_node_3.node);
287 	zassert_true((verify_content_amount(&test_list, 2)),
288 		     "test_list has wrong content");
289 
290 	zassert_true((verify_tail_head(&test_list, &test_node_2.node,
291 				       &test_node_4.node, false)),
292 		     "test_list head/tail are wrong");
293 
294 	/* Removing node 4 */
295 	sys_slist_remove(&test_list, &test_node_2.node, &test_node_4.node);
296 	zassert_true((verify_content_amount(&test_list, 1)),
297 		     "test_list has wrong content");
298 
299 	zassert_true((verify_tail_head(&test_list, &test_node_2.node,
300 				       &test_node_2.node, true)),
301 		     "test_list head/tail are wrong");
302 
303 	/* Removing node 2 */
304 	sys_slist_remove(&test_list, NULL, &test_node_2.node);
305 	zassert_true((verify_emptyness(&test_list)),
306 		     "test_list should be empty");
307 
308 	/* test iterator from a node */
309 	struct data_node {
310 		sys_snode_t node;
311 		int data;
312 	} data_node[6] = {
313 		{ .data = 0 },
314 		{ .data = 1 },
315 		{ .data = 2 },
316 		{ .data = 3 },
317 		{ .data = 4 },
318 		{ .data = 5 },
319 	};
320 	sys_snode_t *node = NULL;
321 	int ii;
322 
323 	sys_slist_init(&test_list);
324 
325 	for (ii = 0; ii < 6; ii++) {
326 		sys_slist_append(&test_list, &data_node[ii].node);
327 	}
328 
329 	ii = 0;
330 	SYS_SLIST_ITERATE_FROM_NODE(&test_list, node) {
331 		ii++;
332 		if (((struct data_node *)node)->data == 2) {
333 			break;
334 		}
335 	}
336 	zassert_equal(ii, 3, "");
337 
338 	ii = 0;
339 	SYS_SLIST_ITERATE_FROM_NODE(&test_list, node) {
340 		ii++;
341 		if (((struct data_node *)node)->data == 3) {
342 			break;
343 		}
344 	}
345 	zassert_equal(ii, 1, "");
346 
347 	ii = 0;
348 	SYS_SLIST_ITERATE_FROM_NODE(&test_list, node) {
349 		ii++;
350 	}
351 	zassert_equal(ii, 2, "");
352 
353 	/* test sys_slist_remove and sys_slist_append inside safe node iteration */
354 	sys_snode_t *s_node, *prev, *removed;
355 	sys_snode_t append;
356 
357 	removed = NULL;
358 	SYS_SLIST_FOR_EACH_NODE_SAFE(&test_list, node, s_node) {
359 		/* Remove first node under iteration */
360 		if (removed == NULL) {
361 			sys_slist_remove(&test_list, NULL, node);
362 			removed = node;
363 		}
364 	}
365 	zassert_not_null(removed);
366 	zassert_true((verify_content_amount(&test_list, 5)), "test_list has wrong content");
367 	sys_slist_prepend(&test_list, removed);
368 
369 	removed = NULL;
370 	SYS_SLIST_FOR_EACH_NODE_SAFE(&test_list, node, s_node) {
371 		/* Remove last node under iteration */
372 		if (node->next == NULL) {
373 			sys_slist_remove(&test_list, prev, node);
374 			removed = node;
375 		}
376 		prev = node;
377 	}
378 	zassert_not_null(removed);
379 	zassert_true((verify_content_amount(&test_list, 5)), "test_list has wrong content");
380 	sys_slist_append(&test_list, removed);
381 
382 	SYS_SLIST_FOR_EACH_NODE_SAFE(&test_list, node, s_node) {
383 		/* Append on first iteration */
384 		if (test_list.head == node) {
385 			sys_slist_append(&test_list, &append);
386 		}
387 	}
388 	zassert_true((verify_content_amount(&test_list, 7)), "test_list has wrong content");
389 	sys_slist_find_and_remove(&test_list, &append);
390 
391 	SYS_SLIST_FOR_EACH_NODE_SAFE(&test_list, node, s_node) {
392 		/* Append on last iteration */
393 		if (node->next == NULL) {
394 			sys_slist_append(&test_list, &append);
395 		}
396 	}
397 	zassert_true((verify_content_amount(&test_list, 7)), "test_list has wrong content");
398 	sys_slist_find_and_remove(&test_list, &append);
399 
400 	/* test sys_slist_remove and sys_slist_append inside safe container iteration */
401 	struct container_node *cnode, *s_cnode, *cprev, *cremoved;
402 	struct container_node cappend;
403 
404 	cremoved = NULL;
405 	SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&test_list, cnode, s_cnode, node) {
406 		/* Remove on first iteration */
407 		if (cremoved == NULL) {
408 			sys_slist_remove(&test_list, NULL, &cnode->node);
409 			cremoved = cnode;
410 		}
411 	}
412 	zassert_not_null(cremoved);
413 	zassert_true((verify_content_amount(&test_list, 5)), "test_list has wrong content");
414 	sys_slist_prepend(&test_list, &cremoved->node);
415 
416 	cremoved = NULL;
417 	SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&test_list, cnode, s_cnode, node) {
418 		/* Remove on last iteration */
419 		if (cnode->node.next == NULL) {
420 			sys_slist_remove(&test_list, &cprev->node, &cnode->node);
421 			cremoved = cnode;
422 		}
423 		cprev = cnode;
424 	}
425 	zassert_not_null(cremoved);
426 	zassert_true((verify_content_amount(&test_list, 5)), "test_list has wrong content");
427 	sys_slist_append(&test_list, &cremoved->node);
428 
429 	SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&test_list, cnode, s_cnode, node) {
430 		/* Append on first iteration */
431 		if (test_list.head == &cnode->node) {
432 			sys_slist_append(&test_list, &cappend.node);
433 		}
434 	}
435 	zassert_true((verify_content_amount(&test_list, 7)), "test_list has wrong content");
436 	sys_slist_find_and_remove(&test_list, &cappend.node);
437 
438 	SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&test_list, cnode, s_cnode, node) {
439 		/* Append on last iteration */
440 		if (cnode->node.next == NULL) {
441 			sys_slist_append(&test_list, &cappend.node);
442 		}
443 	}
444 	zassert_true((verify_content_amount(&test_list, 7)), "test_list has wrong content");
445 	sys_slist_find_and_remove(&test_list, &cappend.node);
446 
447 	/* test sys_slist_get_not_empty() and sys_slist_get() APIs */
448 	for (ii = 0; ii < 6; ii++) {
449 		node = sys_slist_get_not_empty(&test_list);
450 		zassert_equal(((struct data_node *)node)->data, ii, "");
451 	}
452 	for (ii = 0; ii < 6; ii++) {
453 		/* regenerate test_list since we just emptied it */
454 		sys_slist_append(&test_list, &data_node[ii].node);
455 	}
456 	for (ii = 0; ii < 6; ii++) {
457 		node = sys_slist_get(&test_list);
458 		zassert_equal(((struct data_node *)node)->data, ii, "");
459 	}
460 	node = sys_slist_get(&test_list);
461 	zassert_equal(node, NULL, "");
462 
463 	/* test sys_slist_append_list() */
464 	sys_slist_init(&append_list);
465 	struct data_node data_node_append[6] = {
466 		{ .data = 6 },
467 		{ .data = 7 },
468 		{ .data = 8 },
469 		{ .data = 9 },
470 		{ .data = 10 },
471 		{ .data = 11 },
472 	};
473 	for (ii = 0; ii < 6; ii++) {
474 		/* regenerate test_list, which we just emptied */
475 		sys_slist_append(&test_list, &data_node[ii].node);
476 		/* Build append_list so that the node pointers are correct */
477 		sys_slist_append(&append_list, &data_node_append[ii].node);
478 	}
479 	sys_slist_append_list(&test_list, &data_node_append[0].node,
480 			      &data_node_append[5].node);
481 	for (ii = 0; ii < 12; ii++) {
482 		node = sys_slist_get(&test_list);
483 		zassert_equal(((struct data_node *)node)->data, ii,
484 			      "expected %d got %d", ii,
485 			      ((struct data_node *)node)->data);
486 	}
487 
488 	/* test sys_slist_append_list with empty list */
489 	sys_slist_init(&test_list);
490 	sys_slist_init(&append_list);
491 	for (ii = 0; ii < 6; ii++) {
492 		/* regenerate test_list only */
493 		sys_slist_append(&test_list, &data_node[ii].node);
494 	}
495 	sys_slist_append_list(&test_list, append_list.head, append_list.tail);
496 	node = sys_slist_peek_tail(&test_list);
497 	zassert_equal(((struct data_node *)node)->data, data_node[5].data, "expected %d got %d",
498 		      data_node[5].data, ((struct data_node *)node)->data);
499 
500 	/* test sys_slist_merge_slist */
501 	sys_slist_init(&test_list);
502 	sys_slist_init(&append_list);
503 	for (ii = 0; ii < 6; ii++) {
504 		/* regenerate both lists */
505 		sys_slist_append(&test_list, &data_node[ii].node);
506 		sys_slist_append(&append_list, &data_node_append[ii].node);
507 	}
508 	sys_slist_merge_slist(&test_list, &append_list);
509 	for (ii = 0; ii < 12; ii++) {
510 		node = sys_slist_get(&test_list);
511 		zassert_equal(((struct data_node *)node)->data, ii,
512 			      "expected %d got %d", ii,
513 			      ((struct data_node *)node)->data);
514 	}
515 	zassert_true(sys_slist_is_empty(&append_list),
516 		     "merged list is not empty");
517 
518 	/* test sys_slist_merge_slist with empty list */
519 	sys_slist_init(&test_list);
520 	sys_slist_init(&append_list);
521 	for (ii = 0; ii < 6; ii++) {
522 		/* regenerate test_list only */
523 		sys_slist_append(&test_list, &data_node[ii].node);
524 	}
525 
526 	sys_slist_merge_slist(&test_list, &append_list);
527 	node = sys_slist_peek_tail(&test_list);
528 	zassert_equal(((struct data_node *)node)->data, data_node[5].data, "expected %d got %d",
529 		      data_node[5].data, ((struct data_node *)node)->data);
530 }
531 
532 /**
533  * @}
534  */
535