test_msgpack.c revision 290067
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
29static const int niter = 1000;
30static const int ntests = 100;
31static const int nelt = 10;
32
33static int recursion = 0;
34
35typedef ucl_object_t* (*ucl_msgpack_test)(void);
36
37static ucl_object_t* ucl_test_integer (void);
38static ucl_object_t* ucl_test_string (void);
39static ucl_object_t* ucl_test_boolean (void);
40static ucl_object_t* ucl_test_map (void);
41static ucl_object_t* ucl_test_array (void);
42
43ucl_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
53typedef struct
54{
55	uint64_t state;
56	uint64_t inc;
57} pcg32_random_t;
58
59pcg32_random_t rng;
60
61/*
62 * From http://www.pcg-random.org/
63 */
64static uint32_t
65pcg32_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
75static const char *
76random_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
96int
97main (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
186static ucl_object_t*
187ucl_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
212static ucl_object_t*
213ucl_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
257static ucl_object_t*
258ucl_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
273static ucl_object_t*
274ucl_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
313static ucl_object_t*
314ucl_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