xref: /freebsd/contrib/libucl/tests/test_msgpack.c (revision 39ee7a7a6bdd1557b1c3532abf60d139798ac88b)
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 = 1000;
30 static const int ntests = 100;
31 static const int nelt = 10;
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 
43 ucl_msgpack_test tests[] = {
44 		ucl_test_integer,
45 		ucl_test_string,
46 		ucl_test_boolean,
47 		ucl_test_map,
48 		ucl_test_array,
49 };
50 
51 #define NTESTS (sizeof(tests) / sizeof(tests[0]))
52 
53 typedef struct
54 {
55 	uint64_t state;
56 	uint64_t inc;
57 } pcg32_random_t;
58 
59 pcg32_random_t rng;
60 
61 /*
62  * From http://www.pcg-random.org/
63  */
64 static uint32_t
65 pcg32_random (void)
66 {
67 	uint64_t oldstate = rng.state;
68 
69 	rng.state = oldstate * 6364136223846793005ULL + (rng.inc | 1);
70 	uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u;
71 	uint32_t rot = oldstate >> 59u;
72 	return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
73 }
74 
75 static const char *
76 random_key (size_t *lenptr)
77 {
78 	static char keybuf[512];
79 	int keylen, i;
80 	char c;
81 
82 	keylen = pcg32_random () % (sizeof (keybuf) - 1) + 1;
83 
84 	for (i = 0; i < keylen; i ++) {
85 		do {
86 			c = pcg32_random () & 0xFF;
87 		} while (!isgraph (c));
88 
89 		keybuf[i] = c;
90 	}
91 
92 	*lenptr = keylen;
93 	return keybuf;
94 }
95 
96 int
97 main (int argc, char **argv)
98 {
99 	int fd, i, j;
100 	uint32_t sel;
101 	ucl_object_t *obj, *elt;
102 	struct ucl_parser *parser;
103 	size_t klen, elen, elen2;
104 	const char *key;
105 	unsigned char *emitted, *emitted2;
106 	FILE *out;
107 	const char *fname_out = NULL;
108 
109 	switch (argc) {
110 	case 2:
111 		fname_out = argv[1];
112 		break;
113 	}
114 
115 	/* Seed prng */
116 	fd = open ("/dev/urandom", O_RDONLY);
117 	assert (fd != -1);
118 	assert (read (fd, &rng, sizeof (rng)) == sizeof (rng));
119 	close (fd);
120 
121 	for (i = 0; i < niter; i ++) {
122 		if (fname_out != NULL) {
123 			out = fopen (fname_out, "w");
124 			if (out == NULL) {
125 				exit (-errno);
126 			}
127 		}
128 		else {
129 			out = NULL;
130 		}
131 
132 		/* Generate phase */
133 		obj = ucl_object_typed_new (UCL_OBJECT);
134 
135 		for (j = 0; j < ntests; j ++) {
136 			sel = pcg32_random () % NTESTS;
137 
138 			key = random_key (&klen);
139 			recursion = 0;
140 			elt = tests[sel]();
141 			assert (elt != NULL);
142 			assert (klen != 0);
143 
144 			ucl_object_insert_key (obj, elt, key, klen, true);
145 		}
146 
147 		emitted = ucl_object_emit_len (obj, UCL_EMIT_MSGPACK, &elen);
148 
149 		assert (emitted != NULL);
150 
151 		if (out) {
152 			fprintf (out, "%*.s\n", (int)elen, emitted);
153 
154 			fclose (out);
155 		}
156 		ucl_object_unref (obj);
157 
158 		parser = ucl_parser_new (0);
159 
160 		if (!ucl_parser_add_chunk_full (parser, emitted, elen, 0,
161 				UCL_DUPLICATE_APPEND, UCL_PARSE_MSGPACK)) {
162 			fprintf (stderr, "error parsing input: %s",
163 					ucl_parser_get_error (parser));
164 			assert (0);
165 		}
166 
167 		obj = ucl_parser_get_object (parser);
168 		assert (obj != NULL);
169 
170 		emitted2 = ucl_object_emit_len (obj, UCL_EMIT_MSGPACK, &elen2);
171 
172 		assert (emitted2 != NULL);
173 		assert (elen2 == elen);
174 		assert (memcmp (emitted, emitted2, elen) == 0);
175 
176 		ucl_parser_free (parser);
177 		ucl_object_unref (obj);
178 		free (emitted);
179 		free (emitted2);
180 	}
181 
182 	return 0;
183 }
184 
185 
186 static ucl_object_t*
187 ucl_test_integer (void)
188 {
189 	ucl_object_t *res;
190 	int count, i;
191 	uint64_t cur;
192 
193 	res = ucl_object_typed_new (UCL_ARRAY);
194 	count = pcg32_random () % nelt;
195 
196 	for (i = 0; i < count; i ++) {
197 		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
198 		ucl_array_append (res, ucl_object_fromint (cur % 128));
199 		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
200 		ucl_array_append (res, ucl_object_fromint (-cur % 128));
201 		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
202 		ucl_array_append (res, ucl_object_fromint (cur % 65536));
203 		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
204 		ucl_array_append (res, ucl_object_fromint (cur % INT32_MAX));
205 		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
206 		ucl_array_append (res, ucl_object_fromint (cur));
207 	}
208 
209 	return res;
210 }
211 
212 static ucl_object_t*
213 ucl_test_string (void)
214 {
215 	ucl_object_t *res, *elt;
216 	int count, i;
217 	uint32_t cur_len;
218 	char *str;
219 
220 	res = ucl_object_typed_new (UCL_ARRAY);
221 	count = pcg32_random () % nelt;
222 
223 	for (i = 0; i < count; i ++) {
224 		while ((cur_len = pcg32_random ()) % 128 == 0);
225 
226 		str = malloc (cur_len % 128);
227 		ucl_array_append (res, ucl_object_fromstring_common (str, cur_len % 128,
228 				UCL_STRING_RAW));
229 		free (str);
230 
231 		while ((cur_len = pcg32_random ()) % 512 == 0);
232 		str = malloc (cur_len % 512);
233 		ucl_array_append (res, ucl_object_fromstring_common (str, cur_len % 512,
234 				UCL_STRING_RAW));
235 		free (str);
236 
237 		while ((cur_len = pcg32_random ()) % 128 == 0);
238 		str = malloc (cur_len % 128);
239 		elt = ucl_object_fromstring_common (str, cur_len % 128,
240 				UCL_STRING_RAW);
241 		elt->flags |= UCL_OBJECT_BINARY;
242 		ucl_array_append (res, elt);
243 		free (str);
244 
245 		while ((cur_len = pcg32_random ()) % 512 == 0);
246 		str = malloc (cur_len % 512);
247 		elt = ucl_object_fromstring_common (str, cur_len % 512,
248 				UCL_STRING_RAW);
249 		elt->flags |= UCL_OBJECT_BINARY;
250 		ucl_array_append (res, elt);
251 		free (str);
252 	}
253 
254 	return res;
255 }
256 
257 static ucl_object_t*
258 ucl_test_boolean (void)
259 {
260 	ucl_object_t *res;
261 	int count, i;
262 
263 	res = ucl_object_typed_new (UCL_ARRAY);
264 	count = pcg32_random () % nelt;
265 
266 	for (i = 0; i < count; i ++) {
267 		ucl_array_append (res, ucl_object_frombool (pcg32_random () % 2));
268 	}
269 
270 	return res;
271 }
272 
273 static ucl_object_t*
274 ucl_test_map (void)
275 {
276 	ucl_object_t *res, *cur;
277 	int count, i;
278 	uint32_t cur_len, sel;
279 	size_t klen;
280 	const char *key;
281 
282 	res = ucl_object_typed_new (UCL_OBJECT);
283 	count = pcg32_random () % nelt;
284 
285 	recursion ++;
286 
287 	for (i = 0; i < count; i ++) {
288 
289 		if (recursion > 10) {
290 			sel = pcg32_random () % (NTESTS - 2);
291 		}
292 		else {
293 			sel = pcg32_random () % NTESTS;
294 		}
295 
296 		key = random_key (&klen);
297 		cur = tests[sel]();
298 		assert (cur != NULL);
299 		assert (klen != 0);
300 
301 		ucl_object_insert_key (res, cur, key, klen, true);
302 
303 		/* Multi value key */
304 		cur = tests[sel]();
305 		assert (cur != NULL);
306 
307 		ucl_object_insert_key (res, cur, key, klen, true);
308 	}
309 
310 	return res;
311 }
312 
313 static ucl_object_t*
314 ucl_test_array (void)
315 {
316 	ucl_object_t *res, *cur;
317 	int count, i;
318 	uint32_t cur_len, sel;
319 
320 	res = ucl_object_typed_new (UCL_ARRAY);
321 	count = pcg32_random () % nelt;
322 
323 	recursion ++;
324 
325 	for (i = 0; i < count; i ++) {
326 		if (recursion > 10) {
327 			sel = pcg32_random () % (NTESTS - 2);
328 		}
329 		else {
330 			sel = pcg32_random () % NTESTS;
331 		}
332 
333 		cur = tests[sel]();
334 		assert (cur != NULL);
335 
336 		ucl_array_append (res, cur);
337 	}
338 
339 	return res;
340 }
341