1 /*
2  * Copyright (c) 2017 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/ztest.h>
8 #include <zephyr/sys/dlist.h>
9 
10 static sys_dlist_t test_list;
11 
12 struct container_node {
13 	sys_dnode_t node;
14 	int unused;
15 };
16 
17 static struct container_node test_node_1;
18 static struct container_node test_node_2;
19 static struct container_node test_node_3;
20 static struct container_node test_node_4;
21 
verify_emptyness(sys_dlist_t * list)22 static inline bool verify_emptyness(sys_dlist_t *list)
23 {
24 	sys_dnode_t *node;
25 	sys_dnode_t *s_node;
26 	struct container_node *cnode;
27 	struct container_node *s_cnode;
28 	int count;
29 
30 	if (!sys_dlist_is_empty(list)) {
31 		return false;
32 	}
33 
34 	if (sys_dlist_peek_head(list)) {
35 		return false;
36 	}
37 
38 	if (sys_dlist_peek_tail(list)) {
39 		return false;
40 	}
41 
42 	if (sys_dlist_len(list) != 0) {
43 		return false;
44 	}
45 
46 	count = 0;
47 	SYS_DLIST_FOR_EACH_NODE(list, node) {
48 		count++;
49 	}
50 
51 	if (count) {
52 		return false;
53 	}
54 
55 	SYS_DLIST_FOR_EACH_NODE_SAFE(list, node, s_node) {
56 		count++;
57 	}
58 
59 	if (count) {
60 		return false;
61 	}
62 
63 	count = 0;
64 	SYS_DLIST_FOR_EACH_CONTAINER(list, cnode, node) {
65 		count++;
66 	}
67 
68 	if (count) {
69 		return false;
70 	}
71 
72 	count = 0;
73 	SYS_DLIST_FOR_EACH_CONTAINER_SAFE(list, cnode, s_cnode, node) {
74 		count++;
75 	}
76 
77 	if (count) {
78 		return false;
79 	}
80 
81 	return true;
82 }
83 
verify_content_amount(sys_dlist_t * list,int amount)84 static inline bool verify_content_amount(sys_dlist_t *list, int amount)
85 {
86 	sys_dnode_t *node;
87 	sys_dnode_t *s_node;
88 	struct container_node *cnode;
89 	struct container_node *s_cnode;
90 	int count;
91 
92 	if (sys_dlist_is_empty(list)) {
93 		return false;
94 	}
95 
96 	if (!sys_dlist_peek_head(list)) {
97 		return false;
98 	}
99 
100 	if (!sys_dlist_peek_tail(list)) {
101 		return false;
102 	}
103 
104 	if (sys_dlist_len(list) != amount) {
105 		return false;
106 	}
107 
108 	count = 0;
109 	SYS_DLIST_FOR_EACH_NODE(list, node) {
110 		count++;
111 	}
112 
113 	if (count != amount) {
114 		return false;
115 	}
116 
117 	count = 0;
118 	SYS_DLIST_FOR_EACH_NODE_SAFE(list, node, s_node) {
119 		count++;
120 	}
121 
122 	if (count != amount) {
123 		return false;
124 	}
125 
126 	count = 0;
127 	SYS_DLIST_FOR_EACH_CONTAINER(list, cnode, node) {
128 		count++;
129 	}
130 
131 	if (count != amount) {
132 		return false;
133 	}
134 
135 	count = 0;
136 	SYS_DLIST_FOR_EACH_CONTAINER_SAFE(list, cnode, s_cnode, node) {
137 		count++;
138 	}
139 
140 	if (count != amount) {
141 		return false;
142 	}
143 
144 	return true;
145 }
146 
verify_tail_head(sys_dlist_t * list,sys_dnode_t * head,sys_dnode_t * tail,bool same)147 static inline bool verify_tail_head(sys_dlist_t *list,
148 				    sys_dnode_t *head,
149 				    sys_dnode_t *tail,
150 				    bool same)
151 {
152 	if (sys_dlist_peek_head(list) != head) {
153 		return false;
154 	}
155 
156 	if (sys_dlist_peek_tail(list) != tail) {
157 		return false;
158 	}
159 
160 	if (same) {
161 		if (sys_dlist_peek_head(list) != sys_dlist_peek_tail(list)) {
162 			return false;
163 		}
164 	} else {
165 		if (sys_dlist_peek_head(list) == sys_dlist_peek_tail(list)) {
166 			return false;
167 		}
168 	}
169 
170 	return true;
171 }
172 /**
173  * @addtogroup unit_tests
174  * @{
175  */
176 
177 /**
178  * @brief Verify doubly linked list functionalities
179  *
180  * @see sys_dlist_append(), sys_dlist_remove(), sys_dlist_prepend(),
181  * sys_dlist_remove(), sys_dlist_insert(), sys_dlist_peek_next()
182  * SYS_DLIST_ITERATE_FROM_NODE()
183  */
ZTEST(dlist_api,test_dlist)184 ZTEST(dlist_api, test_dlist)
185 {
186 	sys_dlist_init(&test_list);
187 
188 	zassert_true((verify_emptyness(&test_list)),
189 			"test_list should be empty");
190 
191 	/* Appending node 1 */
192 	sys_dlist_append(&test_list, &test_node_1.node);
193 	zassert_true((verify_content_amount(&test_list, 1)),
194 		     "test_list has wrong content");
195 
196 	zassert_true((verify_tail_head(&test_list, &test_node_1.node,
197 				       &test_node_1.node, true)),
198 		     "test_list head/tail are wrong");
199 
200 	/* Finding and removing node 1 */
201 	zassert_true(sys_dnode_is_linked(&test_node_1.node),
202 		     "node1 is not linked");
203 	sys_dlist_remove(&test_node_1.node);
204 	zassert_true((verify_emptyness(&test_list)),
205 		     "test_list should be empty");
206 	zassert_false(sys_dnode_is_linked(&test_node_1.node),
207 		      "node1 is still linked");
208 
209 	/* Prepending node 1 */
210 	sys_dlist_prepend(&test_list, &test_node_1.node);
211 	zassert_true((verify_content_amount(&test_list, 1)),
212 		     "test_list has wrong content");
213 
214 	zassert_true((verify_tail_head(&test_list, &test_node_1.node,
215 				       &test_node_1.node, true)),
216 		     "test_list head/tail are wrong");
217 
218 	/* Removing node 1 */
219 	sys_dlist_remove(&test_node_1.node);
220 	zassert_true((verify_emptyness(&test_list)),
221 		     "test_list should be empty");
222 
223 	/* Appending node 1 */
224 	sys_dlist_append(&test_list, &test_node_1.node);
225 	/* Prepending node 2 */
226 	sys_dlist_prepend(&test_list, &test_node_2.node);
227 
228 	zassert_true((verify_content_amount(&test_list, 2)),
229 		     "test_list has wrong content");
230 
231 	zassert_true((verify_tail_head(&test_list, &test_node_2.node,
232 				       &test_node_1.node, false)),
233 		     "test_list head/tail are wrong");
234 
235 	/* Appending node 3 */
236 	sys_dlist_append(&test_list, &test_node_3.node);
237 
238 	zassert_true((verify_content_amount(&test_list, 3)),
239 		     "test_list has wrong content");
240 
241 	zassert_true((verify_tail_head(&test_list, &test_node_2.node,
242 				       &test_node_3.node, false)),
243 		     "test_list head/tail are wrong");
244 
245 	zassert_true((sys_dlist_peek_next(&test_list, &test_node_2.node) ==
246 		      &test_node_1.node),
247 		     "test_list node links are wrong");
248 
249 	/* Inserting node 4 after node 2 */
250 	sys_dlist_insert(test_node_2.node.next, &test_node_4.node);
251 
252 	zassert_true((verify_tail_head(&test_list, &test_node_2.node,
253 				       &test_node_3.node, false)),
254 		     "test_list head/tail are wrong");
255 
256 	zassert_true((sys_dlist_peek_next(&test_list, &test_node_2.node) ==
257 		      &test_node_4.node),
258 		     "test_list node links are wrong");
259 
260 	/* Finding and removing node 1 */
261 	sys_dlist_remove(&test_node_1.node);
262 	zassert_true((verify_content_amount(&test_list, 3)),
263 		     "test_list has wrong content");
264 
265 	zassert_true((verify_tail_head(&test_list, &test_node_2.node,
266 				       &test_node_3.node, false)),
267 		     "test_list head/tail are wrong");
268 
269 	/* Removing node 3 */
270 	sys_dlist_remove(&test_node_3.node);
271 	zassert_true((verify_content_amount(&test_list, 2)),
272 		     "test_list has wrong content");
273 
274 	zassert_true((verify_tail_head(&test_list, &test_node_2.node,
275 				       &test_node_4.node, false)),
276 		     "test_list head/tail are wrong");
277 
278 	/* Removing node 4 */
279 	sys_dlist_remove(&test_node_4.node);
280 	zassert_true((verify_content_amount(&test_list, 1)),
281 		     "test_list has wrong content");
282 
283 	zassert_true((verify_tail_head(&test_list, &test_node_2.node,
284 				       &test_node_2.node, true)),
285 		     "test_list head/tail are wrong");
286 
287 	/* Removing node 2 */
288 	sys_dlist_remove(&test_node_2.node);
289 	zassert_true((verify_emptyness(&test_list)),
290 		     "test_list should be empty");
291 
292 	/* test iterator from a node */
293 	struct data_node {
294 		sys_dnode_t node;
295 		int data;
296 	} data_node[6] = {
297 		{ .data = 0 },
298 		{ .data = 1 },
299 		{ .data = 2 },
300 		{ .data = 3 },
301 		{ .data = 4 },
302 		{ .data = 5 },
303 	};
304 	sys_dnode_t *node = NULL;
305 	int ii;
306 
307 	sys_dlist_init(&test_list);
308 
309 	for (ii = 0; ii < 6; ii++) {
310 		sys_dlist_append(&test_list, &data_node[ii].node);
311 	}
312 
313 	ii = 0;
314 	SYS_DLIST_ITERATE_FROM_NODE(&test_list, node) {
315 		ii++;
316 		if (((struct data_node *)node)->data == 2) {
317 			break;
318 		}
319 	}
320 	zassert_equal(ii, 3, "");
321 
322 	ii = 0;
323 	SYS_DLIST_ITERATE_FROM_NODE(&test_list, node) {
324 		ii++;
325 		if (((struct data_node *)node)->data == 3) {
326 			break;
327 		}
328 	}
329 	zassert_equal(ii, 1, "");
330 
331 	ii = 0;
332 	SYS_DLIST_ITERATE_FROM_NODE(&test_list, node) {
333 		ii++;
334 	}
335 	zassert_equal(ii, 2, "");
336 }
337 
cond(sys_dnode_t * node,void * data)338 int cond(sys_dnode_t *node, void *data)
339 {
340 	return (node == data) ? 1 : 0;
341 }
342 /**
343  * @brief Verify doubly linked list functionalities
344  *
345  * @see sys_dlist_is_head(),sys_dlist_is_tail(),
346  * sys_dlist_has_multiple_nodes(),sys_dlist_get()
347  * sys_dlist_peek_head_not_empty(),sys_dlist_insert_at(),
348  * sys_dlist_peek_prev(),
349  */
ZTEST(dlist_api,test_dlist2)350 ZTEST(dlist_api, test_dlist2)
351 {
352 	struct container_node test_node[6];
353 	struct container_node insert_node;
354 	struct container_node insert_node2;
355 
356 	/* Initialize */
357 	memset(test_node, 0, sizeof(test_node));
358 	memset(&insert_node, 0, sizeof(insert_node));
359 	memset(&insert_node2, 0, sizeof(insert_node2));
360 	sys_dlist_init(&test_list);
361 
362 	/* Check if the dlist is empty */
363 	zassert_true(sys_dlist_get(&test_list) == NULL,
364 			"Get a empty dilst, NULL will be returned");
365 
366 	/* Check if a node can append as head if dlist is empty */
367 	sys_dlist_insert_at(&test_list, &insert_node.node,
368 				cond, &test_node[2].node);
369 	zassert_true(test_list.head == &insert_node.node, "");
370 	zassert_true(test_list.tail == &insert_node.node, "");
371 
372 	/* Re-initialize and insert nodes */
373 	sys_dlist_init(&test_list);
374 
375 	for (int i = 0; i < 5; i++) {
376 		sys_dlist_append(&test_list, &test_node[i].node);
377 	}
378 
379 	zassert_true(sys_dlist_peek_head_not_empty(&test_list) != NULL,
380 				"dlist appended incorrectly");
381 
382 	zassert_true(sys_dlist_is_head(&test_list,
383 						&test_node[0].node),
384 				"dlist appended incorrectly");
385 
386 	zassert_true(sys_dlist_is_tail(&test_list,
387 					&test_node[4].node),
388 				"dlist appended incorrectly");
389 
390 	zassert_true(sys_dlist_has_multiple_nodes(&test_list),
391 				"dlist appended incorrectly");
392 
393 	zassert_true(sys_dlist_peek_prev(&test_list,
394 				&test_node[2].node) == &test_node[1].node,
395 				"dlist appended incorrectly");
396 
397 	zassert_true(sys_dlist_peek_prev(&test_list,
398 				&test_node[0].node) == NULL,
399 				"dlist appended incorrectly");
400 
401 	zassert_true(sys_dlist_peek_prev(&test_list,
402 				NULL) == NULL,
403 				"dlist appended incorrectly");
404 
405 	zassert_true(sys_dlist_get(&test_list) ==
406 				&test_node[0].node,
407 				"Get a dilst, head will be returned");
408 
409 	/* Check if a node can insert in front of known nodes */
410 	sys_dlist_insert_at(&test_list, &insert_node.node,
411 				cond, &test_node[2].node);
412 	zassert_true(sys_dlist_peek_next(&test_list,
413 				&test_node[1].node) == &insert_node.node, " ");
414 
415 	/* Check if a node can append if the node is unknown */
416 	sys_dlist_insert_at(&test_list, &insert_node2.node,
417 				cond, &test_node[5].node);
418 	zassert_true(sys_dlist_peek_next(&test_list,
419 				&test_node[4].node) == &insert_node2.node, " ");
420 }
421 
422 /**
423  * @}
424  */
425