1 /*
2 * SysDB - t/unit/core/object_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 #include "core/object.h"
29 #include "libsysdb_test.h"
31 #include <check.h>
33 /*
34 * private data types
35 */
37 static int init_noop_called = 0;
38 static int init_noop_retval = 0;
39 static int
40 obj_init_noop(sdb_object_t *obj, va_list __attribute__((unused)) ap)
41 {
42 ++init_noop_called;
43 fail_unless(obj != NULL, "obj init function: received obj == NULL");
44 return init_noop_retval;
45 } /* obj_init_noop */
47 static int destroy_noop_called = 0;
48 static void
49 obj_destroy_noop(sdb_object_t *obj)
50 {
51 ++destroy_noop_called;
52 fail_unless(obj != NULL, "obj destroy function: received obj == NULL");
53 } /* obj_destroy_noop */
55 struct noop {
56 sdb_object_t super;
57 int data;
58 };
59 static sdb_type_t noop_type = {
60 /* size = */ sizeof(struct noop),
61 /* init = */ obj_init_noop,
62 /* destroy = */ obj_destroy_noop,
63 };
65 static void *wrapped = (void *)0x42;
67 static int destroy_wrapper_called = 0;
68 static void
69 wrapper_destroy(void *obj)
70 {
71 ++destroy_wrapper_called;
72 fail_unless(obj == wrapped,
73 "wrapper_destroy received unexpected obj %p; expected: %p",
74 obj, wrapped);
75 } /* wrapper_destroy */
77 START_TEST(test_obj_create)
78 {
79 sdb_object_t *obj;
80 sdb_type_t test_type = noop_type;
82 const char *name = "test-object";
84 init_noop_called = 0;
85 init_noop_retval = 0;
86 destroy_noop_called = 0;
87 obj = sdb_object_create(name, test_type);
88 fail_unless(obj != NULL,
89 "sdb_object_create() = NULL; expected: a new object");
90 fail_unless(obj->type.size == test_type.size,
91 "after sdb_object_create(): type size mismatch; got: %zu; "
92 "expected: %zu", obj->type.size, test_type.size);
93 fail_unless(obj->type.init == obj_init_noop,
94 "after sdb_object_create(): type init = %p; exptected: %p",
95 obj->type.init, obj_init_noop);
96 fail_unless(obj->type.destroy == obj_destroy_noop,
97 "after sdb_object_create(): type destroy = %p; exptected: %p",
98 obj->type.destroy, obj_destroy_noop);
99 fail_unless(obj->ref_cnt == 1,
100 "after sdb_object_create(): obj->ref_cnt = %d; expected: 1",
101 obj->ref_cnt);
102 fail_unless(!strcmp(obj->name, "test-object"),
103 "after sdb_object_create(): obj->name = '%s'; expected: '%s'",
104 obj->name, name);
105 fail_unless(obj->name != name,
106 "after sdb_object_create(): obj->name was not strdup()'ed");
108 fail_unless(init_noop_called == 1,
109 "sdb_object_create() did not call object's init function");
110 fail_unless(destroy_noop_called == 0,
111 "sdb_object_create() called object's destroy function");
112 fail_unless(((struct noop *)obj)->data == 0,
113 "sdb_object_create() did not initialize data to zero");
115 sdb_object_deref(obj);
116 fail_unless(destroy_noop_called == 1,
117 "sdb_object_deref() did not call object's destroy function");
119 init_noop_called = 0;
120 init_noop_retval = -1;
121 destroy_noop_called = 0;
122 obj = sdb_object_create(name, test_type);
123 fail_unless(obj == NULL,
124 "sdb_object_create() = %p; expected NULL (init returned -1)",
125 obj);
126 fail_unless(init_noop_called == 1,
127 "sdb_object_create() did not call object's init function");
128 fail_unless(destroy_noop_called == 1,
129 "sdb_object_create() did not call object's destroy function "
130 "after init failure");
132 test_type.size = 1;
133 init_noop_called = 0;
134 init_noop_retval = 0;
135 destroy_noop_called = 0;
136 obj = sdb_object_create(name, test_type);
137 fail_unless(obj == NULL,
138 "sdb_object_create() = %p; expected NULL (type's size too small)",
139 obj);
140 fail_unless(init_noop_called == 0,
141 "sdb_object_create() called object's init function "
142 "when size was too small");
143 fail_unless(destroy_noop_called == 0,
144 "sdb_object_create() called object's destroy function "
145 "when size was too small");
147 test_type.size = sizeof(struct noop);
148 init_noop_retval = 0;
149 test_type.init = NULL;
150 obj = sdb_object_create(name, test_type);
151 fail_unless(obj != NULL,
152 "sdb_object_create() fails without init callback");
153 sdb_object_deref(obj);
155 test_type.destroy = NULL;
156 obj = sdb_object_create(name, test_type);
157 fail_unless(obj != NULL,
158 "sdb_object_create() fails without destroy callback");
159 sdb_object_deref(obj);
161 init_noop_called = 0;
162 obj = sdb_object_create_simple(name, sizeof(struct noop), NULL);
163 fail_unless(obj != NULL,
164 "sdb_object_create_simple() = NULL; expected: <obj>");
165 fail_unless(obj->type.size == sizeof(struct noop),
166 "sdb_object_create_simple() created object of size %zu; "
167 "expected: %zu", obj->type.size, sizeof(struct noop));
168 fail_unless(obj->type.init == NULL,
169 "sdb_object_create_simple() did not set init=NULL");
170 fail_unless(obj->type.destroy == NULL,
171 "sdb_object_create_simple() did not set destroy=NULL");
172 fail_unless(init_noop_called == 0,
173 "sdb_object_create_simple() unexpectedly called noop's init");
174 sdb_object_deref(obj);
176 obj = sdb_object_create_T(NULL, struct noop);
177 fail_unless(obj != NULL,
178 "sdb_object_create_simple() = NULL; expected: <obj>");
179 fail_unless(obj->type.size == sizeof(struct noop),
180 "sdb_object_create_simple() created object of size %zu; "
181 "expected: %zu", obj->type.size, sizeof(struct noop));
182 fail_unless(obj->type.init == NULL,
183 "sdb_object_create_simple() did not set init=NULL");
184 fail_unless(obj->type.destroy == NULL,
185 "sdb_object_create_simple() did not set destroy=NULL");
186 fail_unless(init_noop_called == 0,
187 "sdb_object_create_simple() unexpectedly called noop's init");
188 sdb_object_deref(obj);
189 }
190 END_TEST
192 START_TEST(test_obj_wrapper)
193 {
194 sdb_object_t *obj;
195 const char *name = "wrapped-object";
197 destroy_wrapper_called = 0;
198 obj = sdb_object_create_wrapper(name, wrapped, wrapper_destroy);
199 fail_unless(obj != NULL,
200 "sdb_object_create_wrapper() = NULL; expected: wrapper object");
201 fail_unless(obj->ref_cnt == 1,
202 "after sdb_object_create_wrapper(); obj->ref_cnt = %d; "
203 "expected: 1", obj->ref_cnt);
204 fail_unless(!strcmp(obj->name, name),
205 "after sdb_object_create_wrapper(); obj->name = %s; expected: %s",
206 obj->name, name);
207 fail_unless(obj->name != name,
208 "sdb_object_create_wrapper() did not copy object name");
209 fail_unless(SDB_OBJ_WRAPPER(obj)->data == wrapped,
210 "wrapped object wraps unexpected data %p; expected: %p",
211 SDB_OBJ_WRAPPER(obj)->data, wrapped);
213 fail_unless(destroy_wrapper_called == 0,
214 "sdb_object_create_wrapper() called object's destructor");
216 sdb_object_deref(obj);
217 fail_unless(destroy_wrapper_called == 1,
218 "sdb_object_deref() did not call wrapped object's destructor");
219 }
220 END_TEST
222 START_TEST(test_obj_ref)
223 {
224 sdb_object_t *obj;
225 sdb_type_t test_type = noop_type;
227 init_noop_called = 0;
228 init_noop_retval = 0;
229 destroy_noop_called = 0;
231 obj = sdb_object_create("test-object", test_type);
232 fail_unless(obj != NULL,
233 "sdb_object_create() = NULL; expected: valid object");
235 sdb_object_ref(obj);
236 fail_unless(obj->ref_cnt == 2,
237 "after db_object_ref(): obj->ref_cnt = %d; expected: 2",
238 obj->ref_cnt);
240 sdb_object_ref(obj);
241 fail_unless(obj->ref_cnt == 3,
242 "after db_object_ref(): obj->ref_cnt = %d; expected: 3",
243 obj->ref_cnt);
245 obj->ref_cnt = 42;
246 sdb_object_ref(obj);
247 fail_unless(obj->ref_cnt == 43,
248 "after db_object_ref(): obj->ref_cnt = %d; expected: 43",
249 obj->ref_cnt);
251 fail_unless(init_noop_called == 1,
252 "after some sdb_object_ref(); object's init called %d times; "
253 "expected: 1", init_noop_called);
254 fail_unless(destroy_noop_called == 0,
255 "after some sdb_object_ref(); object's destroy called %d time%s; "
256 "expected: 0", destroy_noop_called == 1 ? "" : "2",
257 destroy_noop_called);
259 sdb_object_deref(obj);
260 fail_unless(obj->ref_cnt == 42,
261 "after db_object_deref(): obj->ref_cnt = %d; expected: 42",
262 obj->ref_cnt);
264 obj->ref_cnt = 23;
265 sdb_object_deref(obj);
266 fail_unless(obj->ref_cnt == 22,
267 "after db_object_deref(): obj->ref_cnt = %d; expected: 22",
268 obj->ref_cnt);
270 fail_unless(init_noop_called == 1,
271 "after some sdb_object_{de,}ref(); object's init called %d times; "
272 "expected: 1", init_noop_called);
273 fail_unless(destroy_noop_called == 0,
274 "after some sdb_object_{de,}ref(); object's destroy called "
275 "%d time%s; expected: 0", destroy_noop_called == 1 ? "" : "2",
276 destroy_noop_called);
278 obj->ref_cnt = 1;
279 sdb_object_deref(obj);
280 fail_unless(init_noop_called == 1,
281 "after some sdb_object_{de,}ref(); object's init called %d times; "
282 "expected: 1", init_noop_called);
283 fail_unless(destroy_noop_called == 1,
284 "after some sdb_object_{de,}ref(); object's destroy called "
285 "%d times; expected: 1", destroy_noop_called);
287 /* this should work */
288 sdb_object_deref(NULL);
289 }
290 END_TEST
292 START_TEST(test_obj_cmp)
293 {
294 sdb_object_t *obj1, *obj2, *obj3, *obj4;
295 int status;
297 obj1 = sdb_object_create("a", noop_type);
298 obj2 = sdb_object_create("b", noop_type);
299 obj3 = sdb_object_create("B", noop_type);
300 obj4 = sdb_object_create("c", noop_type);
302 status = sdb_object_cmp_by_name(obj1, obj2);
303 fail_unless(status == -1,
304 "sdb_object_cmp_by_name('a', 'b') = %d; expected: -1", status);
305 status = sdb_object_cmp_by_name(obj2, obj3);
306 fail_unless(status == 0,
307 "sdb_object_cmp_by_name('b', 'B') = %d; expected: 0", status);
308 status = sdb_object_cmp_by_name(obj4, obj3);
309 fail_unless(status == 1,
310 "sdb_object_cmp_by_name('c', 'B') = %d; expected: 1", status);
311 status = sdb_object_cmp_by_name(obj1, obj1);
312 fail_unless(status == 0,
313 "sdb_object_cmp_by_name('a', 'a') = %d; expected: 0", status);
315 sdb_object_deref(obj1);
316 sdb_object_deref(obj2);
317 sdb_object_deref(obj3);
318 sdb_object_deref(obj4);
319 }
320 END_TEST
322 Suite *
323 core_object_suite(void)
324 {
325 Suite *s = suite_create("core::object");
326 TCase *tc;
328 tc = tcase_create("core");
329 tcase_add_test(tc, test_obj_create);
330 tcase_add_test(tc, test_obj_wrapper);
331 tcase_add_test(tc, test_obj_ref);
332 tcase_add_test(tc, test_obj_cmp);
333 suite_add_tcase(s, tc);
335 return s;
336 } /* core_object_suite */
338 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */