xref: /netbsd-src/crypto/external/bsd/heimdal/dist/lib/base/test_base.c (revision d3273b5b76f5afaafe308cead5511dbb8df8c5e9)
1 /*	$NetBSD: test_base.c,v 1.2 2017/01/28 21:31:45 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 2010-2016 Kungliga Tekniska Högskolan
5  * (Royal Institute of Technology, Stockholm, Sweden).
6  * All rights reserved.
7  *
8  * Portions Copyright (c) 2010 Apple Inc. All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  *
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  *
21  * 3. Neither the name of the Institute nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  */
37 
38 /*
39  * This is a test of libheimbase functionality.  If you make any changes
40  * to libheimbase or to this test you should run it under valgrind with
41  * the following options:
42  *
43  *  -v --track-fds=yes --num-callers=30 --leak-check=full
44  *
45  * and make sure that there are no leaks that don't have
46  * __heim_string_constant() or heim_db_register() in their stack trace.
47  */
48 
49 #include <err.h>
50 #include <errno.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <sys/types.h>
55 #include <sys/stat.h>
56 #ifndef WIN32
57 #include <sys/file.h>
58 #endif
59 #ifdef HAVE_IO_H
60 #include <io.h>
61 #endif
62 #ifdef HAVE_UNISTD_H
63 #include <unistd.h>
64 #endif
65 #include <fcntl.h>
66 
67 #include "baselocl.h"
68 
69 static void
memory_free(heim_object_t obj)70 memory_free(heim_object_t obj)
71 {
72 }
73 
74 static int
test_memory(void)75 test_memory(void)
76 {
77     void *ptr;
78 
79     ptr = heim_alloc(10, "memory", memory_free);
80 
81     heim_retain(ptr);
82     heim_release(ptr);
83 
84     heim_retain(ptr);
85     heim_release(ptr);
86 
87     heim_release(ptr);
88 
89     ptr = heim_alloc(10, "memory", NULL);
90     heim_release(ptr);
91 
92     return 0;
93 }
94 
95 static int
test_mutex(void)96 test_mutex(void)
97 {
98     HEIMDAL_MUTEX m = HEIMDAL_MUTEX_INITIALIZER;
99 
100     HEIMDAL_MUTEX_lock(&m);
101     HEIMDAL_MUTEX_unlock(&m);
102     HEIMDAL_MUTEX_destroy(&m);
103 
104     HEIMDAL_MUTEX_init(&m);
105     HEIMDAL_MUTEX_lock(&m);
106     HEIMDAL_MUTEX_unlock(&m);
107     HEIMDAL_MUTEX_destroy(&m);
108 
109     return 0;
110 }
111 
112 static int
test_rwlock(void)113 test_rwlock(void)
114 {
115     HEIMDAL_RWLOCK l = HEIMDAL_RWLOCK_INITIALIZER;
116 
117     HEIMDAL_RWLOCK_rdlock(&l);
118     HEIMDAL_RWLOCK_unlock(&l);
119     HEIMDAL_RWLOCK_wrlock(&l);
120     HEIMDAL_RWLOCK_unlock(&l);
121     if (HEIMDAL_RWLOCK_trywrlock(&l) != 0)
122 	err(1, "HEIMDAL_RWLOCK_trywrlock() failed with lock not held");
123     HEIMDAL_RWLOCK_unlock(&l);
124     if (HEIMDAL_RWLOCK_tryrdlock(&l))
125 	err(1, "HEIMDAL_RWLOCK_tryrdlock() failed with lock not held");
126     HEIMDAL_RWLOCK_unlock(&l);
127     HEIMDAL_RWLOCK_destroy(&l);
128 
129     HEIMDAL_RWLOCK_init(&l);
130     HEIMDAL_RWLOCK_rdlock(&l);
131     HEIMDAL_RWLOCK_unlock(&l);
132     HEIMDAL_RWLOCK_wrlock(&l);
133     HEIMDAL_RWLOCK_unlock(&l);
134     if (HEIMDAL_RWLOCK_trywrlock(&l))
135 	err(1, "HEIMDAL_RWLOCK_trywrlock() failed with lock not held");
136     HEIMDAL_RWLOCK_unlock(&l);
137     if (HEIMDAL_RWLOCK_tryrdlock(&l))
138 	err(1, "HEIMDAL_RWLOCK_tryrdlock() failed with lock not held");
139     HEIMDAL_RWLOCK_unlock(&l);
140     HEIMDAL_RWLOCK_destroy(&l);
141 
142     return 0;
143 }
144 
145 static int
test_dict(void)146 test_dict(void)
147 {
148     heim_dict_t dict;
149     heim_number_t a1 = heim_number_create(1);
150     heim_string_t a2 = heim_string_create("hejsan");
151     heim_number_t a3 = heim_number_create(3);
152     heim_string_t a4 = heim_string_create("foosan");
153 
154     dict = heim_dict_create(10);
155 
156     heim_dict_set_value(dict, a1, a2);
157     heim_dict_set_value(dict, a3, a4);
158 
159     heim_dict_delete_key(dict, a3);
160     heim_dict_delete_key(dict, a1);
161 
162     heim_release(a1);
163     heim_release(a2);
164     heim_release(a3);
165     heim_release(a4);
166 
167     heim_release(dict);
168 
169     return 0;
170 }
171 
172 static int
test_auto_release(void)173 test_auto_release(void)
174 {
175     heim_auto_release_t ar1, ar2;
176     heim_number_t n1;
177     heim_string_t s1;
178 
179     ar1 = heim_auto_release_create();
180 
181     s1 = heim_string_create("hejsan");
182     heim_auto_release(s1);
183 
184     n1 = heim_number_create(1);
185     heim_auto_release(n1);
186 
187     ar2 = heim_auto_release_create();
188 
189     n1 = heim_number_create(1);
190     heim_auto_release(n1);
191 
192     heim_release(ar2);
193     heim_release(ar1);
194 
195     return 0;
196 }
197 
198 static int
test_string(void)199 test_string(void)
200 {
201     heim_string_t s1, s2;
202     const char *string = "hejsan";
203 
204     s1 = heim_string_create(string);
205     s2 = heim_string_create(string);
206 
207     if (heim_cmp(s1, s2) != 0) {
208 	printf("the same string is not the same\n");
209 	exit(1);
210     }
211 
212     heim_release(s1);
213     heim_release(s2);
214 
215     return 0;
216 }
217 
218 static int
test_error(void)219 test_error(void)
220 {
221     heim_error_t e;
222     heim_string_t s;
223 
224     e = heim_error_create(10, "foo: %s", "bar");
225     heim_assert(heim_error_get_code(e) == 10, "error_code != 10");
226 
227     s = heim_error_copy_string(e);
228     heim_assert(strcmp(heim_string_get_utf8(s), "foo: bar") == 0, "msg wrong");
229 
230     heim_release(s);
231     heim_release(e);
232 
233     return 0;
234 }
235 
236 static int
test_json(void)237 test_json(void)
238 {
239     static char *j[] = {
240 	"{ \"k1\" : \"s1\", \"k2\" : \"s2\" }",
241 	"{ \"k1\" : [\"s1\", \"s2\", \"s3\"], \"k2\" : \"s3\" }",
242 	"{ \"k1\" : {\"k2\":\"s1\",\"k3\":\"s2\",\"k4\":\"s3\"}, \"k5\" : \"s4\" }",
243 	"[ \"v1\", \"v2\", [\"v3\",\"v4\",[\"v 5\",\" v 7 \"]], -123456789, "
244 	    "null, true, false, 123456789, \"\"]",
245 	" -1"
246     };
247     char *s;
248     size_t i, k;
249     heim_object_t o, o2;
250     heim_string_t k1 = heim_string_create("k1");
251 
252     o = heim_json_create("\"string\"", 10, 0, NULL);
253     heim_assert(o != NULL, "string");
254     heim_assert(heim_get_tid(o) == heim_string_get_type_id(), "string-tid");
255     heim_assert(strcmp("string", heim_string_get_utf8(o)) == 0, "wrong string");
256     heim_release(o);
257 
258     o = heim_json_create(" \"foo\\\"bar\" ]", 10, 0, NULL);
259     heim_assert(o != NULL, "string");
260     heim_assert(heim_get_tid(o) == heim_string_get_type_id(), "string-tid");
261     heim_assert(strcmp("foo\"bar", heim_string_get_utf8(o)) == 0, "wrong string");
262     heim_release(o);
263 
264     o = heim_json_create(" { \"key\" : \"value\" }", 10, 0, NULL);
265     heim_assert(o != NULL, "dict");
266     heim_assert(heim_get_tid(o) == heim_dict_get_type_id(), "dict-tid");
267     heim_release(o);
268 
269     o = heim_json_create("{ { \"k1\" : \"s1\", \"k2\" : \"s2\" } : \"s3\", "
270 			 "{ \"k3\" : \"s4\" } : -1 }", 10, 0, NULL);
271     heim_assert(o != NULL, "dict");
272     heim_assert(heim_get_tid(o) == heim_dict_get_type_id(), "dict-tid");
273     heim_release(o);
274 
275     o = heim_json_create("{ { \"k1\" : \"s1\", \"k2\" : \"s2\" } : \"s3\", "
276 			 "{ \"k3\" : \"s4\" } : -1 }", 10,
277 			 HEIM_JSON_F_STRICT_DICT, NULL);
278     heim_assert(o == NULL, "dict");
279 
280     o = heim_json_create(" { \"k1\" : \"s1\", \"k2\" : \"s2\" }", 10, 0, NULL);
281     heim_assert(o != NULL, "dict");
282     heim_assert(heim_get_tid(o) == heim_dict_get_type_id(), "dict-tid");
283     o2 = heim_dict_copy_value(o, k1);
284     heim_assert(heim_get_tid(o2) == heim_string_get_type_id(), "string-tid");
285     heim_release(o2);
286     heim_release(o);
287 
288     o = heim_json_create(" { \"k1\" : { \"k2\" : \"s2\" } }", 10, 0, NULL);
289     heim_assert(o != NULL, "dict");
290     heim_assert(heim_get_tid(o) == heim_dict_get_type_id(), "dict-tid");
291     o2 = heim_dict_copy_value(o, k1);
292     heim_assert(heim_get_tid(o2) == heim_dict_get_type_id(), "dict-tid");
293     heim_release(o2);
294     heim_release(o);
295 
296     o = heim_json_create("{ \"k1\" : 1 }", 10, 0, NULL);
297     heim_assert(o != NULL, "array");
298     heim_assert(heim_get_tid(o) == heim_dict_get_type_id(), "dict-tid");
299     o2 = heim_dict_copy_value(o, k1);
300     heim_assert(heim_get_tid(o2) == heim_number_get_type_id(), "number-tid");
301     heim_release(o2);
302     heim_release(o);
303 
304     o = heim_json_create("-10", 10, 0, NULL);
305     heim_assert(o != NULL, "number");
306     heim_assert(heim_get_tid(o) == heim_number_get_type_id(), "number-tid");
307     heim_release(o);
308 
309     o = heim_json_create("99", 10, 0, NULL);
310     heim_assert(o != NULL, "number");
311     heim_assert(heim_get_tid(o) == heim_number_get_type_id(), "number-tid");
312     heim_release(o);
313 
314     o = heim_json_create(" [ 1 ]", 10, 0, NULL);
315     heim_assert(o != NULL, "array");
316     heim_assert(heim_get_tid(o) == heim_array_get_type_id(), "array-tid");
317     heim_release(o);
318 
319     o = heim_json_create(" [ -1 ]", 10, 0, NULL);
320     heim_assert(o != NULL, "array");
321     heim_assert(heim_get_tid(o) == heim_array_get_type_id(), "array-tid");
322     heim_release(o);
323 
324     for (i = 0; i < (sizeof (j) / sizeof (j[0])); i++) {
325 	o = heim_json_create(j[i], 10, 0, NULL);
326 	if (o == NULL) {
327 	    fprintf(stderr, "Failed to parse this JSON: %s\n", j[i]);
328 	    return 1;
329 	}
330 	heim_release(o);
331 	/* Simple fuzz test */
332 	for (k = strlen(j[i]) - 1; k > 0; k--) {
333 	    o = heim_json_create_with_bytes(j[i], k, 10, 0, NULL);
334 	    if (o != NULL) {
335 		fprintf(stderr, "Invalid JSON parsed: %.*s\n", (int)k, j[i]);
336 		return EINVAL;
337 	    }
338 	}
339 	/* Again, but this time make it so valgrind can find invalid accesses */
340 	for (k = strlen(j[i]) - 1; k > 0; k--) {
341 	    s = strndup(j[i], k);
342 	    if (s == NULL)
343 		return ENOMEM;
344 	    o = heim_json_create(s, 10, 0, NULL);
345 	    free(s);
346 	    if (o != NULL) {
347 		fprintf(stderr, "Invalid JSON parsed: %s\n", j[i]);
348 		return EINVAL;
349 	    }
350 	}
351 	/* Again, but with no NUL termination */
352 	for (k = strlen(j[i]) - 1; k > 0; k--) {
353 	    s = malloc(k);
354 	    if (s == NULL)
355 		return ENOMEM;
356 	    memcpy(s, j[i], k);
357 	    o = heim_json_create_with_bytes(s, k, 10, 0, NULL);
358 	    free(s);
359 	    if (o != NULL) {
360 		fprintf(stderr, "Invalid JSON parsed: %s\n", j[i]);
361 		return EINVAL;
362 	    }
363 	}
364     }
365 
366     heim_release(k1);
367 
368     return 0;
369 }
370 
371 static int
test_path(void)372 test_path(void)
373 {
374     heim_dict_t dict = heim_dict_create(11);
375     heim_string_t p1 = heim_string_create("abc");
376     heim_string_t p2a = heim_string_create("def");
377     heim_string_t p2b = heim_string_create("DEF");
378     heim_number_t p3 = heim_number_create(0);
379     heim_string_t p4a = heim_string_create("ghi");
380     heim_string_t p4b = heim_string_create("GHI");
381     heim_array_t a = heim_array_create();
382     heim_number_t l1 = heim_number_create(42);
383     heim_number_t l2 = heim_number_create(813);
384     heim_number_t l3 = heim_number_create(1234);
385     heim_string_t k1 = heim_string_create("k1");
386     heim_string_t k2 = heim_string_create("k2");
387     heim_string_t k3 = heim_string_create("k3");
388     heim_string_t k2_1 = heim_string_create("k2-1");
389     heim_string_t k2_2 = heim_string_create("k2-2");
390     heim_string_t k2_3 = heim_string_create("k2-3");
391     heim_string_t k2_4 = heim_string_create("k2-4");
392     heim_string_t k2_5 = heim_string_create("k2-5");
393     heim_string_t k2_5_1 = heim_string_create("k2-5-1");
394     heim_object_t o;
395     heim_object_t neg_num;
396     int ret;
397 
398     if (!dict || !p1 || !p2a || !p2b || !p4a || !p4b)
399 	return ENOMEM;
400 
401     ret = heim_path_create(dict, 11, a, NULL, p1, p2a, NULL);
402     heim_release(a);
403     if (ret)
404 	return ret;
405     ret = heim_path_create(dict, 11, l3, NULL, p1, p2b, NULL);
406     if (ret)
407 	return ret;
408     o = heim_path_get(dict, NULL, p1, p2b, NULL);
409     if (o != l3)
410 	return 1;
411     ret = heim_path_create(dict, 11, NULL, NULL, p1, p2a, p3, NULL);
412     if (ret)
413 	return ret;
414     ret = heim_path_create(dict, 11, l1, NULL, p1, p2a, p3, p4a, NULL);
415     if (ret)
416 	return ret;
417     ret = heim_path_create(dict, 11, l2, NULL, p1, p2a, p3, p4b, NULL);
418     if (ret)
419 	return ret;
420 
421     o = heim_path_get(dict, NULL, p1, p2a, p3, p4a, NULL);
422     if (o != l1)
423 	return 1;
424     o = heim_path_get(dict, NULL, p1, p2a, p3, p4b, NULL);
425     if (o != l2)
426 	return 1;
427 
428     heim_release(dict);
429 
430     /* Test that JSON parsing works right by using heim_path_get() */
431     dict = heim_json_create("{\"k1\":1,"
432 			    "\"k2\":{\"k2-1\":21,"
433 				    "\"k2-2\":null,"
434 				    "\"k2-3\":true,"
435 				    "\"k2-4\":false,"
436 				    "\"k2-5\":[1,2,3,{\"k2-5-1\":-1},-2]},"
437 			    "\"k3\":[true,false,0,42]}", 10, 0, NULL);
438     heim_assert(dict != NULL, "dict");
439     o = heim_path_get(dict, NULL, k1, NULL);
440     if (heim_cmp(o, heim_number_create(1))) return 1;
441     o = heim_path_get(dict, NULL, k2, NULL);
442     if (heim_get_tid(o) != heim_dict_get_type_id()) return 1;
443     o = heim_path_get(dict, NULL, k2, k2_1, NULL);
444     if (heim_cmp(o, heim_number_create(21))) return 1;
445     o = heim_path_get(dict, NULL, k2, k2_2, NULL);
446     if (heim_cmp(o, heim_null_create())) return 1;
447     o = heim_path_get(dict, NULL, k2, k2_3, NULL);
448     if (heim_cmp(o, heim_bool_create(1))) return 1;
449     o = heim_path_get(dict, NULL, k2, k2_4, NULL);
450     if (heim_cmp(o, heim_bool_create(0))) return 1;
451     o = heim_path_get(dict, NULL, k2, k2_5, NULL);
452     if (heim_get_tid(o) != heim_array_get_type_id()) return 1;
453     o = heim_path_get(dict, NULL, k2, k2_5, heim_number_create(0), NULL);
454     if (heim_cmp(o, heim_number_create(1))) return 1;
455     o = heim_path_get(dict, NULL, k2, k2_5, heim_number_create(1), NULL);
456     if (heim_cmp(o, heim_number_create(2))) return 1;
457     o = heim_path_get(dict, NULL, k2, k2_5, heim_number_create(3), k2_5_1, NULL);
458     if (heim_cmp(o, neg_num = heim_number_create(-1))) return 1;
459     heim_release(neg_num);
460     o = heim_path_get(dict, NULL, k2, k2_5, heim_number_create(4), NULL);
461     if (heim_cmp(o, neg_num = heim_number_create(-2))) return 1;
462     heim_release(neg_num);
463     o = heim_path_get(dict, NULL, k3, heim_number_create(3), NULL);
464     if (heim_cmp(o, heim_number_create(42))) return 1;
465 
466     heim_release(dict);
467     heim_release(p1);
468     heim_release(p2a);
469     heim_release(p2b);
470     heim_release(p4a);
471     heim_release(p4b);
472     heim_release(k1);
473     heim_release(k2);
474     heim_release(k3);
475     heim_release(k2_1);
476     heim_release(k2_2);
477     heim_release(k2_3);
478     heim_release(k2_4);
479     heim_release(k2_5);
480     heim_release(k2_5_1);
481 
482     return 0;
483 }
484 
485 typedef struct dict_db {
486     heim_dict_t dict;
487     int locked;
488 } *dict_db_t;
489 
490 static int
dict_db_open(void * plug,const char * dbtype,const char * dbname,heim_dict_t options,void ** db,heim_error_t * error)491 dict_db_open(void *plug, const char *dbtype, const char *dbname,
492 	     heim_dict_t options, void **db, heim_error_t *error)
493 {
494     dict_db_t dictdb;
495     heim_dict_t contents = NULL;
496 
497     if (error)
498 	*error = NULL;
499     if (dbtype && *dbtype && strcmp(dbtype, "dictdb"))
500 	return EINVAL;
501     if (dbname && *dbname && strcmp(dbname, "MEMORY") != 0)
502 	return EINVAL;
503     dictdb = heim_alloc(sizeof (*dictdb), "dict_db", NULL);
504     if (dictdb == NULL)
505 	return ENOMEM;
506 
507     if (contents != NULL)
508 	dictdb->dict = contents;
509     else {
510 	dictdb->dict = heim_dict_create(29);
511 	if (dictdb->dict == NULL) {
512 	    heim_release(dictdb);
513 	    return ENOMEM;
514 	}
515     }
516 
517     *db = dictdb;
518     return 0;
519 }
520 
521 static int
dict_db_close(void * db,heim_error_t * error)522 dict_db_close(void *db, heim_error_t *error)
523 {
524     dict_db_t dictdb = db;
525 
526     if (error)
527 	*error = NULL;
528     heim_release(dictdb->dict);
529     heim_release(dictdb);
530     return 0;
531 }
532 
533 static int
dict_db_lock(void * db,int read_only,heim_error_t * error)534 dict_db_lock(void *db, int read_only, heim_error_t *error)
535 {
536     dict_db_t dictdb = db;
537 
538     if (error)
539 	*error = NULL;
540     if (dictdb->locked)
541 	return EWOULDBLOCK;
542     dictdb->locked = 1;
543     return 0;
544 }
545 
546 static int
dict_db_unlock(void * db,heim_error_t * error)547 dict_db_unlock(void *db, heim_error_t *error)
548 {
549     dict_db_t dictdb = db;
550 
551     if (error)
552 	*error = NULL;
553     dictdb->locked = 0;
554     return 0;
555 }
556 
557 static heim_data_t
dict_db_copy_value(void * db,heim_string_t table,heim_data_t key,heim_error_t * error)558 dict_db_copy_value(void *db, heim_string_t table, heim_data_t key,
559 		  heim_error_t *error)
560 {
561     dict_db_t dictdb = db;
562 
563     if (error)
564 	*error = NULL;
565 
566     return heim_retain(heim_path_get(dictdb->dict, error, table, key, NULL));
567 }
568 
569 static int
dict_db_set_value(void * db,heim_string_t table,heim_data_t key,heim_data_t value,heim_error_t * error)570 dict_db_set_value(void *db, heim_string_t table,
571 		  heim_data_t key, heim_data_t value, heim_error_t *error)
572 {
573     dict_db_t dictdb = db;
574 
575     if (error)
576 	*error = NULL;
577 
578     if (table == NULL)
579 	table = HSTR("");
580 
581     return heim_path_create(dictdb->dict, 29, value, error, table, key, NULL);
582 }
583 
584 static int
dict_db_del_key(void * db,heim_string_t table,heim_data_t key,heim_error_t * error)585 dict_db_del_key(void *db, heim_string_t table, heim_data_t key,
586 		heim_error_t *error)
587 {
588     dict_db_t dictdb = db;
589 
590     if (error)
591 	*error = NULL;
592 
593     if (table == NULL)
594 	table = HSTR("");
595 
596     heim_path_delete(dictdb->dict, error, table, key, NULL);
597     return 0;
598 }
599 
600 struct dict_db_iter_ctx {
601     heim_db_iterator_f_t        iter_f;
602     void                        *iter_ctx;
603 };
604 
dict_db_iter_f(heim_object_t key,heim_object_t value,void * arg)605 static void dict_db_iter_f(heim_object_t key, heim_object_t value, void *arg)
606 {
607     struct dict_db_iter_ctx *ctx = arg;
608 
609     ctx->iter_f((heim_object_t)key, (heim_object_t)value, ctx->iter_ctx);
610 }
611 
612 static void
dict_db_iter(void * db,heim_string_t table,void * iter_data,heim_db_iterator_f_t iter_f,heim_error_t * error)613 dict_db_iter(void *db, heim_string_t table, void *iter_data,
614 	     heim_db_iterator_f_t iter_f, heim_error_t *error)
615 {
616     dict_db_t dictdb = db;
617     struct dict_db_iter_ctx ctx;
618     heim_dict_t table_dict;
619 
620     if (error)
621 	*error = NULL;
622 
623     if (table == NULL)
624 	table = HSTR("");
625 
626     table_dict = heim_dict_copy_value(dictdb->dict, table);
627     if (table_dict == NULL)
628 	return;
629 
630     ctx.iter_ctx = iter_data;
631     ctx.iter_f = iter_f;
632 
633     heim_dict_iterate_f(table_dict, &ctx, dict_db_iter_f);
634     heim_release(table_dict);
635 }
636 
637 static void
test_db_iter(heim_data_t k,heim_data_t v,void * arg)638 test_db_iter(heim_data_t k, heim_data_t v, void *arg)
639 {
640     int *ret = arg;
641     const void *kptr, *vptr;
642     size_t klen, vlen;
643 
644     heim_assert(heim_get_tid(k) == heim_data_get_type_id(), "...");
645 
646     kptr = heim_data_get_ptr(k);
647     klen = heim_data_get_length(k);
648     vptr = heim_data_get_ptr(v);
649     vlen = heim_data_get_length(v);
650 
651     if (klen == strlen("msg") && !strncmp(kptr, "msg", strlen("msg")) &&
652 	vlen == strlen("abc") && !strncmp(vptr, "abc", strlen("abc")))
653 	*ret &= ~(1);
654     else if (klen == strlen("msg2") &&
655 	!strncmp(kptr, "msg2", strlen("msg2")) &&
656 	vlen == strlen("FooBar") && !strncmp(vptr, "FooBar", strlen("FooBar")))
657 	*ret &= ~(2);
658     else
659 	*ret |= 4;
660 }
661 
662 static struct heim_db_type dbt = {
663     1, dict_db_open, NULL, dict_db_close,
664     dict_db_lock, dict_db_unlock, NULL, NULL, NULL, NULL,
665     dict_db_copy_value, dict_db_set_value,
666     dict_db_del_key, dict_db_iter
667 };
668 
669 static int
test_db(const char * dbtype,const char * dbname)670 test_db(const char *dbtype, const char *dbname)
671 {
672     heim_data_t k1, k2, v, v1, v2, v3;
673     heim_db_t db;
674     int ret;
675 
676     if (dbtype == NULL) {
677 	ret = heim_db_register("dictdb", NULL, &dbt);
678 	heim_assert(!ret, "...");
679 	db = heim_db_create("dictdb", "foo", NULL, NULL);
680 	heim_assert(!db, "...");
681 	db = heim_db_create("foobar", "MEMORY", NULL, NULL);
682 	heim_assert(!db, "...");
683 	db = heim_db_create("dictdb", "MEMORY", NULL, NULL);
684 	heim_assert(db, "...");
685     } else {
686 	heim_dict_t options;
687 
688 	options = heim_dict_create(11);
689 	if (options == NULL) return ENOMEM;
690 	if (heim_dict_set_value(options, HSTR("journal-filename"),
691 				HSTR("json-journal")))
692 	    return ENOMEM;
693 	if (heim_dict_set_value(options, HSTR("create"), heim_null_create()))
694 	    return ENOMEM;
695 	if (heim_dict_set_value(options, HSTR("truncate"), heim_null_create()))
696 	    return ENOMEM;
697 	db = heim_db_create(dbtype, dbname, options, NULL);
698 	heim_assert(db, "...");
699 	heim_release(options);
700     }
701 
702     k1 = heim_data_create("msg", strlen("msg"));
703     k2 = heim_data_create("msg2", strlen("msg2"));
704     v1 = heim_data_create("Hello world!", strlen("Hello world!"));
705     v2 = heim_data_create("FooBar", strlen("FooBar"));
706     v3 = heim_data_create("abc", strlen("abc"));
707 
708     ret = heim_db_set_value(db, NULL, k1, v1, NULL);
709     heim_assert(!ret, "...");
710 
711     v = heim_db_copy_value(db, NULL, k1, NULL);
712     heim_assert(v && !heim_cmp(v, v1), "...");
713     heim_release(v);
714 
715     ret = heim_db_set_value(db, NULL, k2, v2, NULL);
716     heim_assert(!ret, "...");
717 
718     v = heim_db_copy_value(db, NULL, k2, NULL);
719     heim_assert(v && !heim_cmp(v, v2), "...");
720     heim_release(v);
721 
722     ret = heim_db_set_value(db, NULL, k1, v3, NULL);
723     heim_assert(!ret, "...");
724 
725     v = heim_db_copy_value(db, NULL, k1, NULL);
726     heim_assert(v && !heim_cmp(v, v3), "...");
727     heim_release(v);
728 
729     ret = 3;
730     heim_db_iterate_f(db, NULL, &ret, test_db_iter, NULL);
731     heim_assert(!ret, "...");
732 
733     ret = heim_db_begin(db, 0, NULL);
734     heim_assert(!ret, "...");
735 
736     ret = heim_db_commit(db, NULL);
737     heim_assert(!ret, "...");
738 
739     ret = heim_db_begin(db, 0, NULL);
740     heim_assert(!ret, "...");
741 
742     ret = heim_db_rollback(db, NULL);
743     heim_assert(!ret, "...");
744 
745     ret = heim_db_begin(db, 0, NULL);
746     heim_assert(!ret, "...");
747 
748     ret = heim_db_set_value(db, NULL, k1, v1, NULL);
749     heim_assert(!ret, "...");
750 
751     v = heim_db_copy_value(db, NULL, k1, NULL);
752     heim_assert(v && !heim_cmp(v, v1), "...");
753     heim_release(v);
754 
755     ret = heim_db_rollback(db, NULL);
756     heim_assert(!ret, "...");
757 
758     v = heim_db_copy_value(db, NULL, k1, NULL);
759     heim_assert(v && !heim_cmp(v, v3), "...");
760     heim_release(v);
761 
762     ret = heim_db_begin(db, 0, NULL);
763     heim_assert(!ret, "...");
764 
765     ret = heim_db_set_value(db, NULL, k1, v1, NULL);
766     heim_assert(!ret, "...");
767 
768     v = heim_db_copy_value(db, NULL, k1, NULL);
769     heim_assert(v && !heim_cmp(v, v1), "...");
770     heim_release(v);
771 
772     ret = heim_db_commit(db, NULL);
773     heim_assert(!ret, "...");
774 
775     v = heim_db_copy_value(db, NULL, k1, NULL);
776     heim_assert(v && !heim_cmp(v, v1), "...");
777     heim_release(v);
778 
779     ret = heim_db_begin(db, 0, NULL);
780     heim_assert(!ret, "...");
781 
782     ret = heim_db_delete_key(db, NULL, k1, NULL);
783     heim_assert(!ret, "...");
784 
785     v = heim_db_copy_value(db, NULL, k1, NULL);
786     heim_assert(v == NULL, "...");
787     heim_release(v);
788 
789     ret = heim_db_rollback(db, NULL);
790     heim_assert(!ret, "...");
791 
792     v = heim_db_copy_value(db, NULL, k1, NULL);
793     heim_assert(v && !heim_cmp(v, v1), "...");
794     heim_release(v);
795 
796     if (dbtype != NULL) {
797 	heim_data_t k3 = heim_data_create("value-is-a-dict", strlen("value-is-a-dict"));
798 	heim_dict_t vdict = heim_dict_create(11);
799 	heim_db_t db2;
800 
801 	heim_assert(k3 && vdict, "...");
802 	ret = heim_dict_set_value(vdict, HSTR("vdict-k1"), heim_number_create(11));
803 	heim_assert(!ret, "...");
804 	ret = heim_dict_set_value(vdict, HSTR("vdict-k2"), heim_null_create());
805 	heim_assert(!ret, "...");
806 	ret = heim_dict_set_value(vdict, HSTR("vdict-k3"), HSTR("a value"));
807 	heim_assert(!ret, "...");
808 	ret = heim_db_set_value(db, NULL, k3, (heim_data_t)vdict, NULL);
809 	heim_assert(!ret, "...");
810 
811 	heim_release(vdict);
812 
813 	db2 = heim_db_create(dbtype, dbname, NULL, NULL);
814 	heim_assert(db2, "...");
815 
816 	vdict = (heim_dict_t)heim_db_copy_value(db2, NULL, k3, NULL);
817 	heim_release(db2);
818 	heim_release(k3);
819 	heim_assert(vdict, "...");
820 	heim_assert(heim_get_tid(vdict) == heim_dict_get_type_id(), "...");
821 
822 	v = heim_dict_copy_value(vdict, HSTR("vdict-k1"));
823 	heim_assert(v && !heim_cmp(v, heim_number_create(11)), "...");
824 	heim_release(v);
825 
826 	v = heim_dict_copy_value(vdict, HSTR("vdict-k2"));
827 	heim_assert(v && !heim_cmp(v, heim_null_create()), "...");
828 	heim_release(v);
829 
830 	v = heim_dict_copy_value(vdict, HSTR("vdict-k3"));
831 	heim_assert(v && !heim_cmp(v, HSTR("a value")), "...");
832 	heim_release(v);
833 
834 	heim_release(vdict);
835     }
836 
837     heim_release(db);
838     heim_release(k1);
839     heim_release(k2);
840     heim_release(v1);
841     heim_release(v2);
842     heim_release(v3);
843 
844     return 0;
845 }
846 
847 struct test_array_iter_ctx {
848     char buf[256];
849 };
850 
test_array_iter(heim_object_t elt,void * arg,int * stop)851 static void test_array_iter(heim_object_t elt, void *arg, int *stop)
852 {
853     struct test_array_iter_ctx *iter_ctx = arg;
854 
855     strcat(iter_ctx->buf, heim_string_get_utf8((heim_string_t)elt));
856 }
857 
858 static int
test_array()859 test_array()
860 {
861     struct test_array_iter_ctx iter_ctx;
862     heim_string_t s1 = heim_string_create("abc");
863     heim_string_t s2 = heim_string_create("def");
864     heim_string_t s3 = heim_string_create("ghi");
865     heim_string_t s4 = heim_string_create("jkl");
866     heim_string_t s5 = heim_string_create("mno");
867     heim_string_t s6 = heim_string_create("pqr");
868     heim_array_t a = heim_array_create();
869 
870     if (!s1 || !s2 || !s3 || !s4 || !s5 || !s6 || !a)
871 	return ENOMEM;
872 
873     heim_array_append_value(a, s4);
874     heim_array_append_value(a, s5);
875     heim_array_insert_value(a, 0, s3);
876     heim_array_insert_value(a, 0, s2);
877     heim_array_append_value(a, s6);
878     heim_array_insert_value(a, 0, s1);
879 
880     iter_ctx.buf[0] = '\0';
881     heim_array_iterate_f(a, &iter_ctx, test_array_iter);
882     if (strcmp(iter_ctx.buf, "abcdefghijklmnopqr") != 0)
883 	return 1;
884 
885     iter_ctx.buf[0] = '\0';
886     heim_array_delete_value(a, 2);
887     heim_array_iterate_f(a, &iter_ctx, test_array_iter);
888     if (strcmp(iter_ctx.buf, "abcdefjklmnopqr") != 0)
889 	return 1;
890 
891     iter_ctx.buf[0] = '\0';
892     heim_array_delete_value(a, 2);
893     heim_array_iterate_f(a, &iter_ctx, test_array_iter);
894     if (strcmp(iter_ctx.buf, "abcdefmnopqr") != 0)
895 	return 1;
896 
897     iter_ctx.buf[0] = '\0';
898     heim_array_delete_value(a, 0);
899     heim_array_iterate_f(a, &iter_ctx, test_array_iter);
900     if (strcmp(iter_ctx.buf, "defmnopqr") != 0)
901 	return 1;
902 
903     iter_ctx.buf[0] = '\0';
904     heim_array_delete_value(a, 2);
905     heim_array_iterate_f(a, &iter_ctx, test_array_iter);
906     if (strcmp(iter_ctx.buf, "defmno") != 0)
907 	return 1;
908 
909     heim_array_insert_value(a, 0, s1);
910     iter_ctx.buf[0] = '\0';
911     heim_array_iterate_f(a, &iter_ctx, test_array_iter);
912     if (strcmp(iter_ctx.buf, "abcdefmno") != 0)
913 	return 1;
914 
915     heim_array_insert_value(a, 0, s2);
916     iter_ctx.buf[0] = '\0';
917     heim_array_iterate_f(a, &iter_ctx, test_array_iter);
918     if (strcmp(iter_ctx.buf, "defabcdefmno") != 0)
919 	return 1;
920 
921     heim_array_append_value(a, s3);
922     iter_ctx.buf[0] = '\0';
923     heim_array_iterate_f(a, &iter_ctx, test_array_iter);
924     if (strcmp(iter_ctx.buf, "defabcdefmnoghi") != 0)
925 	return 1;
926 
927     heim_array_append_value(a, s6);
928     iter_ctx.buf[0] = '\0';
929     heim_array_iterate_f(a, &iter_ctx, test_array_iter);
930     if (strcmp(iter_ctx.buf, "defabcdefmnoghipqr") != 0)
931 	return 1;
932 
933     heim_release(s1);
934     heim_release(s2);
935     heim_release(s3);
936     heim_release(s4);
937     heim_release(s5);
938     heim_release(s6);
939     heim_release(a);
940 
941     return 0;
942 }
943 
944 int
main(int argc,char ** argv)945 main(int argc, char **argv)
946 {
947     int res = 0;
948 
949     res |= test_memory();
950     res |= test_mutex();
951     res |= test_rwlock();
952     res |= test_dict();
953     res |= test_auto_release();
954     res |= test_string();
955     res |= test_error();
956     res |= test_json();
957     res |= test_path();
958     res |= test_db(NULL, NULL);
959     res |= test_db("json", argc > 1 ? argv[1] : "test_db.json");
960     res |= test_array();
961 
962     return res ? 1 : 0;
963 }
964