xref: /freebsd/contrib/libucl/tests/test_msgpack.c (revision 18054d0220cfc8df9c9568c437bd6fbb59d53c3c)
1 /*
2  * Copyright (c) 2015, Vsevolod Stakhov
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *	 * Redistributions of source code must retain the above copyright
8  *	   notice, this list of conditions and the following disclaimer.
9  *	 * Redistributions in binary form must reproduce the above copyright
10  *	   notice, this list of conditions and the following disclaimer in the
11  *	   documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16  * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24 
25 #include "ucl.h"
26 #include "ucl_internal.h"
27 #include <ctype.h>
28 
29 static const int niter = 20;
30 static const int ntests = 10;
31 static const int nelt = 20;
32 
33 static int recursion = 0;
34 
35 typedef ucl_object_t* (*ucl_msgpack_test)(void);
36 
37 static ucl_object_t* ucl_test_integer (void);
38 static ucl_object_t* ucl_test_string (void);
39 static ucl_object_t* ucl_test_boolean (void);
40 static ucl_object_t* ucl_test_map (void);
41 static ucl_object_t* ucl_test_array (void);
42 static ucl_object_t* ucl_test_large_map (void);
43 static ucl_object_t* ucl_test_large_array (void);
44 static ucl_object_t* ucl_test_large_string (void);
45 static ucl_object_t* ucl_test_null (void);
46 
47 ucl_msgpack_test tests[] = {
48 		ucl_test_integer,
49 		ucl_test_string,
50 		ucl_test_boolean,
51 		ucl_test_map,
52 		ucl_test_array,
53 		ucl_test_null
54 };
55 
56 #define NTESTS (sizeof(tests) / sizeof(tests[0]))
57 
58 typedef struct
59 {
60 	uint64_t state;
61 	uint64_t inc;
62 } pcg32_random_t;
63 
64 pcg32_random_t rng;
65 
66 /*
67  * From http://www.pcg-random.org/
68  */
69 static uint32_t
70 pcg32_random (void)
71 {
72 	uint64_t oldstate = rng.state;
73 
74 	rng.state = oldstate * 6364136223846793005ULL + (rng.inc | 1);
75 	uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u;
76 	uint32_t rot = oldstate >> 59u;
77 	return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
78 }
79 
80 static const char *
81 random_key (size_t *lenptr)
82 {
83 	static char keybuf[512];
84 	int keylen, i;
85 	char c;
86 
87 	keylen = pcg32_random () % (sizeof (keybuf) - 1) + 1;
88 
89 	for (i = 0; i < keylen; i ++) {
90 		do {
91 			c = pcg32_random () & 0xFF;
92 		} while (!isgraph (c));
93 
94 		keybuf[i] = c;
95 	}
96 
97 	*lenptr = keylen;
98 	return keybuf;
99 }
100 
101 int
102 main (int argc, char **argv)
103 {
104 	int fd, i, j;
105 	uint32_t sel;
106 	ucl_object_t *obj, *elt;
107 	struct ucl_parser *parser;
108 	size_t klen, elen, elen2;
109 	const char *key;
110 	unsigned char *emitted, *emitted2;
111 	FILE *out;
112 	const char *fname_out = NULL;
113 
114 	switch (argc) {
115 	case 2:
116 		fname_out = argv[1];
117 		break;
118 	}
119 
120 	/* Seed prng */
121 	fd = open ("/dev/urandom", O_RDONLY);
122 	assert (fd != -1);
123 	assert (read (fd, &rng, sizeof (rng)) == sizeof (rng));
124 	close (fd);
125 
126 	for (i = 0; i < niter; i ++) {
127 		if (fname_out != NULL) {
128 			out = fopen (fname_out, "w");
129 			if (out == NULL) {
130 				exit (-errno);
131 			}
132 		}
133 		else {
134 			out = NULL;
135 		}
136 
137 		/* Generate phase */
138 		obj = ucl_object_typed_new (UCL_OBJECT);
139 
140 		for (j = 0; j < ntests; j ++) {
141 			sel = pcg32_random () % NTESTS;
142 
143 			key = random_key (&klen);
144 			recursion = 0;
145 			elt = tests[sel]();
146 			assert (elt != NULL);
147 			assert (klen != 0);
148 
149 			ucl_object_insert_key (obj, elt, key, klen, true);
150 		}
151 
152 		key = random_key (&klen);
153 		elt = ucl_test_large_array ();
154 		ucl_object_insert_key (obj, elt, key, klen, true);
155 
156 		key = random_key (&klen);
157 		elt = ucl_test_large_map ();
158 		ucl_object_insert_key (obj, elt, key, klen, true);
159 
160 		key = random_key (&klen);
161 		elt = ucl_test_large_string ();
162 		ucl_object_insert_key (obj, elt, key, klen, true);
163 
164 		emitted = ucl_object_emit_len (obj, UCL_EMIT_MSGPACK, &elen);
165 
166 		assert (emitted != NULL);
167 
168 		if (out) {
169 			fprintf (out, "%*.s\n", (int)elen, emitted);
170 
171 			fclose (out);
172 		}
173 		ucl_object_unref (obj);
174 
175 		parser = ucl_parser_new (0);
176 
177 		if (!ucl_parser_add_chunk_full (parser, emitted, elen, 0,
178 				UCL_DUPLICATE_APPEND, UCL_PARSE_MSGPACK)) {
179 			fprintf (stderr, "error parsing input: %s",
180 					ucl_parser_get_error (parser));
181 			assert (0);
182 		}
183 
184 		obj = ucl_parser_get_object (parser);
185 		assert (obj != NULL);
186 
187 		emitted2 = ucl_object_emit_len (obj, UCL_EMIT_MSGPACK, &elen2);
188 
189 		assert (emitted2 != NULL);
190 		assert (elen2 == elen);
191 		assert (memcmp (emitted, emitted2, elen) == 0);
192 
193 		ucl_parser_free (parser);
194 		ucl_object_unref (obj);
195 		free (emitted);
196 		free (emitted2);
197 	}
198 
199 	return 0;
200 }
201 
202 
203 static ucl_object_t*
204 ucl_test_integer (void)
205 {
206 	ucl_object_t *res;
207 	int count, i;
208 	uint64_t cur;
209 	double curf;
210 
211 	res = ucl_object_typed_new (UCL_ARRAY);
212 	count = pcg32_random () % nelt;
213 
214 	for (i = 0; i < count; i ++) {
215 		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
216 		ucl_array_append (res, ucl_object_fromint (cur % 128));
217 		ucl_array_append (res, ucl_object_fromint (-(cur % 128)));
218 		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
219 		ucl_array_append (res, ucl_object_fromint (cur % UINT16_MAX));
220 		ucl_array_append (res, ucl_object_fromint (-(cur % INT16_MAX)));
221 		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
222 		ucl_array_append (res, ucl_object_fromint (cur % UINT32_MAX));
223 		ucl_array_append (res, ucl_object_fromint (-(cur % INT32_MAX)));
224 		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
225 		ucl_array_append (res, ucl_object_fromint (cur));
226 		ucl_array_append (res, ucl_object_fromint (-cur));
227 		/* Double version */
228 		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
229 		curf = (cur % 128) / 19 * 16;
230 		ucl_array_append (res, ucl_object_fromdouble (curf));
231 		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
232 		curf = -(cur % 128) / 19 * 16;
233 		ucl_array_append (res, ucl_object_fromdouble (curf));
234 		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
235 		curf = (cur % 65536) / 19 * 16;
236 		ucl_array_append (res, ucl_object_fromdouble (curf));
237 		ucl_array_append (res, ucl_object_fromdouble (-curf));
238 		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
239 		curf = (cur % INT32_MAX) / 19 * 16;
240 		ucl_array_append (res, ucl_object_fromdouble (curf));
241 		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
242 		memcpy (&curf, &cur, sizeof (curf));
243 		ucl_array_append (res, ucl_object_fromint (cur));
244 	}
245 
246 	return res;
247 }
248 
249 static ucl_object_t*
250 ucl_test_string (void)
251 {
252 	ucl_object_t *res, *elt;
253 	int count, i;
254 	uint32_t cur_len;
255 	char *str;
256 
257 	res = ucl_object_typed_new (UCL_ARRAY);
258 	count = pcg32_random () % nelt;
259 
260 	for (i = 0; i < count; i ++) {
261 		while ((cur_len = pcg32_random ()) % 128 == 0);
262 
263 		str = malloc (cur_len % 128);
264 		ucl_array_append (res, ucl_object_fromstring_common (str, cur_len % 128,
265 				UCL_STRING_RAW));
266 		free (str);
267 
268 		while ((cur_len = pcg32_random ()) % 512 == 0);
269 		str = malloc (cur_len % 512);
270 		ucl_array_append (res, ucl_object_fromstring_common (str, cur_len % 512,
271 				UCL_STRING_RAW));
272 		free (str);
273 
274 		while ((cur_len = pcg32_random ()) % 128 == 0);
275 		str = malloc (cur_len % 128);
276 		elt = ucl_object_fromstring_common (str, cur_len % 128,
277 				UCL_STRING_RAW);
278 		elt->flags |= UCL_OBJECT_BINARY;
279 		ucl_array_append (res, elt);
280 		free (str);
281 
282 		while ((cur_len = pcg32_random ()) % 512 == 0);
283 		str = malloc (cur_len % 512);
284 		elt = ucl_object_fromstring_common (str, cur_len % 512,
285 				UCL_STRING_RAW);
286 		elt->flags |= UCL_OBJECT_BINARY;
287 		ucl_array_append (res, elt);
288 		free (str);
289 	}
290 
291 	/* One large string */
292 	str = malloc (65537);
293 	elt = ucl_object_fromstring_common (str, 65537,
294 			UCL_STRING_RAW);
295 	elt->flags |= UCL_OBJECT_BINARY;
296 	ucl_array_append (res, elt);
297 	free (str);
298 
299 	return res;
300 }
301 
302 static ucl_object_t*
303 ucl_test_boolean (void)
304 {
305 	ucl_object_t *res;
306 	int count, i;
307 
308 	res = ucl_object_typed_new (UCL_ARRAY);
309 	count = pcg32_random () % nelt;
310 
311 	for (i = 0; i < count; i ++) {
312 		ucl_array_append (res, ucl_object_frombool (pcg32_random () % 2));
313 	}
314 
315 	return res;
316 }
317 
318 static ucl_object_t*
319 ucl_test_map (void)
320 {
321 	ucl_object_t *res, *cur;
322 	int count, i;
323 	uint32_t cur_len, sel;
324 	size_t klen;
325 	const char *key;
326 
327 	res = ucl_object_typed_new (UCL_OBJECT);
328 	count = pcg32_random () % nelt;
329 
330 	recursion ++;
331 
332 	for (i = 0; i < count; i ++) {
333 
334 		if (recursion > 10) {
335 			for (;;) {
336 				sel = pcg32_random () % NTESTS;
337 				if (tests[sel] != ucl_test_map &&
338 						tests[sel] != ucl_test_array) {
339 					break;
340 				}
341 			}
342 		}
343 		else {
344 			sel = pcg32_random () % NTESTS;
345 		}
346 
347 		key = random_key (&klen);
348 		cur = tests[sel]();
349 		assert (cur != NULL);
350 		assert (klen != 0);
351 
352 		ucl_object_insert_key (res, cur, key, klen, true);
353 
354 		/* Multi value key */
355 		cur = tests[sel]();
356 		assert (cur != NULL);
357 
358 		ucl_object_insert_key (res, cur, key, klen, true);
359 	}
360 
361 	return res;
362 }
363 
364 static ucl_object_t*
365 ucl_test_large_map (void)
366 {
367 	ucl_object_t *res, *cur;
368 	int count, i;
369 	uint32_t cur_len;
370 	size_t klen;
371 	const char *key;
372 
373 	res = ucl_object_typed_new (UCL_OBJECT);
374 	count = 65537;
375 
376 	recursion ++;
377 
378 	for (i = 0; i < count; i ++) {
379 		key = random_key (&klen);
380 		cur = ucl_test_boolean ();
381 		assert (cur != NULL);
382 		assert (klen != 0);
383 
384 		ucl_object_insert_key (res, cur, key, klen, true);
385 	}
386 
387 	return res;
388 }
389 
390 static ucl_object_t*
391 ucl_test_array (void)
392 {
393 	ucl_object_t *res, *cur;
394 	int count, i;
395 	uint32_t cur_len, sel;
396 
397 	res = ucl_object_typed_new (UCL_ARRAY);
398 	count = pcg32_random () % nelt;
399 
400 	recursion ++;
401 
402 	for (i = 0; i < count; i ++) {
403 		if (recursion > 10) {
404 			for (;;) {
405 				sel = pcg32_random () % NTESTS;
406 				if (tests[sel] != ucl_test_map &&
407 						tests[sel] != ucl_test_array) {
408 					break;
409 				}
410 			}
411 		}
412 		else {
413 			sel = pcg32_random () % NTESTS;
414 		}
415 
416 		cur = tests[sel]();
417 		assert (cur != NULL);
418 
419 		ucl_array_append (res, cur);
420 	}
421 
422 	return res;
423 }
424 
425 static ucl_object_t*
426 ucl_test_large_array (void)
427 {
428 	ucl_object_t *res, *cur;
429 	int count, i;
430 	uint32_t cur_len;
431 
432 	res = ucl_object_typed_new (UCL_ARRAY);
433 	count = 65537;
434 
435 	recursion ++;
436 
437 	for (i = 0; i < count; i ++) {
438 		cur = ucl_test_boolean ();
439 		assert (cur != NULL);
440 
441 		ucl_array_append (res, cur);
442 	}
443 
444 	return res;
445 }
446 
447 static ucl_object_t*
448 ucl_test_large_string (void)
449 {
450 	ucl_object_t *res;
451 	char *str;
452 	uint32_t cur_len;
453 
454 	while ((cur_len = pcg32_random ()) % 100000 == 0);
455 	str = malloc (cur_len % 100000);
456 	res = ucl_object_fromstring_common (str, cur_len % 100000,
457 				UCL_STRING_RAW);
458 	res->flags |= UCL_OBJECT_BINARY;
459 	free (str);
460 
461 	return res;
462 }
463 
464 static ucl_object_t*
465 ucl_test_null (void)
466 {
467 	return ucl_object_typed_new (UCL_NULL);
468 }
469