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 70 memory_free(heim_object_t obj) 71 { 72 } 73 74 static int 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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