xref: /spdk/test/unit/lib/json/json_write.c/json_write_ut.c (revision 45f7571a08ed25a4d3f9453f4a4ee245835feeb8)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (c) Intel Corporation.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "spdk/stdinc.h"
35 
36 #include "spdk_cunit.h"
37 
38 #include "json_write.c"
39 
40 #include "spdk/util.h"
41 
42 static uint8_t g_buf[1000];
43 static uint8_t *g_write_pos;
44 
45 static int
46 write_cb(void *cb_ctx, const void *data, size_t size)
47 {
48 	size_t buf_free = g_buf + sizeof(g_buf) - g_write_pos;
49 
50 	if (size > buf_free) {
51 		return -1;
52 	}
53 
54 	memcpy(g_write_pos, data, size);
55 	g_write_pos += size;
56 
57 	return 0;
58 }
59 
60 #define BEGIN() \
61 	memset(g_buf, 0, sizeof(g_buf)); \
62 	g_write_pos = g_buf; \
63 	w = spdk_json_write_begin(write_cb, NULL, 0); \
64 	CU_ASSERT_FATAL(w != NULL)
65 
66 #define END(json) \
67 	CU_ASSERT(spdk_json_write_end(w) == 0); \
68 	CU_ASSERT(g_write_pos - g_buf == sizeof(json) - 1); \
69 	CU_ASSERT(memcmp(json, g_buf, sizeof(json) - 1) == 0)
70 
71 #define END_NOCMP() \
72 	CU_ASSERT(spdk_json_write_end(w) == 0)
73 
74 #define END_FAIL() \
75 	CU_ASSERT(spdk_json_write_end(w) < 0)
76 
77 #define VAL_STRING(str) \
78 	CU_ASSERT(spdk_json_write_string_raw(w, str, sizeof(str) - 1) == 0)
79 
80 #define VAL_STRING_FAIL(str) \
81 	CU_ASSERT(spdk_json_write_string_raw(w, str, sizeof(str) - 1) < 0)
82 
83 #define STR_PASS(in, out) \
84 	BEGIN(); VAL_STRING(in); END("\"" out "\"")
85 
86 #define STR_FAIL(in) \
87 	BEGIN(); VAL_STRING_FAIL(in); END_FAIL()
88 
89 #define VAL_NAME(name) \
90 	CU_ASSERT(spdk_json_write_name_raw(w, name, sizeof(name) - 1) == 0)
91 
92 #define VAL_NULL() CU_ASSERT(spdk_json_write_null(w) == 0)
93 #define VAL_TRUE() CU_ASSERT(spdk_json_write_bool(w, true) == 0)
94 #define VAL_FALSE() CU_ASSERT(spdk_json_write_bool(w, false) == 0)
95 
96 #define VAL_INT32(i) CU_ASSERT(spdk_json_write_int32(w, i) == 0);
97 #define VAL_UINT32(u) CU_ASSERT(spdk_json_write_uint32(w, u) == 0);
98 
99 #define VAL_ARRAY_BEGIN() CU_ASSERT(spdk_json_write_array_begin(w) == 0)
100 #define VAL_ARRAY_END() CU_ASSERT(spdk_json_write_array_end(w) == 0)
101 
102 #define VAL_OBJECT_BEGIN() CU_ASSERT(spdk_json_write_object_begin(w) == 0)
103 #define VAL_OBJECT_END() CU_ASSERT(spdk_json_write_object_end(w) == 0)
104 
105 #define VAL(v) CU_ASSERT(spdk_json_write_val(w, v) == 0)
106 
107 static void
108 test_write_literal(void)
109 {
110 	struct spdk_json_write_ctx *w;
111 
112 	BEGIN();
113 	VAL_NULL();
114 	END("null");
115 
116 	BEGIN();
117 	VAL_TRUE();
118 	END("true");
119 
120 	BEGIN();
121 	VAL_FALSE();
122 	END("false");
123 }
124 
125 static void
126 test_write_string_simple(void)
127 {
128 	struct spdk_json_write_ctx *w;
129 
130 	STR_PASS("hello world", "hello world");
131 	STR_PASS(" ", " ");
132 	STR_PASS("~", "~");
133 }
134 
135 static void
136 test_write_string_escapes(void)
137 {
138 	struct spdk_json_write_ctx *w;
139 
140 	/* Two-character escapes */
141 	STR_PASS("\b", "\\b");
142 	STR_PASS("\f", "\\f");
143 	STR_PASS("\n", "\\n");
144 	STR_PASS("\r", "\\r");
145 	STR_PASS("\t", "\\t");
146 	STR_PASS("\"", "\\\"");
147 	STR_PASS("\\", "\\\\");
148 
149 	/* JSON defines an escape for forward slash, but it is optional */
150 	STR_PASS("/", "/");
151 
152 	STR_PASS("hello\nworld", "hello\\nworld");
153 
154 	STR_PASS("\x00", "\\u0000");
155 	STR_PASS("\x01", "\\u0001");
156 	STR_PASS("\x02", "\\u0002");
157 
158 	STR_PASS("\xC3\xB6", "\\u00F6");
159 	STR_PASS("\xE2\x88\x9A", "\\u221A");
160 	STR_PASS("\xEA\xAA\xAA", "\\uAAAA");
161 
162 	/* Surrogate pairs */
163 	STR_PASS("\xF0\x9D\x84\x9E", "\\uD834\\uDD1E");
164 	STR_PASS("\xF0\xA0\x9C\x8E", "\\uD841\\uDF0E");
165 
166 	/* Examples from RFC 3629 */
167 	STR_PASS("\x41\xE2\x89\xA2\xCE\x91\x2E", "A\\u2262\\u0391.");
168 	STR_PASS("\xED\x95\x9C\xEA\xB5\xAD\xEC\x96\xB4", "\\uD55C\\uAD6D\\uC5B4");
169 	STR_PASS("\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E", "\\u65E5\\u672C\\u8A9E");
170 	STR_PASS("\xEF\xBB\xBF\xF0\xA3\x8E\xB4", "\\uFEFF\\uD84C\\uDFB4");
171 
172 	/* UTF-8 edge cases */
173 	STR_PASS("\x7F", "\\u007F");
174 	STR_FAIL("\x80");
175 	STR_FAIL("\xC1");
176 	STR_FAIL("\xC2");
177 	STR_PASS("\xC2\x80", "\\u0080");
178 	STR_PASS("\xC2\xBF", "\\u00BF");
179 	STR_PASS("\xDF\x80", "\\u07C0");
180 	STR_PASS("\xDF\xBF", "\\u07FF");
181 	STR_FAIL("\xDF");
182 	STR_FAIL("\xE0\x80");
183 	STR_FAIL("\xE0\x1F");
184 	STR_FAIL("\xE0\x1F\x80");
185 	STR_FAIL("\xE0");
186 	STR_FAIL("\xE0\xA0");
187 	STR_PASS("\xE0\xA0\x80", "\\u0800");
188 	STR_PASS("\xE0\xA0\xBF", "\\u083F");
189 	STR_FAIL("\xE0\xA0\xC0");
190 	STR_PASS("\xE0\xBF\x80", "\\u0FC0");
191 	STR_PASS("\xE0\xBF\xBF", "\\u0FFF");
192 	STR_FAIL("\xE0\xC0\x80");
193 	STR_FAIL("\xE1");
194 	STR_FAIL("\xE1\x80");
195 	STR_FAIL("\xE1\x7F\x80");
196 	STR_FAIL("\xE1\x80\x7F");
197 	STR_PASS("\xE1\x80\x80", "\\u1000");
198 	STR_PASS("\xE1\x80\xBF", "\\u103F");
199 	STR_PASS("\xE1\xBF\x80", "\\u1FC0");
200 	STR_PASS("\xE1\xBF\xBF", "\\u1FFF");
201 	STR_FAIL("\xE1\xC0\x80");
202 	STR_FAIL("\xE1\x80\xC0");
203 	STR_PASS("\xEF\x80\x80", "\\uF000");
204 	STR_PASS("\xEF\xBF\xBF", "\\uFFFF");
205 	STR_FAIL("\xF0");
206 	STR_FAIL("\xF0\x90");
207 	STR_FAIL("\xF0\x90\x80");
208 	STR_FAIL("\xF0\x80\x80\x80");
209 	STR_FAIL("\xF0\x8F\x80\x80");
210 	STR_PASS("\xF0\x90\x80\x80", "\\uD800\\uDC00");
211 	STR_PASS("\xF0\x90\x80\xBF", "\\uD800\\uDC3F");
212 	STR_PASS("\xF0\x90\xBF\x80", "\\uD803\\uDFC0");
213 	STR_PASS("\xF0\xBF\x80\x80", "\\uD8BC\\uDC00");
214 	STR_FAIL("\xF0\xC0\x80\x80");
215 	STR_FAIL("\xF1");
216 	STR_FAIL("\xF1\x80");
217 	STR_FAIL("\xF1\x80\x80");
218 	STR_FAIL("\xF1\x80\x80\x7F");
219 	STR_PASS("\xF1\x80\x80\x80", "\\uD8C0\\uDC00");
220 	STR_PASS("\xF1\x80\x80\xBF", "\\uD8C0\\uDC3F");
221 	STR_PASS("\xF1\x80\xBF\x80", "\\uD8C3\\uDFC0");
222 	STR_PASS("\xF1\xBF\x80\x80", "\\uD9BC\\uDC00");
223 	STR_PASS("\xF3\x80\x80\x80", "\\uDAC0\\uDC00");
224 	STR_FAIL("\xF3\xC0\x80\x80");
225 	STR_FAIL("\xF3\x80\xC0\x80");
226 	STR_FAIL("\xF3\x80\x80\xC0");
227 	STR_FAIL("\xF4");
228 	STR_FAIL("\xF4\x80");
229 	STR_FAIL("\xF4\x80\x80");
230 	STR_PASS("\xF4\x80\x80\x80", "\\uDBC0\\uDC00");
231 	STR_PASS("\xF4\x8F\x80\x80", "\\uDBFC\\uDC00");
232 	STR_PASS("\xF4\x8F\xBF\xBF", "\\uDBFF\\uDFFF");
233 	STR_FAIL("\xF4\x90\x80\x80");
234 	STR_FAIL("\xF5");
235 	STR_FAIL("\xF5\x80");
236 	STR_FAIL("\xF5\x80\x80");
237 	STR_FAIL("\xF5\x80\x80\x80");
238 	STR_FAIL("\xF5\x80\x80\x80\x80");
239 
240 	/* Overlong encodings */
241 	STR_FAIL("\xC0\x80");
242 
243 	/* Surrogate pairs */
244 	STR_FAIL("\xED\xA0\x80"); /* U+D800 First high surrogate */
245 	STR_FAIL("\xED\xAF\xBF"); /* U+DBFF Last high surrogate */
246 	STR_FAIL("\xED\xB0\x80"); /* U+DC00 First low surrogate */
247 	STR_FAIL("\xED\xBF\xBF"); /* U+DFFF Last low surrogate */
248 	STR_FAIL("\xED\xA1\x8C\xED\xBE\xB4"); /* U+233B4 (invalid surrogate pair encoding) */
249 }
250 
251 static void
252 test_write_number_int32(void)
253 {
254 	struct spdk_json_write_ctx *w;
255 
256 	BEGIN();
257 	VAL_INT32(0);
258 	END("0");
259 
260 	BEGIN();
261 	VAL_INT32(1);
262 	END("1");
263 
264 	BEGIN();
265 	VAL_INT32(123);
266 	END("123");
267 
268 	BEGIN();
269 	VAL_INT32(-123);
270 	END("-123");
271 
272 	BEGIN();
273 	VAL_INT32(2147483647);
274 	END("2147483647");
275 
276 	BEGIN();
277 	VAL_INT32(-2147483648);
278 	END("-2147483648");
279 }
280 
281 static void
282 test_write_number_uint32(void)
283 {
284 	struct spdk_json_write_ctx *w;
285 
286 	BEGIN();
287 	VAL_UINT32(0);
288 	END("0");
289 
290 	BEGIN();
291 	VAL_UINT32(1);
292 	END("1");
293 
294 	BEGIN();
295 	VAL_UINT32(123);
296 	END("123");
297 
298 	BEGIN();
299 	VAL_UINT32(2147483647);
300 	END("2147483647");
301 
302 	BEGIN();
303 	VAL_UINT32(4294967295);
304 	END("4294967295");
305 }
306 
307 static void
308 test_write_array(void)
309 {
310 	struct spdk_json_write_ctx *w;
311 
312 	BEGIN();
313 	VAL_ARRAY_BEGIN();
314 	VAL_ARRAY_END();
315 	END("[]");
316 
317 	BEGIN();
318 	VAL_ARRAY_BEGIN();
319 	VAL_INT32(0);
320 	VAL_ARRAY_END();
321 	END("[0]");
322 
323 	BEGIN();
324 	VAL_ARRAY_BEGIN();
325 	VAL_INT32(0);
326 	VAL_INT32(1);
327 	VAL_ARRAY_END();
328 	END("[0,1]");
329 
330 	BEGIN();
331 	VAL_ARRAY_BEGIN();
332 	VAL_INT32(0);
333 	VAL_INT32(1);
334 	VAL_INT32(2);
335 	VAL_ARRAY_END();
336 	END("[0,1,2]");
337 
338 	BEGIN();
339 	VAL_ARRAY_BEGIN();
340 	VAL_STRING("a");
341 	VAL_ARRAY_END();
342 	END("[\"a\"]");
343 
344 	BEGIN();
345 	VAL_ARRAY_BEGIN();
346 	VAL_STRING("a");
347 	VAL_STRING("b");
348 	VAL_ARRAY_END();
349 	END("[\"a\",\"b\"]");
350 
351 	BEGIN();
352 	VAL_ARRAY_BEGIN();
353 	VAL_STRING("a");
354 	VAL_STRING("b");
355 	VAL_STRING("c");
356 	VAL_ARRAY_END();
357 	END("[\"a\",\"b\",\"c\"]");
358 
359 	BEGIN();
360 	VAL_ARRAY_BEGIN();
361 	VAL_TRUE();
362 	VAL_ARRAY_END();
363 	END("[true]");
364 
365 	BEGIN();
366 	VAL_ARRAY_BEGIN();
367 	VAL_TRUE();
368 	VAL_FALSE();
369 	VAL_ARRAY_END();
370 	END("[true,false]");
371 
372 	BEGIN();
373 	VAL_ARRAY_BEGIN();
374 	VAL_TRUE();
375 	VAL_FALSE();
376 	VAL_TRUE();
377 	VAL_ARRAY_END();
378 	END("[true,false,true]");
379 }
380 
381 static void
382 test_write_object(void)
383 {
384 	struct spdk_json_write_ctx *w;
385 
386 	BEGIN();
387 	VAL_OBJECT_BEGIN();
388 	VAL_OBJECT_END();
389 	END("{}");
390 
391 	BEGIN();
392 	VAL_OBJECT_BEGIN();
393 	VAL_NAME("a");
394 	VAL_INT32(0);
395 	VAL_OBJECT_END();
396 	END("{\"a\":0}");
397 
398 	BEGIN();
399 	VAL_OBJECT_BEGIN();
400 	VAL_NAME("a");
401 	VAL_INT32(0);
402 	VAL_NAME("b");
403 	VAL_INT32(1);
404 	VAL_OBJECT_END();
405 	END("{\"a\":0,\"b\":1}");
406 
407 	BEGIN();
408 	VAL_OBJECT_BEGIN();
409 	VAL_NAME("a");
410 	VAL_INT32(0);
411 	VAL_NAME("b");
412 	VAL_INT32(1);
413 	VAL_NAME("c");
414 	VAL_INT32(2);
415 	VAL_OBJECT_END();
416 	END("{\"a\":0,\"b\":1,\"c\":2}");
417 }
418 
419 static void
420 test_write_nesting(void)
421 {
422 	struct spdk_json_write_ctx *w;
423 
424 	BEGIN();
425 	VAL_ARRAY_BEGIN();
426 	VAL_ARRAY_BEGIN();
427 	VAL_ARRAY_END();
428 	VAL_ARRAY_END();
429 	END("[[]]");
430 
431 	BEGIN();
432 	VAL_ARRAY_BEGIN();
433 	VAL_ARRAY_BEGIN();
434 	VAL_ARRAY_BEGIN();
435 	VAL_ARRAY_END();
436 	VAL_ARRAY_END();
437 	VAL_ARRAY_END();
438 	END("[[[]]]");
439 
440 	BEGIN();
441 	VAL_ARRAY_BEGIN();
442 	VAL_INT32(0);
443 	VAL_ARRAY_BEGIN();
444 	VAL_ARRAY_END();
445 	VAL_ARRAY_END();
446 	END("[0,[]]");
447 
448 	BEGIN();
449 	VAL_ARRAY_BEGIN();
450 	VAL_ARRAY_BEGIN();
451 	VAL_ARRAY_END();
452 	VAL_INT32(0);
453 	VAL_ARRAY_END();
454 	END("[[],0]");
455 
456 	BEGIN();
457 	VAL_ARRAY_BEGIN();
458 	VAL_INT32(0);
459 	VAL_ARRAY_BEGIN();
460 	VAL_INT32(1);
461 	VAL_ARRAY_END();
462 	VAL_INT32(2);
463 	VAL_ARRAY_END();
464 	END("[0,[1],2]");
465 
466 	BEGIN();
467 	VAL_ARRAY_BEGIN();
468 	VAL_INT32(0);
469 	VAL_INT32(1);
470 	VAL_ARRAY_BEGIN();
471 	VAL_INT32(2);
472 	VAL_INT32(3);
473 	VAL_ARRAY_END();
474 	VAL_INT32(4);
475 	VAL_INT32(5);
476 	VAL_ARRAY_END();
477 	END("[0,1,[2,3],4,5]");
478 
479 	BEGIN();
480 	VAL_OBJECT_BEGIN();
481 	VAL_NAME("a");
482 	VAL_OBJECT_BEGIN();
483 	VAL_OBJECT_END();
484 	VAL_OBJECT_END();
485 	END("{\"a\":{}}");
486 
487 	BEGIN();
488 	VAL_OBJECT_BEGIN();
489 	VAL_NAME("a");
490 	VAL_OBJECT_BEGIN();
491 	VAL_NAME("b");
492 	VAL_INT32(0);
493 	VAL_OBJECT_END();
494 	VAL_OBJECT_END();
495 	END("{\"a\":{\"b\":0}}");
496 
497 	BEGIN();
498 	VAL_OBJECT_BEGIN();
499 	VAL_NAME("a");
500 	VAL_ARRAY_BEGIN();
501 	VAL_INT32(0);
502 	VAL_ARRAY_END();
503 	VAL_OBJECT_END();
504 	END("{\"a\":[0]}");
505 
506 	BEGIN();
507 	VAL_ARRAY_BEGIN();
508 	VAL_OBJECT_BEGIN();
509 	VAL_NAME("a");
510 	VAL_INT32(0);
511 	VAL_OBJECT_END();
512 	VAL_ARRAY_END();
513 	END("[{\"a\":0}]");
514 
515 	BEGIN();
516 	VAL_ARRAY_BEGIN();
517 	VAL_OBJECT_BEGIN();
518 	VAL_NAME("a");
519 	VAL_OBJECT_BEGIN();
520 	VAL_NAME("b");
521 	VAL_ARRAY_BEGIN();
522 	VAL_OBJECT_BEGIN();
523 	VAL_NAME("c");
524 	VAL_INT32(1);
525 	VAL_OBJECT_END();
526 	VAL_INT32(2);
527 	VAL_ARRAY_END();
528 	VAL_NAME("d");
529 	VAL_INT32(3);
530 	VAL_OBJECT_END();
531 	VAL_NAME("e");
532 	VAL_INT32(4);
533 	VAL_OBJECT_END();
534 	VAL_INT32(5);
535 	VAL_ARRAY_END();
536 	END("[{\"a\":{\"b\":[{\"c\":1},2],\"d\":3},\"e\":4},5]");
537 
538 	/* Examples from RFC 7159 */
539 	BEGIN();
540 	VAL_OBJECT_BEGIN();
541 	VAL_NAME("Image");
542 	VAL_OBJECT_BEGIN();
543 	VAL_NAME("Width");
544 	VAL_INT32(800);
545 	VAL_NAME("Height");
546 	VAL_INT32(600);
547 	VAL_NAME("Title");
548 	VAL_STRING("View from 15th Floor");
549 	VAL_NAME("Thumbnail");
550 	VAL_OBJECT_BEGIN();
551 	VAL_NAME("Url");
552 	VAL_STRING("http://www.example.com/image/481989943");
553 	VAL_NAME("Height");
554 	VAL_INT32(125);
555 	VAL_NAME("Width");
556 	VAL_INT32(100);
557 	VAL_OBJECT_END();
558 	VAL_NAME("Animated");
559 	VAL_FALSE();
560 	VAL_NAME("IDs");
561 	VAL_ARRAY_BEGIN();
562 	VAL_INT32(116);
563 	VAL_INT32(943);
564 	VAL_INT32(234);
565 	VAL_INT32(38793);
566 	VAL_ARRAY_END();
567 	VAL_OBJECT_END();
568 	VAL_OBJECT_END();
569 	END(
570 		"{\"Image\":"
571 		"{"
572 		"\"Width\":800,"
573 		"\"Height\":600,"
574 		"\"Title\":\"View from 15th Floor\","
575 		"\"Thumbnail\":{"
576 		"\"Url\":\"http://www.example.com/image/481989943\","
577 		"\"Height\":125,"
578 		"\"Width\":100"
579 		"},"
580 		"\"Animated\":false,"
581 		"\"IDs\":[116,943,234,38793]"
582 		"}"
583 		"}");
584 }
585 
586 /* Round-trip parse and write test */
587 static void
588 test_write_val(void)
589 {
590 	struct spdk_json_write_ctx *w;
591 	struct spdk_json_val values[100];
592 	char src[] = "{\"a\":[1,2,3],\"b\":{\"c\":\"d\"},\"e\":true,\"f\":false,\"g\":null}";
593 
594 	CU_ASSERT(spdk_json_parse(src, strlen(src), values, SPDK_COUNTOF(values), NULL,
595 				  SPDK_JSON_PARSE_FLAG_DECODE_IN_PLACE) == 19);
596 
597 	BEGIN();
598 	VAL(values);
599 	END("{\"a\":[1,2,3],\"b\":{\"c\":\"d\"},\"e\":true,\"f\":false,\"g\":null}");
600 }
601 
602 int main(int argc, char **argv)
603 {
604 	CU_pSuite	suite = NULL;
605 	unsigned int	num_failures;
606 
607 	if (CU_initialize_registry() != CUE_SUCCESS) {
608 		return CU_get_error();
609 	}
610 
611 	suite = CU_add_suite("json", NULL, NULL);
612 	if (suite == NULL) {
613 		CU_cleanup_registry();
614 		return CU_get_error();
615 	}
616 
617 	if (
618 		CU_add_test(suite, "write_literal", test_write_literal) == NULL ||
619 		CU_add_test(suite, "write_string_simple", test_write_string_simple) == NULL ||
620 		CU_add_test(suite, "write_string_escapes", test_write_string_escapes) == NULL ||
621 		CU_add_test(suite, "write_number_int32", test_write_number_int32) == NULL ||
622 		CU_add_test(suite, "write_number_uint32", test_write_number_uint32) == NULL ||
623 		CU_add_test(suite, "write_array", test_write_array) == NULL ||
624 		CU_add_test(suite, "write_object", test_write_object) == NULL ||
625 		CU_add_test(suite, "write_nesting", test_write_nesting) == NULL ||
626 		CU_add_test(suite, "write_val", test_write_val) == NULL) {
627 		CU_cleanup_registry();
628 		return CU_get_error();
629 	}
630 
631 	CU_basic_set_mode(CU_BRM_VERBOSE);
632 
633 	CU_basic_run_tests();
634 
635 	num_failures = CU_get_number_of_failures();
636 	CU_cleanup_registry();
637 
638 	return num_failures;
639 }
640