2 * Copyright (c) 2010-2016 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Portions Copyright (c) 2010 Apple Inc. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * This is a test of libheimbase functionality. If you make any changes
38 * to libheimbase or to this test you should run it under valgrind with
39 * the following options:
41 * -v --track-fds=yes --num-callers=30 --leak-check=full
43 * and make sure that there are no leaks that don't have
44 * __heim_string_constant() or heim_db_register() in their stack trace.
52 #include <sys/types.h>
67 #include "heimbase-atomics.h"
69 static void HEIM_CALLCONV
70 memory_free(heim_object_t obj
)
79 ptr
= heim_alloc(10, "memory", memory_free
);
89 ptr
= heim_alloc(10, "memory", NULL
);
98 HEIMDAL_MUTEX m
= HEIMDAL_MUTEX_INITIALIZER
;
100 HEIMDAL_MUTEX_lock(&m
);
101 HEIMDAL_MUTEX_unlock(&m
);
102 HEIMDAL_MUTEX_destroy(&m
);
104 HEIMDAL_MUTEX_init(&m
);
105 HEIMDAL_MUTEX_lock(&m
);
106 HEIMDAL_MUTEX_unlock(&m
);
107 HEIMDAL_MUTEX_destroy(&m
);
115 HEIMDAL_RWLOCK l
= HEIMDAL_RWLOCK_INITIALIZER
;
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
);
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
);
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");
154 dict
= heim_dict_create(10);
156 heim_dict_set_value(dict
, a1
, a2
);
157 heim_dict_set_value(dict
, a3
, a4
);
159 heim_dict_delete_key(dict
, a3
);
160 heim_dict_delete_key(dict
, a1
);
173 test_auto_release(void)
175 heim_auto_release_t ar1
, ar2
;
179 ar1
= heim_auto_release_create();
181 s1
= heim_string_create("hejsan");
182 heim_auto_release(s1
);
184 n1
= heim_number_create(1);
185 heim_auto_release(n1
);
187 ar2
= heim_auto_release_create();
189 n1
= heim_number_create(1);
190 heim_auto_release(n1
);
201 heim_string_t s1
, s2
;
202 const char *string
= "hejsan";
204 s1
= heim_string_create(string
);
205 s2
= heim_string_create(string
);
207 if (heim_cmp(s1
, s2
) != 0) {
208 printf("the same string is not the same\n");
224 e
= heim_error_create(10, "foo: %s", "bar");
225 heim_assert(heim_error_get_code(e
) == 10, "error_code != 10");
227 s
= heim_error_copy_string(e
);
228 heim_assert(strcmp(heim_string_get_utf8(s
), "foo: bar") == 0, "msg wrong");
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, \"\"]"),
249 heim_object_t o
, o2
, o3
;
250 heim_string_t k1
= heim_string_create("k1");
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 o2
= heim_json_copy_serialize(o
, 0, NULL
);
257 o3
= heim_json_create(heim_string_get_utf8(o2
), 10, 0, NULL
);
258 heim_assert(heim_json_eq(o
, o3
), "JSON text did not round-trip");
264 * Test string escaping:
266 * - C-like must-escapes
267 * - ASCII control character must-escapes
270 * We test round-tripping. First we parse, then we serialize, then parse,
271 * then compare the second parse to the first for equality.
273 * We do compare serialized forms in spite of their not being canonical.
274 * That means that some changes to serialization can cause failures here.
276 o
= heim_json_create("\""
277 "\\b\\f\\n\\r\\t" /* ASCII C-like escapes */
278 "\x1e" /* ASCII control character w/o C-like escape */
279 "\\u00e1" /* á */
283 "\\uD834\\udd1e" /* U+1D11E, as shown in RFC 7159 */
285 heim_assert(o
!= NULL
, "string");
286 heim_assert(heim_get_tid(o
) == heim_string_get_type_id(), "string-tid");
294 "\xf0\x9d\x84\x9e", heim_string_get_utf8(o
)) == 0, "wrong string");
295 o2
= heim_json_copy_serialize(o
,
297 HEIM_JSON_F_NO_ESCAPE_NON_ASCII
, NULL
);
298 heim_assert(strcmp("\"\\b\\f\\n\\r\\t\\u001Eá߿ࠁ老\\uD834\\uDD1E\"",
299 heim_string_get_utf8(o2
)) == 0,
300 "JSON encoding changed; please check that it is till valid");
301 o3
= heim_json_create(heim_string_get_utf8(o2
), 10, HEIM_JSON_F_STRICT
, NULL
);
302 heim_assert(heim_json_eq(o
, o3
), "JSON text did not round-trip");
307 o
= heim_json_create("\""
308 "\\b\\f\\n\\r\\t" /* ASCII C-like escapes */
309 "\x1e" /* ASCII control character w/o C-like escape */
314 "\\uD834\\udd1e" /* U+1D11E, as shown in RFC 7159 */
316 heim_assert(o
!= NULL
, "string");
317 heim_assert(heim_get_tid(o
) == heim_string_get_type_id(), "string-tid");
325 "\xf0\x9d\x84\x9e", heim_string_get_utf8(o
)) == 0, "wrong string");
326 o2
= heim_json_copy_serialize(o
,
328 HEIM_JSON_F_NO_ESCAPE_NON_ASCII
, NULL
);
329 heim_assert(strcmp("\"\\b\\f\\n\\r\\t\\u001Eá߿ࠁ老\\uD834\\uDD1E\"",
330 heim_string_get_utf8(o2
)) == 0,
331 "JSON encoding changed; please check that it is till valid");
332 o3
= heim_json_create(heim_string_get_utf8(o2
), 10, HEIM_JSON_F_STRICT
, NULL
);
333 heim_assert(heim_json_eq(o
, o3
), "JSON text did not round-trip");
339 * Test HEIM_JSON_F_ESCAPE_NON_ASCII.
341 * Also test that we get escaped non-ASCII because we're in a not-UTF-8
342 * locale, since we setlocale(LC_ALL, "C"), so we should escape non-ASCII
345 o
= heim_json_create("\""
346 "\\b\\f\\n\\r\\t" /* ASCII C-like escapes */
347 "\x1e" /* ASCII control character w/o C-like escape */
352 "\\uD834\\udd1e" /* U+1D11E, as shown in RFC 7159 */
354 heim_assert(o
!= NULL
, "string");
355 heim_assert(heim_get_tid(o
) == heim_string_get_type_id(), "string-tid");
363 "\xf0\x9d\x84\x9e", heim_string_get_utf8(o
)) == 0, "wrong string");
364 o2
= heim_json_copy_serialize(o
,
366 HEIM_JSON_F_ESCAPE_NON_ASCII
, NULL
);
367 heim_assert(strcmp("\"\\b\\f\\n\\r\\t\\u001E\\u00E1\\u07FF\\u0801\\u8001"
369 heim_string_get_utf8(o2
)) == 0,
370 "JSON encoding changed; please check that it is till valid");
372 o2
= heim_json_copy_serialize(o
, HEIM_JSON_F_STRICT
, NULL
);
373 heim_assert(strcmp("\"\\b\\f\\n\\r\\t\\u001E\\u00E1\\u07FF\\u0801\\u8001"
375 heim_string_get_utf8(o2
)) == 0,
376 "JSON encoding changed; please check that it is till valid");
377 o3
= heim_json_create(heim_string_get_utf8(o2
), 10, HEIM_JSON_F_STRICT
, NULL
);
378 heim_assert(heim_json_eq(o
, o3
), "JSON text did not round-trip");
383 /* Test rejection of unescaped ASCII control characters */
384 o
= heim_json_create("\"\b\\f\"", 10, HEIM_JSON_F_STRICT
, NULL
);
385 heim_assert(o
== NULL
, "strict parse accepted bad input");
386 o
= heim_json_create("\"\b\x1e\"", 10, HEIM_JSON_F_STRICT
, NULL
);
387 heim_assert(o
== NULL
, "strict parse accepted bad input");
389 o
= heim_json_create("\"\b\\f\"", 10, 0, NULL
);
390 heim_assert(o
!= NULL
, "string");
391 heim_assert(heim_get_tid(o
) == heim_string_get_type_id(), "string-tid");
392 heim_assert(strcmp("\b\f", heim_string_get_utf8(o
)) == 0, "wrong string");
393 o2
= heim_json_copy_serialize(o
,
395 HEIM_JSON_F_NO_ESCAPE_NON_ASCII
, NULL
);
396 heim_assert(strcmp("\"\\b\\f\"", heim_string_get_utf8(o2
)) == 0,
397 "JSON encoding changed; please check that it is till valid");
398 o3
= heim_json_create(heim_string_get_utf8(o2
), 10, HEIM_JSON_F_STRICT
, NULL
);
399 heim_assert(heim_json_eq(o
, o3
), "JSON text did not round-trip");
404 /* Test bogus backslash escape */
405 o
= heim_json_create("\""
407 "\"", 10, HEIM_JSON_F_STRICT
, NULL
);
408 heim_assert(o
== NULL
, "malformed string accepted");
409 o
= heim_json_create("\""
412 heim_assert(o
!= NULL
, "malformed string rejected (not strict)");
413 heim_assert(heim_get_tid(o
) == heim_string_get_type_id(), "string-tid");
414 heim_assert(strcmp(" ", heim_string_get_utf8(o
)) == 0, "wrong string");
415 o2
= heim_json_copy_serialize(o
,
417 HEIM_JSON_F_NO_ESCAPE_NON_ASCII
, NULL
);
418 heim_assert(strcmp("\" \"", heim_string_get_utf8(o2
)) == 0,
419 "JSON encoding changed; please check that it is till valid");
420 o3
= heim_json_create(heim_string_get_utf8(o2
), 10, HEIM_JSON_F_STRICT
, NULL
);
421 heim_assert(heim_json_eq(o
, o3
), "JSON text did not round-trip");
426 /* Test truncated surrogate encoding (bottom code unit) */
427 o
= heim_json_create("\""
430 "\"", 10, HEIM_JSON_F_STRICT
, NULL
);
431 heim_assert(o
== NULL
, "malformed string accepted");
432 o
= heim_json_create("\""
436 heim_assert(o
!= NULL
, "malformed string rejected (not strict)");
437 heim_assert(heim_get_tid(o
) == heim_string_get_type_id(), "string-tid");
440 "\\uD834\\udd", heim_string_get_utf8(o
)) == 0, "wrong string");
441 o2
= heim_json_copy_serialize(o
,
443 HEIM_JSON_F_NO_ESCAPE_NON_ASCII
, NULL
);
444 heim_assert(strcmp("\"老\\\\uD834\\\\udd\"",
445 heim_string_get_utf8(o2
)) == 0,
446 "JSON encoding changed; please check that it is till valid");
447 o3
= heim_json_create(heim_string_get_utf8(o2
), 10, HEIM_JSON_F_STRICT
, NULL
);
448 heim_assert(heim_json_eq(o
, o3
), "JSON text did not round-trip");
453 /* Test truncated surrogate encodings (top code unit) */
454 o
= heim_json_create("\""
457 "\"", 10, HEIM_JSON_F_STRICT
, NULL
);
458 heim_assert(o
== NULL
, "malformed string accepted");
459 o
= heim_json_create("\""
463 heim_assert(o
!= NULL
, "malformed string rejected (not strict)");
464 heim_assert(heim_get_tid(o
) == heim_string_get_type_id(), "string-tid");
467 "\\uD83", heim_string_get_utf8(o
)) == 0, "wrong string");
468 o2
= heim_json_copy_serialize(o
,
470 HEIM_JSON_F_NO_ESCAPE_NON_ASCII
, NULL
);
471 heim_assert(strcmp("\"老\\\\uD83\"",
472 heim_string_get_utf8(o2
)) == 0,
473 "JSON encoding changed; please check that it is till valid");
474 o3
= heim_json_create(heim_string_get_utf8(o2
), 10, HEIM_JSON_F_STRICT
, NULL
);
475 heim_assert(heim_json_eq(o
, o3
), "JSON text did not round-trip");
481 * Test handling of truncated UTF-8 multi-byte sequences.
483 o
= heim_json_create("\""
486 heim_assert(o
!= NULL
, "malformed string rejected (not strict)");
487 heim_assert(heim_get_tid(o
) == heim_string_get_type_id(), "string-tid");
488 heim_assert(strcmp("\xe8\x80",
489 heim_string_get_utf8(o
)) == 0, "wrong string");
490 o2
= heim_json_copy_serialize(o
,
492 HEIM_JSON_F_NO_ESCAPE_NON_ASCII
, NULL
);
493 heim_assert(o2
== NULL
, "malformed string serialized");
494 o2
= heim_json_copy_serialize(o
, HEIM_JSON_F_NO_ESCAPE_NON_ASCII
, NULL
);
495 o3
= heim_json_create(heim_string_get_utf8(o2
), 10, HEIM_JSON_F_STRICT
, NULL
);
496 heim_assert(o3
== NULL
, "malformed string accepted (not strict)");
497 o3
= heim_json_create(heim_string_get_utf8(o2
), 10, 0, NULL
);
498 heim_assert(strcmp("\xe8\x80",
499 heim_string_get_utf8(o3
)) == 0, "wrong string");
504 /* Test handling of unescaped / embedded newline */
505 o
= heim_json_create("\"\n\"", 10, HEIM_JSON_F_STRICT
, NULL
);
506 heim_assert(o
== NULL
, "malformed string accepted (strict)");
507 o
= heim_json_create("\"\n\"", 10, 0, NULL
);
508 heim_assert(o
!= NULL
, "malformed string rejected (not strict)");
509 heim_assert(heim_get_tid(o
) == heim_string_get_type_id(), "string-tid");
510 heim_assert(strcmp("\n", heim_string_get_utf8(o
)) == 0, "wrong string");
511 o2
= heim_json_copy_serialize(o
, HEIM_JSON_F_STRICT
, NULL
);
512 heim_assert(o2
!= NULL
, "string not serialized");
513 o3
= heim_json_create(heim_string_get_utf8(o2
), 10, HEIM_JSON_F_STRICT
, NULL
);
514 heim_assert(o3
!= NULL
, "string not accepted");
515 heim_assert(strcmp("\n", heim_string_get_utf8(o3
)) == 0, "wrong string");
520 /* Test handling of embedded NULs (must decode as data, not string) */
521 o
= heim_json_create("\"\\u0000\"", 10, HEIM_JSON_F_STRICT
, NULL
);
522 heim_assert(o
!= NULL
, "string with NULs rejected");
523 heim_assert(heim_get_tid(o
) == heim_data_get_type_id(), "data-tid");
524 heim_assert(heim_data_get_length(o
) == 1, "wrong data length");
525 heim_assert(((const char *)heim_data_get_ptr(o
))[0] == '\0',
527 o2
= heim_json_copy_serialize(o
, 0, NULL
);
528 heim_assert(o2
!= NULL
, "data not serialized");
533 * Note that the trailing ']' is not part of the JSON text (which is just a
536 o
= heim_json_create(" \"foo\\\"bar\" ]", 10, 0, NULL
);
537 heim_assert(o
!= NULL
, "string");
538 heim_assert(heim_get_tid(o
) == heim_string_get_type_id(), "string-tid");
539 heim_assert(strcmp("foo\"bar", heim_string_get_utf8(o
)) == 0, "wrong string");
540 o2
= heim_json_copy_serialize(o
, 0, NULL
);
541 o3
= heim_json_create(heim_string_get_utf8(o2
), 10, 0, NULL
);
542 heim_assert(heim_json_eq(o
, o3
), "JSON text did not round-trip");
547 o
= heim_json_create(" { \"key\" : \"value\" }", 10, 0, NULL
);
548 heim_assert(o
!= NULL
, "dict");
549 heim_assert(heim_get_tid(o
) == heim_dict_get_type_id(), "dict-tid");
550 o2
= heim_json_copy_serialize(o
, 0, NULL
);
551 o3
= heim_json_create(heim_string_get_utf8(o2
), 10, 0, NULL
);
552 heim_assert(heim_json_eq(o
, o3
), "JSON text did not round-trip");
558 * heim_json_eq() can't handle dicts with dicts as keys, so we don't check
559 * for round-tripping here
561 o
= heim_json_create("{ { \"k1\" : \"s1\", \"k2\" : \"s2\" } : \"s3\", "
562 "{ \"k3\" : \"s4\" } : -1 }", 10, 0, NULL
);
563 heim_assert(o
!= NULL
, "dict");
564 heim_assert(heim_get_tid(o
) == heim_dict_get_type_id(), "dict-tid");
567 o
= heim_json_create("{ { \"k1\" : \"s1\", \"k2\" : \"s2\" } : \"s3\", "
568 "{ \"k3\" : \"s4\" } : -1 }", 10,
569 HEIM_JSON_F_STRICT_DICT
, NULL
);
570 heim_assert(o
== NULL
, "dict");
572 o
= heim_json_create(" { \"k1\" : \"s1\", \"k2\" : \"s2\" }", 10, 0, NULL
);
573 heim_assert(o
!= NULL
, "dict");
574 heim_assert(heim_get_tid(o
) == heim_dict_get_type_id(), "dict-tid");
575 o2
= heim_dict_copy_value(o
, k1
);
576 heim_assert(heim_get_tid(o2
) == heim_string_get_type_id(), "string-tid");
578 o2
= heim_json_copy_serialize(o
, 0, NULL
);
579 o3
= heim_json_create(heim_string_get_utf8(o2
), 10, 0, NULL
);
580 heim_assert(heim_json_eq(o
, o3
), "JSON text did not round-trip");
585 o
= heim_json_create(" { \"k1\" : { \"k2\" : \"s2\" } }", 10, 0, NULL
);
586 heim_assert(o
!= NULL
, "dict");
587 heim_assert(heim_get_tid(o
) == heim_dict_get_type_id(), "dict-tid");
588 o2
= heim_dict_copy_value(o
, k1
);
589 heim_assert(heim_get_tid(o2
) == heim_dict_get_type_id(), "dict-tid");
591 o2
= heim_json_copy_serialize(o
, 0, NULL
);
592 o3
= heim_json_create(heim_string_get_utf8(o2
), 10, 0, NULL
);
593 heim_assert(heim_json_eq(o
, o3
), "JSON text did not round-trip");
598 o
= heim_json_create("{ \"k1\" : 1 }", 10, 0, NULL
);
599 heim_assert(o
!= NULL
, "array");
600 heim_assert(heim_get_tid(o
) == heim_dict_get_type_id(), "dict-tid");
601 o2
= heim_dict_copy_value(o
, k1
);
602 heim_assert(heim_get_tid(o2
) == heim_number_get_type_id(), "number-tid");
604 o2
= heim_json_copy_serialize(o
, 0, NULL
);
605 o3
= heim_json_create(heim_string_get_utf8(o2
), 10, 0, NULL
);
606 heim_assert(heim_json_eq(o
, o3
), "JSON text did not round-trip");
611 o
= heim_json_create("-10", 10, 0, NULL
);
612 heim_assert(o
!= NULL
, "number");
613 heim_assert(heim_get_tid(o
) == heim_number_get_type_id(), "number-tid");
614 o2
= heim_json_copy_serialize(o
, 0, NULL
);
615 o3
= heim_json_create(heim_string_get_utf8(o2
), 10, 0, NULL
);
616 heim_assert(heim_json_eq(o
, o3
), "JSON text did not round-trip");
621 o
= heim_json_create("99", 10, 0, NULL
);
622 heim_assert(o
!= NULL
, "number");
623 heim_assert(heim_get_tid(o
) == heim_number_get_type_id(), "number-tid");
624 o2
= heim_json_copy_serialize(o
, 0, NULL
);
625 o3
= heim_json_create(heim_string_get_utf8(o2
), 10, 0, NULL
);
626 heim_assert(heim_json_eq(o
, o3
), "JSON text did not round-trip");
631 o
= heim_json_create(" [ 1 ]", 10, 0, NULL
);
632 heim_assert(o
!= NULL
, "array");
633 heim_assert(heim_get_tid(o
) == heim_array_get_type_id(), "array-tid");
634 o2
= heim_json_copy_serialize(o
, 0, NULL
);
635 o3
= heim_json_create(heim_string_get_utf8(o2
), 10, 0, NULL
);
636 heim_assert(heim_json_eq(o
, o3
), "JSON text did not round-trip");
641 o
= heim_json_create(" [ -1 ]", 10, 0, NULL
);
642 heim_assert(o
!= NULL
, "array");
643 heim_assert(heim_get_tid(o
) == heim_array_get_type_id(), "array-tid");
644 o2
= heim_json_copy_serialize(o
, 0, NULL
);
645 o3
= heim_json_create(heim_string_get_utf8(o2
), 10, 0, NULL
);
646 heim_assert(heim_json_eq(o
, o3
), "JSON text did not round-trip");
651 for (i
= 0; i
< (sizeof (j
) / sizeof (j
[0])); i
++) {
652 o
= heim_json_create(j
[i
], 10, 0, NULL
);
654 fprintf(stderr
, "Failed to parse this JSON: %s\n", j
[i
]);
657 o2
= heim_json_copy_serialize(o
, 0, NULL
);
658 o3
= heim_json_create(heim_string_get_utf8(o2
), 10, 0, NULL
);
659 heim_assert(heim_json_eq(o
, o3
), "JSON text did not round-trip");
663 /* Simple fuzz test */
664 for (k
= strlen(j
[i
]) - 1; k
> 0; k
--) {
665 o
= heim_json_create_with_bytes(j
[i
], k
, 10, 0, NULL
);
667 fprintf(stderr
, "Invalid JSON parsed: %.*s\n", (int)k
, j
[i
]);
671 /* Again, but this time make it so valgrind can find invalid accesses */
672 for (k
= strlen(j
[i
]) - 1; k
> 0; k
--) {
673 s
= strndup(j
[i
], k
);
676 o
= heim_json_create(s
, 10, 0, NULL
);
679 fprintf(stderr
, "Invalid JSON parsed: %s\n", j
[i
]);
683 /* Again, but with no NUL termination */
684 for (k
= strlen(j
[i
]) - 1; k
> 0; k
--) {
689 o
= heim_json_create_with_bytes(s
, k
, 10, 0, NULL
);
692 fprintf(stderr
, "Invalid JSON parsed: %s\n", j
[i
]);
706 heim_dict_t dict
= heim_dict_create(11);
707 heim_string_t p1
= heim_string_create("abc");
708 heim_string_t p2a
= heim_string_create("def");
709 heim_string_t p2b
= heim_string_create("DEF");
710 heim_number_t p3
= heim_number_create(0);
711 heim_string_t p4a
= heim_string_create("ghi");
712 heim_string_t p4b
= heim_string_create("GHI");
713 heim_array_t a
= heim_array_create();
714 heim_number_t l1
= heim_number_create(42);
715 heim_number_t l2
= heim_number_create(813);
716 heim_number_t l3
= heim_number_create(1234);
717 heim_string_t k1
= heim_string_create("k1");
718 heim_string_t k2
= heim_string_create("k2");
719 heim_string_t k3
= heim_string_create("k3");
720 heim_string_t k2_1
= heim_string_create("k2-1");
721 heim_string_t k2_2
= heim_string_create("k2-2");
722 heim_string_t k2_3
= heim_string_create("k2-3");
723 heim_string_t k2_4
= heim_string_create("k2-4");
724 heim_string_t k2_5
= heim_string_create("k2-5");
725 heim_string_t k2_5_1
= heim_string_create("k2-5-1");
727 heim_object_t neg_num
;
730 if (!dict
|| !p1
|| !p2a
|| !p2b
|| !p4a
|| !p4b
)
733 ret
= heim_path_create(dict
, 11, a
, NULL
, p1
, p2a
, NULL
);
737 ret
= heim_path_create(dict
, 11, l3
, NULL
, p1
, p2b
, NULL
);
740 o
= heim_path_get(dict
, NULL
, p1
, p2b
, NULL
);
743 ret
= heim_path_create(dict
, 11, NULL
, NULL
, p1
, p2a
, p3
, NULL
);
746 ret
= heim_path_create(dict
, 11, l1
, NULL
, p1
, p2a
, p3
, p4a
, NULL
);
749 ret
= heim_path_create(dict
, 11, l2
, NULL
, p1
, p2a
, p3
, p4b
, NULL
);
753 o
= heim_path_get(dict
, NULL
, p1
, p2a
, p3
, p4a
, NULL
);
756 o
= heim_path_get(dict
, NULL
, p1
, p2a
, p3
, p4b
, NULL
);
762 /* Test that JSON parsing works right by using heim_path_get() */
763 dict
= heim_json_create("{\"k1\":1,"
764 "\"k2\":{\"k2-1\":21,"
768 "\"k2-5\":[1,2,3,{\"k2-5-1\":-1},-2]},"
769 "\"k3\":[true,false,0,42]}", 10, 0, NULL
);
770 heim_assert(dict
!= NULL
, "dict");
771 o
= heim_path_get(dict
, NULL
, k1
, NULL
);
772 if (heim_cmp(o
, heim_number_create(1))) return 1;
773 o
= heim_path_get(dict
, NULL
, k2
, NULL
);
774 if (heim_get_tid(o
) != heim_dict_get_type_id()) return 1;
775 o
= heim_path_get(dict
, NULL
, k2
, k2_1
, NULL
);
776 if (heim_cmp(o
, heim_number_create(21))) return 1;
777 o
= heim_path_get(dict
, NULL
, k2
, k2_2
, NULL
);
778 if (heim_cmp(o
, heim_null_create())) return 1;
779 o
= heim_path_get(dict
, NULL
, k2
, k2_3
, NULL
);
780 if (heim_cmp(o
, heim_bool_create(1))) return 1;
781 o
= heim_path_get(dict
, NULL
, k2
, k2_4
, NULL
);
782 if (heim_cmp(o
, heim_bool_create(0))) return 1;
783 o
= heim_path_get(dict
, NULL
, k2
, k2_5
, NULL
);
784 if (heim_get_tid(o
) != heim_array_get_type_id()) return 1;
785 o
= heim_path_get(dict
, NULL
, k2
, k2_5
, heim_number_create(0), NULL
);
786 if (heim_cmp(o
, heim_number_create(1))) return 1;
787 o
= heim_path_get(dict
, NULL
, k2
, k2_5
, heim_number_create(1), NULL
);
788 if (heim_cmp(o
, heim_number_create(2))) return 1;
789 o
= heim_path_get(dict
, NULL
, k2
, k2_5
, heim_number_create(3), k2_5_1
, NULL
);
790 if (heim_cmp(o
, neg_num
= heim_number_create(-1))) return 1;
791 heim_release(neg_num
);
792 o
= heim_path_get(dict
, NULL
, k2
, k2_5
, heim_number_create(4), NULL
);
793 if (heim_cmp(o
, neg_num
= heim_number_create(-2))) return 1;
794 heim_release(neg_num
);
795 o
= heim_path_get(dict
, NULL
, k3
, heim_number_create(3), NULL
);
796 if (heim_cmp(o
, heim_number_create(42))) return 1;
812 heim_release(k2_5_1
);
817 typedef struct dict_db
{
823 dict_db_open(void *plug
, const char *dbtype
, const char *dbname
,
824 heim_dict_t options
, void **db
, heim_error_t
*error
)
827 heim_dict_t contents
= NULL
;
831 if (dbtype
&& *dbtype
&& strcmp(dbtype
, "dictdb") != 0)
833 if (dbname
&& *dbname
&& strcmp(dbname
, "MEMORY") != 0)
835 dictdb
= heim_alloc(sizeof (*dictdb
), "dict_db", NULL
);
839 if (contents
!= NULL
)
840 dictdb
->dict
= contents
;
842 dictdb
->dict
= heim_dict_create(29);
843 if (dictdb
->dict
== NULL
) {
844 heim_release(dictdb
);
854 dict_db_close(void *db
, heim_error_t
*error
)
856 dict_db_t dictdb
= db
;
860 heim_release(dictdb
->dict
);
861 heim_release(dictdb
);
866 dict_db_lock(void *db
, int read_only
, heim_error_t
*error
)
868 dict_db_t dictdb
= db
;
879 dict_db_unlock(void *db
, heim_error_t
*error
)
881 dict_db_t dictdb
= db
;
890 dict_db_copy_value(void *db
, heim_string_t table
, heim_data_t key
,
893 dict_db_t dictdb
= db
;
898 return heim_retain(heim_path_get(dictdb
->dict
, error
, table
, key
, NULL
));
902 dict_db_set_value(void *db
, heim_string_t table
,
903 heim_data_t key
, heim_data_t value
, heim_error_t
*error
)
905 dict_db_t dictdb
= db
;
913 return heim_path_create(dictdb
->dict
, 29, value
, error
, table
, key
, NULL
);
917 dict_db_del_key(void *db
, heim_string_t table
, heim_data_t key
,
920 dict_db_t dictdb
= db
;
928 heim_path_delete(dictdb
->dict
, error
, table
, key
, NULL
);
932 struct dict_db_iter_ctx
{
933 heim_db_iterator_f_t iter_f
;
937 static void dict_db_iter_f(heim_object_t key
, heim_object_t value
, void *arg
)
939 struct dict_db_iter_ctx
*ctx
= arg
;
941 ctx
->iter_f((heim_object_t
)key
, (heim_object_t
)value
, ctx
->iter_ctx
);
945 dict_db_iter(void *db
, heim_string_t table
, void *iter_data
,
946 heim_db_iterator_f_t iter_f
, heim_error_t
*error
)
948 dict_db_t dictdb
= db
;
949 struct dict_db_iter_ctx ctx
;
950 heim_dict_t table_dict
;
958 table_dict
= heim_dict_copy_value(dictdb
->dict
, table
);
959 if (table_dict
== NULL
)
962 ctx
.iter_ctx
= iter_data
;
965 heim_dict_iterate_f(table_dict
, &ctx
, dict_db_iter_f
);
966 heim_release(table_dict
);
970 test_db_iter(heim_data_t k
, heim_data_t v
, void *arg
)
973 const void *kptr
, *vptr
;
976 heim_assert(heim_get_tid(k
) == heim_data_get_type_id(), "...");
978 kptr
= heim_data_get_ptr(k
);
979 klen
= heim_data_get_length(k
);
980 vptr
= heim_data_get_ptr(v
);
981 vlen
= heim_data_get_length(v
);
983 if (klen
== strlen("msg") && strncmp(kptr
, "msg", strlen("msg")) == 0 &&
984 vlen
== strlen("abc") && strncmp(vptr
, "abc", strlen("abc")) == 0)
986 else if (klen
== strlen("msg2") &&
987 strncmp(kptr
, "msg2", strlen("msg2")) == 0 &&
988 vlen
== strlen("FooBar") &&
989 strncmp(vptr
, "FooBar", strlen("FooBar")) == 0)
995 static struct heim_db_type dbt
= {
996 1, dict_db_open
, NULL
, dict_db_close
,
997 dict_db_lock
, dict_db_unlock
, NULL
, NULL
, NULL
, NULL
,
998 dict_db_copy_value
, dict_db_set_value
,
999 dict_db_del_key
, dict_db_iter
1003 test_db(const char *dbtype
, const char *dbname
)
1005 heim_data_t k1
, k2
, v
, v1
, v2
, v3
;
1009 if (dbtype
== NULL
) {
1010 ret
= heim_db_register("dictdb", NULL
, &dbt
);
1011 heim_assert(!ret
, "...");
1012 db
= heim_db_create("dictdb", "foo", NULL
, NULL
);
1013 heim_assert(!db
, "...");
1014 db
= heim_db_create("foobar", "MEMORY", NULL
, NULL
);
1015 heim_assert(!db
, "...");
1016 db
= heim_db_create("dictdb", "MEMORY", NULL
, NULL
);
1017 heim_assert(db
, "...");
1019 heim_dict_t options
;
1021 options
= heim_dict_create(11);
1022 if (options
== NULL
) return ENOMEM
;
1023 if (heim_dict_set_value(options
, HSTR("journal-filename"),
1024 HSTR("json-journal")))
1026 if (heim_dict_set_value(options
, HSTR("create"), heim_null_create()))
1028 if (heim_dict_set_value(options
, HSTR("truncate"), heim_null_create()))
1030 db
= heim_db_create(dbtype
, dbname
, options
, NULL
);
1031 heim_assert(db
, "...");
1032 heim_release(options
);
1035 k1
= heim_data_create("msg", strlen("msg"));
1036 k2
= heim_data_create("msg2", strlen("msg2"));
1037 v1
= heim_data_create("Hello world!", strlen("Hello world!"));
1038 v2
= heim_data_create("FooBar", strlen("FooBar"));
1039 v3
= heim_data_create("abc", strlen("abc"));
1041 ret
= heim_db_set_value(db
, NULL
, k1
, v1
, NULL
);
1042 heim_assert(!ret
, "...");
1044 v
= heim_db_copy_value(db
, NULL
, k1
, NULL
);
1045 heim_assert(v
&& !heim_cmp(v
, v1
), "...");
1048 ret
= heim_db_set_value(db
, NULL
, k2
, v2
, NULL
);
1049 heim_assert(!ret
, "...");
1051 v
= heim_db_copy_value(db
, NULL
, k2
, NULL
);
1052 heim_assert(v
&& !heim_cmp(v
, v2
), "...");
1055 ret
= heim_db_set_value(db
, NULL
, k1
, v3
, NULL
);
1056 heim_assert(!ret
, "...");
1058 v
= heim_db_copy_value(db
, NULL
, k1
, NULL
);
1059 heim_assert(v
&& !heim_cmp(v
, v3
), "...");
1063 heim_db_iterate_f(db
, NULL
, &ret
, test_db_iter
, NULL
);
1064 heim_assert(!ret
, "...");
1066 ret
= heim_db_begin(db
, 0, NULL
);
1067 heim_assert(!ret
, "...");
1069 ret
= heim_db_commit(db
, NULL
);
1070 heim_assert(!ret
, "...");
1072 ret
= heim_db_begin(db
, 0, NULL
);
1073 heim_assert(!ret
, "...");
1075 ret
= heim_db_rollback(db
, NULL
);
1076 heim_assert(!ret
, "...");
1078 ret
= heim_db_begin(db
, 0, NULL
);
1079 heim_assert(!ret
, "...");
1081 ret
= heim_db_set_value(db
, NULL
, k1
, v1
, NULL
);
1082 heim_assert(!ret
, "...");
1084 v
= heim_db_copy_value(db
, NULL
, k1
, NULL
);
1085 heim_assert(v
&& !heim_cmp(v
, v1
), "...");
1088 ret
= heim_db_rollback(db
, NULL
);
1089 heim_assert(!ret
, "...");
1091 v
= heim_db_copy_value(db
, NULL
, k1
, NULL
);
1092 heim_assert(v
&& !heim_cmp(v
, v3
), "...");
1095 ret
= heim_db_begin(db
, 0, NULL
);
1096 heim_assert(!ret
, "...");
1098 ret
= heim_db_set_value(db
, NULL
, k1
, v1
, NULL
);
1099 heim_assert(!ret
, "...");
1101 v
= heim_db_copy_value(db
, NULL
, k1
, NULL
);
1102 heim_assert(v
&& !heim_cmp(v
, v1
), "...");
1105 ret
= heim_db_commit(db
, NULL
);
1106 heim_assert(!ret
, "...");
1108 v
= heim_db_copy_value(db
, NULL
, k1
, NULL
);
1109 heim_assert(v
&& !heim_cmp(v
, v1
), "...");
1112 ret
= heim_db_begin(db
, 0, NULL
);
1113 heim_assert(!ret
, "...");
1115 ret
= heim_db_delete_key(db
, NULL
, k1
, NULL
);
1116 heim_assert(!ret
, "...");
1118 v
= heim_db_copy_value(db
, NULL
, k1
, NULL
);
1119 heim_assert(v
== NULL
, "...");
1122 ret
= heim_db_rollback(db
, NULL
);
1123 heim_assert(!ret
, "...");
1125 v
= heim_db_copy_value(db
, NULL
, k1
, NULL
);
1126 heim_assert(v
&& !heim_cmp(v
, v1
), "...");
1129 if (dbtype
!= NULL
) {
1130 heim_data_t k3
= heim_data_create("value-is-a-dict", strlen("value-is-a-dict"));
1131 heim_dict_t vdict
= heim_dict_create(11);
1134 heim_assert(k3
&& vdict
, "...");
1135 ret
= heim_dict_set_value(vdict
, HSTR("vdict-k1"), heim_number_create(11));
1136 heim_assert(!ret
, "...");
1137 ret
= heim_dict_set_value(vdict
, HSTR("vdict-k2"), heim_null_create());
1138 heim_assert(!ret
, "...");
1139 ret
= heim_dict_set_value(vdict
, HSTR("vdict-k3"), HSTR("a value"));
1140 heim_assert(!ret
, "...");
1141 ret
= heim_db_set_value(db
, NULL
, k3
, (heim_data_t
)vdict
, NULL
);
1142 heim_assert(!ret
, "...");
1144 heim_release(vdict
);
1146 db2
= heim_db_create(dbtype
, dbname
, NULL
, NULL
);
1147 heim_assert(db2
, "...");
1149 vdict
= (heim_dict_t
)heim_db_copy_value(db2
, NULL
, k3
, NULL
);
1152 heim_assert(vdict
, "...");
1153 heim_assert(heim_get_tid(vdict
) == heim_dict_get_type_id(), "...");
1155 v
= heim_dict_copy_value(vdict
, HSTR("vdict-k1"));
1156 heim_assert(v
&& !heim_cmp(v
, heim_number_create(11)), "...");
1159 v
= heim_dict_copy_value(vdict
, HSTR("vdict-k2"));
1160 heim_assert(v
&& !heim_cmp(v
, heim_null_create()), "...");
1163 v
= heim_dict_copy_value(vdict
, HSTR("vdict-k3"));
1164 heim_assert(v
&& !heim_cmp(v
, HSTR("a value")), "...");
1167 heim_release(vdict
);
1180 struct test_array_iter_ctx
{
1184 static void test_array_iter(heim_object_t elt
, void *arg
, int *stop
)
1186 struct test_array_iter_ctx
*iter_ctx
= arg
;
1188 strcat(iter_ctx
->buf
, heim_string_get_utf8((heim_string_t
)elt
));
1194 struct test_array_iter_ctx iter_ctx
;
1195 heim_string_t s1
= heim_string_create("abc");
1196 heim_string_t s2
= heim_string_create("def");
1197 heim_string_t s3
= heim_string_create("ghi");
1198 heim_string_t s4
= heim_string_create("jkl");
1199 heim_string_t s5
= heim_string_create("mno");
1200 heim_string_t s6
= heim_string_create("pqr");
1201 heim_array_t a
= heim_array_create();
1203 if (!s1
|| !s2
|| !s3
|| !s4
|| !s5
|| !s6
|| !a
)
1206 heim_array_append_value(a
, s4
);
1207 heim_array_append_value(a
, s5
);
1208 heim_array_insert_value(a
, 0, s3
);
1209 heim_array_insert_value(a
, 0, s2
);
1210 heim_array_append_value(a
, s6
);
1211 heim_array_insert_value(a
, 0, s1
);
1213 iter_ctx
.buf
[0] = '\0';
1214 heim_array_iterate_f(a
, &iter_ctx
, test_array_iter
);
1215 if (strcmp(iter_ctx
.buf
, "abcdefghijklmnopqr") != 0)
1218 iter_ctx
.buf
[0] = '\0';
1219 heim_array_delete_value(a
, 2);
1220 heim_array_iterate_f(a
, &iter_ctx
, test_array_iter
);
1221 if (strcmp(iter_ctx
.buf
, "abcdefjklmnopqr") != 0)
1224 iter_ctx
.buf
[0] = '\0';
1225 heim_array_delete_value(a
, 2);
1226 heim_array_iterate_f(a
, &iter_ctx
, test_array_iter
);
1227 if (strcmp(iter_ctx
.buf
, "abcdefmnopqr") != 0)
1230 iter_ctx
.buf
[0] = '\0';
1231 heim_array_delete_value(a
, 0);
1232 heim_array_iterate_f(a
, &iter_ctx
, test_array_iter
);
1233 if (strcmp(iter_ctx
.buf
, "defmnopqr") != 0)
1236 iter_ctx
.buf
[0] = '\0';
1237 heim_array_delete_value(a
, 2);
1238 heim_array_iterate_f(a
, &iter_ctx
, test_array_iter
);
1239 if (strcmp(iter_ctx
.buf
, "defmno") != 0)
1242 heim_array_insert_value(a
, 0, s1
);
1243 iter_ctx
.buf
[0] = '\0';
1244 heim_array_iterate_f(a
, &iter_ctx
, test_array_iter
);
1245 if (strcmp(iter_ctx
.buf
, "abcdefmno") != 0)
1248 heim_array_insert_value(a
, 0, s2
);
1249 iter_ctx
.buf
[0] = '\0';
1250 heim_array_iterate_f(a
, &iter_ctx
, test_array_iter
);
1251 if (strcmp(iter_ctx
.buf
, "defabcdefmno") != 0)
1254 heim_array_append_value(a
, s3
);
1255 iter_ctx
.buf
[0] = '\0';
1256 heim_array_iterate_f(a
, &iter_ctx
, test_array_iter
);
1257 if (strcmp(iter_ctx
.buf
, "defabcdefmnoghi") != 0)
1260 heim_array_append_value(a
, s6
);
1261 iter_ctx
.buf
[0] = '\0';
1262 heim_array_iterate_f(a
, &iter_ctx
, test_array_iter
);
1263 if (strcmp(iter_ctx
.buf
, "defabcdefmnoghipqr") != 0)
1277 /* This function tests only that heimbase-atomics.h compiles */
1281 heim_base_atomic(void *) tptr
;
1282 heim_base_atomic(uint32_t) tu32
;
1283 heim_base_atomic(uint64_t) tu64
;
1285 heim_base_atomic_init(&tptr
, NULL
);
1286 heim_base_atomic_init(&tu32
, 0);
1287 heim_base_atomic_init(&tu64
, 0);
1289 if (heim_base_atomic_load(&tptr
))
1291 if (heim_base_atomic_load(&tu32
))
1293 if (heim_base_atomic_load(&tu64
))
1296 heim_base_atomic_store(&tptr
, &tptr
);
1297 heim_base_atomic_store(&tu32
, 1);
1298 heim_base_atomic_store(&tu64
, 1);
1300 if (heim_base_atomic_load(&tptr
) != &tptr
)
1302 if (heim_base_atomic_load(&tu32
) != 1)
1304 if (heim_base_atomic_load(&tu64
) != 1)
1307 if (heim_base_atomic_inc_32(&tu32
) != 2 ||
1308 heim_base_atomic_load(&tu32
) != 2)
1310 if (heim_base_atomic_inc_64(&tu64
) != 2 ||
1311 heim_base_atomic_load(&tu64
) != 2)
1314 if (heim_base_atomic_dec_32(&tu32
) != 1 ||
1315 heim_base_atomic_load(&tu32
) != 1)
1317 if (heim_base_atomic_dec_64(&tu64
) != 1 ||
1318 heim_base_atomic_load(&tu64
) != 1)
1321 heim_base_exchange_pointer(&tptr
, (void *)&tu32
);
1322 if (heim_base_atomic_load(&tptr
) != &tu32
)
1324 heim_base_exchange_32(&tu32
, 32);
1325 if (heim_base_atomic_load(&tu32
) != 32)
1327 heim_base_exchange_64(&tu64
, 64);
1328 if (heim_base_atomic_load(&tu64
) != 64)
1331 if (heim_base_cas_pointer(&tptr
, (void *)&tu32
, (void *)&tu64
) != &tu32
)
1333 if (heim_base_cas_pointer(&tptr
, (void *)&tu32
, (void *)&tptr
) != &tu64
)
1335 if (heim_base_atomic_load(&tptr
) != (void *)&tu64
)
1338 if (heim_base_cas_32(&tu32
, 32, 4) != 32)
1340 if (heim_base_cas_32(&tu32
, 32, 4) != 4)
1342 if (heim_base_atomic_load(&tu32
) != 4)
1345 if (heim_base_cas_64(&tu64
, 64, 4) != 64)
1347 if (heim_base_cas_64(&tu64
, 64, 4) != 4)
1349 if (heim_base_atomic_load(&tu64
) != 4)
1356 main(int argc
, char **argv
)
1361 setlocale(LC_ALL
, "C");
1362 heim_assert(!heim_locale_is_utf8(), "setlocale(LC_ALL, \"C\") failed?");
1365 res
|= test_memory();
1366 res
|= test_mutex();
1367 res
|= test_rwlock();
1369 res
|= test_auto_release();
1370 res
|= test_string();
1371 res
|= test_error();
1374 res
|= test_db(NULL
, NULL
);
1375 res
|= test_db("json", argc
> 1 ? argv
[1] : "test_db.json");
1376 res
|= test_array();
1377 res
|= test_atomics();