1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2023 Google LLC
4  * Written by Simon Glass <sjg@chromium.org>
5  */
6 
7 #include <alist.h>
8 #include <string.h>
9 #include <test/lib.h>
10 #include <test/test.h>
11 #include <test/ut.h>
12 
13 struct my_struct {
14 	uint val;
15 	uint other_val;
16 };
17 
18 enum {
19 	obj_size	= sizeof(struct my_struct),
20 };
21 
22 /* Test alist_init() */
lib_test_alist_init(struct unit_test_state * uts)23 static int lib_test_alist_init(struct unit_test_state *uts)
24 {
25 	struct alist lst;
26 	ulong start;
27 
28 	start = ut_check_free();
29 
30 	/* with a size of 0, the fields should be inited, with no memory used */
31 	memset(&lst, '\xff', sizeof(lst));
32 	ut_assert(alist_init_struct(&lst, struct my_struct));
33 	ut_asserteq_ptr(NULL, lst.data);
34 	ut_asserteq(0, lst.count);
35 	ut_asserteq(0, lst.alloc);
36 	ut_assertok(ut_check_delta(start));
37 	alist_uninit(&lst);
38 	ut_asserteq_ptr(NULL, lst.data);
39 	ut_asserteq(0, lst.count);
40 	ut_asserteq(0, lst.alloc);
41 
42 	/* use an impossible size */
43 	ut_asserteq(false, alist_init(&lst, obj_size,
44 				      CONFIG_SYS_MALLOC_LEN));
45 	ut_assertnull(lst.data);
46 	ut_asserteq(0, lst.count);
47 	ut_asserteq(0, lst.alloc);
48 
49 	/* use a small size */
50 	ut_assert(alist_init(&lst, obj_size, 4));
51 	ut_assertnonnull(lst.data);
52 	ut_asserteq(0, lst.count);
53 	ut_asserteq(4, lst.alloc);
54 
55 	/* free it */
56 	alist_uninit(&lst);
57 	ut_asserteq_ptr(NULL, lst.data);
58 	ut_asserteq(0, lst.count);
59 	ut_asserteq(0, lst.alloc);
60 	ut_assertok(ut_check_delta(start));
61 
62 	/* Check for memory leaks */
63 	ut_assertok(ut_check_delta(start));
64 
65 	return 0;
66 }
67 LIB_TEST(lib_test_alist_init, 0);
68 
69 /* Test alist_get() and alist_getd() */
lib_test_alist_get(struct unit_test_state * uts)70 static int lib_test_alist_get(struct unit_test_state *uts)
71 {
72 	struct alist lst;
73 	ulong start;
74 	void *ptr;
75 
76 	start = ut_check_free();
77 
78 	ut_assert(alist_init(&lst, obj_size, 3));
79 	ut_asserteq(0, lst.count);
80 	ut_asserteq(3, lst.alloc);
81 
82 	ut_assertnull(alist_get_ptr(&lst, 2));
83 	ut_assertnull(alist_get_ptr(&lst, 3));
84 
85 	ptr = alist_ensure_ptr(&lst, 1);
86 	ut_assertnonnull(ptr);
87 	ut_asserteq(2, lst.count);
88 	ptr = alist_ensure_ptr(&lst, 2);
89 	ut_asserteq(3, lst.count);
90 	ut_assertnonnull(ptr);
91 
92 	ptr = alist_ensure_ptr(&lst, 3);
93 	ut_assertnonnull(ptr);
94 	ut_asserteq(4, lst.count);
95 	ut_asserteq(6, lst.alloc);
96 
97 	ut_assertnull(alist_get_ptr(&lst, 4));
98 
99 	alist_uninit(&lst);
100 
101 	/* Check for memory leaks */
102 	ut_assertok(ut_check_delta(start));
103 
104 	return 0;
105 }
106 LIB_TEST(lib_test_alist_get, 0);
107 
108 /* Test alist_has() */
lib_test_alist_has(struct unit_test_state * uts)109 static int lib_test_alist_has(struct unit_test_state *uts)
110 {
111 	struct alist lst;
112 	ulong start;
113 	void *ptr;
114 
115 	start = ut_check_free();
116 
117 	ut_assert(alist_init(&lst, obj_size, 3));
118 
119 	ut_assert(!alist_has(&lst, 0));
120 	ut_assert(!alist_has(&lst, 1));
121 	ut_assert(!alist_has(&lst, 2));
122 	ut_assert(!alist_has(&lst, 3));
123 
124 	/* create a new one to force expansion */
125 	ptr = alist_ensure_ptr(&lst, 4);
126 	ut_assertnonnull(ptr);
127 
128 	ut_assert(alist_has(&lst, 0));
129 	ut_assert(alist_has(&lst, 1));
130 	ut_assert(alist_has(&lst, 2));
131 	ut_assert(alist_has(&lst, 3));
132 	ut_assert(alist_has(&lst, 4));
133 	ut_assert(!alist_has(&lst, 5));
134 
135 	alist_uninit(&lst);
136 
137 	/* Check for memory leaks */
138 	ut_assertok(ut_check_delta(start));
139 
140 	return 0;
141 }
142 LIB_TEST(lib_test_alist_has, 0);
143 
144 /* Test alist_ensure() */
lib_test_alist_ensure(struct unit_test_state * uts)145 static int lib_test_alist_ensure(struct unit_test_state *uts)
146 {
147 	struct my_struct *ptr3, *ptr4;
148 	struct alist lst;
149 	ulong start;
150 
151 	start = ut_check_free();
152 
153 	ut_assert(alist_init_struct(&lst, struct my_struct));
154 	ut_asserteq(obj_size, lst.obj_size);
155 	ut_asserteq(0, lst.count);
156 	ut_asserteq(0, lst.alloc);
157 	ptr3 = alist_ensure_ptr(&lst, 3);
158 	ut_asserteq(4, lst.count);
159 	ut_asserteq(4, lst.alloc);
160 	ut_assertnonnull(ptr3);
161 	ptr3->val = 3;
162 
163 	ptr4 = alist_ensure_ptr(&lst, 4);
164 	ut_asserteq(8, lst.alloc);
165 	ut_asserteq(5, lst.count);
166 	ut_assertnonnull(ptr4);
167 	ptr4->val = 4;
168 	ut_asserteq(4, alist_get(&lst, 4, struct my_struct)->val);
169 
170 	ut_asserteq_ptr(ptr4, alist_ensure(&lst, 4, struct my_struct));
171 
172 	alist_ensure(&lst, 4, struct my_struct)->val = 44;
173 	ut_asserteq(44, alist_get(&lst, 4, struct my_struct)->val);
174 	ut_asserteq(3, alist_get(&lst, 3, struct my_struct)->val);
175 	ut_assertnull(alist_get(&lst, 7, struct my_struct));
176 	ut_asserteq(8, lst.alloc);
177 	ut_asserteq(5, lst.count);
178 
179 	/* add some more, checking handling of malloc() failure */
180 	malloc_enable_testing(0);
181 	ut_assertnonnull(alist_ensure(&lst, 7, struct my_struct));
182 	ut_assertnull(alist_ensure(&lst, 8, struct my_struct));
183 	malloc_disable_testing();
184 
185 	lst.flags &= ~ALISTF_FAIL;
186 	ut_assertnonnull(alist_ensure(&lst, 8, struct my_struct));
187 	ut_asserteq(16, lst.alloc);
188 	ut_asserteq(9, lst.count);
189 
190 	alist_uninit(&lst);
191 
192 	/* Check for memory leaks */
193 	ut_assertok(ut_check_delta(start));
194 
195 	return 0;
196 }
197 LIB_TEST(lib_test_alist_ensure, 0);
198 
199 /* Test alist_add() bits not tested by lib_test_alist_ensure() */
lib_test_alist_add(struct unit_test_state * uts)200 static int lib_test_alist_add(struct unit_test_state *uts)
201 {
202 	struct my_struct data, *ptr, *ptr2;
203 	const struct my_struct *chk;
204 	struct alist lst;
205 	ulong start;
206 
207 	start = ut_check_free();
208 
209 	ut_assert(alist_init_struct(&lst, struct my_struct));
210 
211 	data.val = 123;
212 	data.other_val = 456;
213 	ptr = alist_add(&lst, data);
214 	ut_assertnonnull(ptr);
215 	ut_asserteq(4, lst.alloc);
216 	ut_asserteq(1, lst.count);
217 
218 	ut_asserteq(123, ptr->val);
219 	ut_asserteq(456, ptr->other_val);
220 
221 	ptr2 = alist_add_placeholder(&lst);
222 	ut_assertnonnull(ptr2);
223 
224 	ptr2->val = 321;
225 	ptr2->other_val = 654;
226 
227 	chk = alist_get(&lst, 1, struct my_struct);
228 	ut_asserteq(321, chk->val);
229 	ut_asserteq(654, chk->other_val);
230 
231 	ptr2 = alist_getw(&lst, 1, struct my_struct);
232 	ut_asserteq(321, ptr2->val);
233 	ut_asserteq(654, ptr2->other_val);
234 
235 	alist_uninit(&lst);
236 
237 	/* Check for memory leaks */
238 	ut_assertok(ut_check_delta(start));
239 
240 	return 0;
241 }
242 LIB_TEST(lib_test_alist_add, 0);
243 
244 /* Test alist_next()  */
lib_test_alist_next(struct unit_test_state * uts)245 static int lib_test_alist_next(struct unit_test_state *uts)
246 {
247 	const struct my_struct *ptr;
248 	struct my_struct data, *ptr2;
249 	struct alist lst;
250 	ulong start;
251 
252 	start = ut_check_free();
253 
254 	ut_assert(alist_init_struct(&lst, struct my_struct));
255 	data.val = 123;
256 	data.other_val = 0;
257 	alist_add(&lst, data);
258 
259 	data.val = 321;
260 	alist_add(&lst, data);
261 
262 	data.val = 789;
263 	alist_add(&lst, data);
264 
265 	ptr = alist_get(&lst, 0, struct my_struct);
266 	ut_assertnonnull(ptr);
267 	ut_asserteq(123, ptr->val);
268 
269 	ptr = alist_next(&lst, ptr);
270 	ut_assertnonnull(ptr);
271 	ut_asserteq(321, ptr->val);
272 
273 	ptr2 = (struct my_struct *)ptr;
274 	ptr2 = alist_nextw(&lst, ptr2);
275 	ut_assertnonnull(ptr2);
276 
277 	ptr = alist_next(&lst, ptr);
278 	ut_assertnonnull(ptr);
279 	ut_asserteq(789, ptr->val);
280 	ut_asserteq_ptr(ptr, ptr2);
281 	ptr2->val = 89;
282 	ut_asserteq(89, ptr->val);
283 
284 	ptr = alist_next(&lst, ptr);
285 	ut_assertnull(ptr);
286 
287 	alist_uninit(&lst);
288 
289 	/* Check for memory leaks */
290 	ut_assertok(ut_check_delta(start));
291 
292 	return 0;
293 }
294 LIB_TEST(lib_test_alist_next, 0);
295 
296 /* Test alist_for_each()  */
lib_test_alist_for_each(struct unit_test_state * uts)297 static int lib_test_alist_for_each(struct unit_test_state *uts)
298 {
299 	const struct my_struct *ptr;
300 	struct my_struct data, *ptr2;
301 	struct alist lst;
302 	ulong start;
303 	int sum;
304 
305 	start = ut_check_free();
306 
307 	ut_assert(alist_init_struct(&lst, struct my_struct));
308 	ut_asserteq_ptr(NULL, alist_end(&lst, struct my_struct));
309 
310 	sum = 0;
311 	alist_for_each(ptr, &lst)
312 		sum++;
313 	ut_asserteq(0, sum);
314 
315 	alist_for_each(ptr, &lst)
316 		sum++;
317 	ut_asserteq(0, sum);
318 
319 	/* add three items */
320 	data.val = 1;
321 	data.other_val = 0;
322 	alist_add(&lst, data);
323 
324 	ptr = lst.data;
325 	ut_asserteq_ptr(ptr + 1, alist_end(&lst, struct my_struct));
326 
327 	data.val = 2;
328 	alist_add(&lst, data);
329 	ut_asserteq_ptr(ptr + 2, alist_end(&lst, struct my_struct));
330 
331 	data.val = 3;
332 	alist_add(&lst, data);
333 	ut_asserteq_ptr(ptr + 3, alist_end(&lst, struct my_struct));
334 
335 	/* check alist_chk_ptr() */
336 	ut_asserteq(true, alist_chk_ptr(&lst, ptr + 2));
337 	ut_asserteq(false, alist_chk_ptr(&lst, ptr + 3));
338 	ut_asserteq(false, alist_chk_ptr(&lst, ptr + 4));
339 	ut_asserteq(true, alist_chk_ptr(&lst, ptr));
340 	ut_asserteq(false, alist_chk_ptr(&lst, ptr - 1));
341 
342 	/* sum all items */
343 	sum = 0;
344 	alist_for_each(ptr, &lst)
345 		sum += ptr->val;
346 	ut_asserteq(6, sum);
347 
348 	/* increment all items */
349 	alist_for_each(ptr2, &lst)
350 		ptr2->val += 1;
351 
352 	/* sum all items again */
353 	sum = 0;
354 	alist_for_each(ptr, &lst)
355 		sum += ptr->val;
356 	ut_asserteq(9, sum);
357 
358 	ptr = lst.data;
359 	ut_asserteq_ptr(ptr + 3, alist_end(&lst, struct my_struct));
360 
361 	/* empty the list and try again */
362 	alist_empty(&lst);
363 	ut_asserteq_ptr(ptr, alist_end(&lst, struct my_struct));
364 	ut_assertnull(alist_get(&lst, 0, struct my_struct));
365 
366 	sum = 0;
367 	alist_for_each(ptr, &lst)
368 		sum += ptr->val;
369 	ut_asserteq(0, sum);
370 
371 	alist_uninit(&lst);
372 
373 	/* Check for memory leaks */
374 	ut_assertok(ut_check_delta(start));
375 
376 	return 0;
377 }
378 LIB_TEST(lib_test_alist_for_each, 0);
379 
380 /* Test alist_empty()  */
lib_test_alist_empty(struct unit_test_state * uts)381 static int lib_test_alist_empty(struct unit_test_state *uts)
382 {
383 	struct my_struct data;
384 	struct alist lst;
385 	ulong start;
386 
387 	start = ut_check_free();
388 
389 	ut_assert(alist_init_struct(&lst, struct my_struct));
390 	ut_asserteq(0, lst.count);
391 	data.val = 1;
392 	data.other_val = 0;
393 	alist_add(&lst, data);
394 	ut_asserteq(1, lst.count);
395 	ut_asserteq(4, lst.alloc);
396 
397 	alist_empty(&lst);
398 	ut_asserteq(0, lst.count);
399 	ut_asserteq(4, lst.alloc);
400 	ut_assertnonnull(lst.data);
401 	ut_asserteq(sizeof(data), lst.obj_size);
402 
403 	alist_uninit(&lst);
404 
405 	/* Check for memory leaks */
406 	ut_assertok(ut_check_delta(start));
407 
408 	return 0;
409 }
410 LIB_TEST(lib_test_alist_empty, 0);
411 
lib_test_alist_filter(struct unit_test_state * uts)412 static int lib_test_alist_filter(struct unit_test_state *uts)
413 {
414 	struct my_struct *from, *to, *ptr;
415 	struct my_struct data;
416 	struct alist lst;
417 	ulong start;
418 	int count;
419 
420 	start = ut_check_free();
421 
422 	ut_assert(alist_init_struct(&lst, struct my_struct));
423 	data.val = 1;
424 	data.other_val = 0;
425 	alist_add(&lst, data);
426 
427 	data.val = 2;
428 	alist_add(&lst, data);
429 
430 	data.val = 3;
431 	alist_add(&lst, data);
432 	ptr = lst.data;
433 
434 	/* filter out all values except 2 */
435 	alist_for_each_filter(from, to, &lst) {
436 		if (from->val != 2)
437 			*to++ = *from;
438 	}
439 	alist_update_end(&lst, to);
440 
441 	ut_asserteq(2, lst.count);
442 	ut_assertnonnull(lst.data);
443 
444 	ut_asserteq(1, alist_get(&lst, 0, struct my_struct)->val);
445 	ut_asserteq(3, alist_get(&lst, 1, struct my_struct)->val);
446 	ut_asserteq_ptr(ptr + 3, from);
447 	ut_asserteq_ptr(ptr + 2, to);
448 
449 	/* filter out nothing */
450 	alist_for_each_filter(from, to, &lst) {
451 		if (from->val != 2)
452 			*to++ = *from;
453 	}
454 	alist_update_end(&lst, to);
455 	ut_asserteq_ptr(ptr + 2, from);
456 	ut_asserteq_ptr(ptr + 2, to);
457 
458 	ut_asserteq(2, lst.count);
459 	ut_assertnonnull(lst.data);
460 
461 	ut_asserteq(1, alist_get(&lst, 0, struct my_struct)->val);
462 	ut_asserteq(3, alist_get(&lst, 1, struct my_struct)->val);
463 
464 	/* filter out everything */
465 	alist_for_each_filter(from, to, &lst) {
466 		if (from->val == 2)
467 			*to++ = *from;
468 	}
469 	alist_update_end(&lst, to);
470 	ut_asserteq_ptr(ptr + 2, from);
471 	ut_asserteq_ptr(ptr, to);
472 
473 	/* filter out everything (nop) */
474 	count = 0;
475 	alist_for_each_filter(from, to, &lst) {
476 		if (from->val == 2)
477 			*to++ = *from;
478 		count++;
479 	}
480 	alist_update_end(&lst, to);
481 	ut_asserteq_ptr(ptr, from);
482 	ut_asserteq_ptr(ptr, to);
483 	ut_asserteq(0, count);
484 
485 	ut_asserteq(0, lst.count);
486 	ut_assertnonnull(lst.data);
487 
488 	alist_uninit(&lst);
489 
490 	/* Check for memory leaks */
491 	ut_assertok(ut_check_delta(start));
492 
493 	return 0;
494 }
495 LIB_TEST(lib_test_alist_filter, 0);
496