1 /*
2 * SysDB - t/unit/utils/llist_test.c
3 * Copyright (C) 2013 Sebastian 'tokkee' Harl <sh@tokkee.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
28 #if HAVE_CONFIG_H
29 # include "config.h"
30 #endif
32 #include "utils/llist.h"
33 #include "testutils.h"
35 #include <check.h>
37 /*
38 * private data types
39 */
41 static sdb_object_t golden_data[] = {
42 SDB_OBJECT_STATIC("abc"),
43 SDB_OBJECT_STATIC("bcd"),
44 SDB_OBJECT_STATIC("cde"),
45 SDB_OBJECT_STATIC("def"),
46 SDB_OBJECT_STATIC("efg"),
47 SDB_OBJECT_STATIC("fgh"),
48 SDB_OBJECT_STATIC("ghi")
49 };
51 static char *unused_names[] = {
52 "xyz",
53 "yza",
54 "zab"
55 };
57 static sdb_llist_t *list;
59 static void
60 setup(void)
61 {
62 list = sdb_llist_create();
63 fail_unless(list != NULL,
64 "sdb_llist_create() = NULL; expected list object");
65 } /* setup */
67 static void
68 teardown(void)
69 {
70 sdb_llist_destroy(list);
71 list = NULL;
72 } /* teardown */
74 /* populate the list with the golden data in the specified order */
75 static void
76 populate(void)
77 {
78 size_t i;
79 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
80 int check = sdb_llist_append(list, &golden_data[i]);
81 fail_unless(check == 0,
82 "sdb_llist_append(%s) = %i; expected: 0",
83 golden_data[i].name, check);
84 }
85 } /* populate */
87 START_TEST(test_clone)
88 {
89 sdb_llist_t *clone;
90 size_t i;
92 populate();
94 clone = sdb_llist_clone(list);
95 fail_unless(clone != NULL,
96 "sdb_llist_clone() = NULL; expected: cloned list object");
98 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
99 fail_unless(golden_data[i].ref_cnt == 3,
100 "sdb_llist_clone() did not take ownership");
101 }
103 sdb_llist_destroy(clone);
104 }
105 END_TEST
107 START_TEST(test_destroy)
108 {
109 size_t i;
110 populate();
111 sdb_llist_destroy(list);
112 list = NULL;
114 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
115 fail_unless(golden_data[i].ref_cnt == 1,
116 "sdb_llist_destroy() did not deref element %s",
117 golden_data[i].name);
118 }
119 }
120 END_TEST
122 START_TEST(test_clear)
123 {
124 size_t i;
125 populate();
126 sdb_llist_clear(list);
128 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
129 fail_unless(golden_data[i].ref_cnt == 1,
130 "sdb_llist_clear() did not deref element %s",
131 golden_data[i].name);
132 }
134 i = sdb_llist_len(list);
135 fail_unless(i == 0,
136 "sdb_llist_clear() left %zu elements in the list; "
137 "expected: 0", i);
138 }
139 END_TEST
141 START_TEST(test_append)
142 {
143 size_t i;
145 fail_unless(sdb_llist_len(list) == 0,
146 "sdb_llist_len(<empty list>) = %zu; expected: 0",
147 sdb_llist_len(list));
149 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
150 int check = sdb_llist_append(list, &golden_data[i]);
151 fail_unless(check == 0,
152 "sdb_llist_append(%s) = %i; expected: 0",
153 golden_data[i].name, check);
154 fail_unless(golden_data[i].ref_cnt == 2,
155 "sdb_llist_append(%s) did not take ownership",
156 golden_data[i].name);
157 fail_unless(sdb_llist_len(list) == i + 1,
158 "sdb_llist_len(<empty list>) = %zu; expected: zu",
159 sdb_llist_len(list), i + 1);
160 }
161 }
162 END_TEST
164 START_TEST(test_insert)
165 {
166 size_t i;
167 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
168 int check = sdb_llist_insert(list, &golden_data[i], 0);
169 fail_unless(check == 0,
170 "sdb_llist_insert(%s, 0) = %i; expected: 0",
171 golden_data[i].name, check);
172 fail_unless(golden_data[i].ref_cnt == 2,
173 "sdb_llist_insert(%s, 0) did not take ownership",
174 golden_data[i].name);
175 }
176 }
177 END_TEST
179 START_TEST(test_validate_insert)
180 {
181 size_t i;
182 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
183 /* none of these operations will succeed
184 * => 1 is invalid for each case */
185 int check = sdb_llist_insert(list, &golden_data[i], 1);
186 fail_unless(check == -1,
187 "sdb_llist_insert(%s, 1) = %i; expected: -1",
188 golden_data[i].name, check);
189 fail_unless(golden_data[i].ref_cnt == 1,
190 "sdb_llist_insert(%s, 1) took ownership",
191 golden_data[i].name);
192 }
193 }
194 END_TEST
196 START_TEST(test_get)
197 {
198 size_t i;
199 populate();
200 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
201 sdb_object_t *check = sdb_llist_get(list, i);
202 fail_unless(check == &golden_data[i],
203 "sdb_llist_get() = %p; expected: %p",
204 check, &golden_data[i]);
205 fail_unless(check->ref_cnt == 3,
206 "sdb_llist_get() didn't increment reference count; got: %i; "
207 "expected: 3", check->ref_cnt);
208 sdb_object_deref(check);
209 }
210 }
211 END_TEST
213 START_TEST(test_remove_by_name)
214 {
215 /* "random" indexes */
216 int indexes[] = { 4, 5, 3, 6, 2, 0, 1 };
217 size_t i;
219 populate();
221 for (i = 0; i < SDB_STATIC_ARRAY_LEN(indexes); ++i) {
222 sdb_object_t *check;
224 fail_unless((size_t)indexes[i] < SDB_STATIC_ARRAY_LEN(golden_data),
225 "INTERNAL ERROR: invalid index %i", indexes[i]);
227 check = sdb_llist_remove_by_name(list, golden_data[indexes[i]].name);
228 fail_unless(check == &golden_data[indexes[i]],
229 "sdb_llist_remove_by_name() = %p; expected: %p",
230 check, &golden_data[indexes[i]]);
231 fail_unless(check->ref_cnt == 2,
232 "sdb_llist_remove_by_name() returned unexpected reference "
233 "count; got: %i; expected: 2", check->ref_cnt);
235 check = sdb_llist_remove_by_name(list, golden_data[indexes[i]].name);
236 fail_unless(check == NULL,
237 "sdb_llist_remove_by_name() did not remove the element");
238 }
239 }
240 END_TEST
242 static int
243 dummy_lookup(const sdb_object_t __attribute__((unused)) *obj,
244 const void __attribute__((unused)) *user_data)
245 {
246 return 0;
247 } /* dummy_lookup */
249 START_TEST(test_search)
250 {
251 size_t i;
252 populate();
253 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
254 sdb_object_t *check = sdb_llist_search_by_name(list,
255 golden_data[i].name);
256 fail_unless(check == &golden_data[i],
257 "sdb_llist_search_by_name(%s) = NULL; expected: %p",
258 golden_data[i].name, &golden_data[i]);
259 }
261 for (i = 0; i < SDB_STATIC_ARRAY_LEN(unused_names); ++i) {
262 sdb_object_t *check = sdb_llist_search_by_name(list,
263 unused_names[i]);
264 fail_unless(check == NULL,
265 "sdb_llist_search_by_name(%s) = %p; expected: NULL",
266 unused_names[i], check);
267 }
269 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
270 /* dummy_lookup always return 0, thus, this will always return the
271 * first element */
272 sdb_object_t *check = sdb_llist_search(list, dummy_lookup, NULL);
273 fail_unless(check == &golden_data[i],
274 "sdb_llist_search() = %p (%s); expected: %p (%s)",
275 check, check->name, &golden_data[i], golden_data[i].name);
277 /* => remove the first element */
278 check = sdb_llist_remove(list, dummy_lookup, NULL);
279 fail_unless(check == &golden_data[i],
280 "sdb_llist_remove() = %p (%s); expected: %p (%s)",
281 check, check->name, &golden_data[i], golden_data[i].name);
282 fail_unless(check->ref_cnt == 2,
283 "sdb_llist_remove() changed reference count; got: %i; "
284 "expected: 2", check->ref_cnt);
285 }
286 /* should now be empty */
287 fail_unless(sdb_llist_len(list) == 0,
288 "Still have %i elements in the list; expected: 0",
289 sdb_llist_len(list));
290 }
291 END_TEST
293 START_TEST(test_shift)
294 {
295 size_t i;
296 populate();
297 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
298 sdb_object_t *check = sdb_llist_shift(list);
299 fail_unless(check == &golden_data[i],
300 "sdb_llist_shift() = NULL; expected: %p",
301 &golden_data[i]);
302 fail_unless(check->ref_cnt == 2,
303 "sdb_llist_shift() changed reference count; got: %i; "
304 "expected: 2", check->ref_cnt);
305 }
307 /* must be empty now */
308 fail_unless(sdb_llist_shift(list) == NULL,
309 "sdb_llist_shift() returned value; expected: NULL");
310 }
311 END_TEST
313 START_TEST(test_iter)
314 {
315 sdb_llist_iter_t *iter;
316 size_t i;
318 populate();
320 iter = sdb_llist_get_iter(list);
321 fail_unless(iter != NULL,
322 "sdb_llist_get_iter() did not return an iterator");
324 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
325 sdb_object_t *check;
326 fail_unless(sdb_llist_iter_has_next(iter),
327 "sdb_llist_iter_has_next() = FALSE; expected: TRUE");
328 check = sdb_llist_iter_get_next(iter);
329 fail_unless(check == &golden_data[i],
330 "sdb_llist_iter_get_next() = %p; expected: %p",
331 check, &golden_data[i]);
332 }
334 fail_unless(!sdb_llist_iter_has_next(iter),
335 "sdb_llist_iter_has_next() = TRUE; expected: FALSE");
336 fail_unless(sdb_llist_iter_get_next(iter) == NULL,
337 "sdb_llist_iter_get_next() returned value; expected: NULL");
338 sdb_llist_iter_destroy(iter);
339 }
340 END_TEST
342 START_TEST(test_iter_remove)
343 {
344 sdb_llist_iter_t *iter;
345 sdb_object_t *check;
346 size_t i;
348 populate();
350 iter = sdb_llist_get_iter(list);
351 fail_unless(iter != NULL,
352 "sdb_llist_get_iter() did not return an iterator");
354 i = 0;
355 while (sdb_llist_iter_has_next(iter)) {
356 check = sdb_llist_iter_get_next(iter);
357 fail_unless(check == &golden_data[i],
358 "sdb_llist_iter_get_next() = %p; expected: %p",
359 check, &golden_data[i]);
361 sdb_llist_iter_remove_current(iter);
362 ++i;
363 }
364 sdb_llist_iter_destroy(iter);
366 fail_unless(i == (size_t)SDB_STATIC_ARRAY_LEN(golden_data),
367 "iterated for %zu steps; expected: %i",
368 i, SDB_STATIC_ARRAY_LEN(golden_data));
370 /* all elements should be removed */
371 check = sdb_llist_shift(list);
372 fail_unless(check == NULL,
373 "sdb_llist_shift() = %p; expected: NULL", check);
374 }
375 END_TEST
377 TEST_MAIN("utils::llist")
378 {
379 TCase *tc = tcase_create("core");
380 tcase_add_checked_fixture(tc, setup, teardown);
381 tcase_add_test(tc, test_clone);
382 tcase_add_test(tc, test_destroy);
383 tcase_add_test(tc, test_clear);
384 tcase_add_test(tc, test_append);
385 tcase_add_test(tc, test_insert);
386 tcase_add_test(tc, test_validate_insert);
387 tcase_add_test(tc, test_get);
388 tcase_add_test(tc, test_remove_by_name);
389 tcase_add_test(tc, test_search);
390 tcase_add_test(tc, test_shift);
391 tcase_add_test(tc, test_iter);
392 tcase_add_test(tc, test_iter_remove);
393 ADD_TCASE(tc);
394 }
395 TEST_MAIN_END
397 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */