test_msgpack.c revision 290067
1290067Sbapt/*
2290067Sbapt * Copyright (c) 2015, Vsevolod Stakhov
3290067Sbapt * All rights reserved.
4290067Sbapt *
5290067Sbapt * Redistribution and use in source and binary forms, with or without
6290067Sbapt * modification, are permitted provided that the following conditions are met:
7290067Sbapt *	 * Redistributions of source code must retain the above copyright
8290067Sbapt *	   notice, this list of conditions and the following disclaimer.
9290067Sbapt *	 * Redistributions in binary form must reproduce the above copyright
10290067Sbapt *	   notice, this list of conditions and the following disclaimer in the
11290067Sbapt *	   documentation and/or other materials provided with the distribution.
12290067Sbapt *
13290067Sbapt * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY
14290067Sbapt * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15290067Sbapt * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16290067Sbapt * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
17290067Sbapt * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18290067Sbapt * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19290067Sbapt * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20290067Sbapt * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21290067Sbapt * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22290067Sbapt * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23290067Sbapt */
24290067Sbapt
25290067Sbapt#include "ucl.h"
26290067Sbapt#include "ucl_internal.h"
27290067Sbapt#include <ctype.h>
28290067Sbapt
29290067Sbaptstatic const int niter = 1000;
30290067Sbaptstatic const int ntests = 100;
31290067Sbaptstatic const int nelt = 10;
32290067Sbapt
33290067Sbaptstatic int recursion = 0;
34290067Sbapt
35290067Sbapttypedef ucl_object_t* (*ucl_msgpack_test)(void);
36290067Sbapt
37290067Sbaptstatic ucl_object_t* ucl_test_integer (void);
38290067Sbaptstatic ucl_object_t* ucl_test_string (void);
39290067Sbaptstatic ucl_object_t* ucl_test_boolean (void);
40290067Sbaptstatic ucl_object_t* ucl_test_map (void);
41290067Sbaptstatic ucl_object_t* ucl_test_array (void);
42290067Sbapt
43290067Sbaptucl_msgpack_test tests[] = {
44290067Sbapt		ucl_test_integer,
45290067Sbapt		ucl_test_string,
46290067Sbapt		ucl_test_boolean,
47290067Sbapt		ucl_test_map,
48290067Sbapt		ucl_test_array,
49290067Sbapt};
50290067Sbapt
51290067Sbapt#define NTESTS (sizeof(tests) / sizeof(tests[0]))
52290067Sbapt
53290067Sbapttypedef struct
54290067Sbapt{
55290067Sbapt	uint64_t state;
56290067Sbapt	uint64_t inc;
57290067Sbapt} pcg32_random_t;
58290067Sbapt
59290067Sbaptpcg32_random_t rng;
60290067Sbapt
61290067Sbapt/*
62290067Sbapt * From http://www.pcg-random.org/
63290067Sbapt */
64290067Sbaptstatic uint32_t
65290067Sbaptpcg32_random (void)
66290067Sbapt{
67290067Sbapt	uint64_t oldstate = rng.state;
68290067Sbapt
69290067Sbapt	rng.state = oldstate * 6364136223846793005ULL + (rng.inc | 1);
70290067Sbapt	uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u;
71290067Sbapt	uint32_t rot = oldstate >> 59u;
72290067Sbapt	return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
73290067Sbapt}
74290067Sbapt
75290067Sbaptstatic const char *
76290067Sbaptrandom_key (size_t *lenptr)
77290067Sbapt{
78290067Sbapt	static char keybuf[512];
79290067Sbapt	int keylen, i;
80290067Sbapt	char c;
81290067Sbapt
82290067Sbapt	keylen = pcg32_random () % (sizeof (keybuf) - 1) + 1;
83290067Sbapt
84290067Sbapt	for (i = 0; i < keylen; i ++) {
85290067Sbapt		do {
86290067Sbapt			c = pcg32_random () & 0xFF;
87290067Sbapt		} while (!isgraph (c));
88290067Sbapt
89290067Sbapt		keybuf[i] = c;
90290067Sbapt	}
91290067Sbapt
92290067Sbapt	*lenptr = keylen;
93290067Sbapt	return keybuf;
94290067Sbapt}
95290067Sbapt
96290067Sbaptint
97290067Sbaptmain (int argc, char **argv)
98290067Sbapt{
99290067Sbapt	int fd, i, j;
100290067Sbapt	uint32_t sel;
101290067Sbapt	ucl_object_t *obj, *elt;
102290067Sbapt	struct ucl_parser *parser;
103290067Sbapt	size_t klen, elen, elen2;
104290067Sbapt	const char *key;
105290067Sbapt	unsigned char *emitted, *emitted2;
106290067Sbapt	FILE *out;
107290067Sbapt	const char *fname_out = NULL;
108290067Sbapt
109290067Sbapt	switch (argc) {
110290067Sbapt	case 2:
111290067Sbapt		fname_out = argv[1];
112290067Sbapt		break;
113290067Sbapt	}
114290067Sbapt
115290067Sbapt	/* Seed prng */
116290067Sbapt	fd = open ("/dev/urandom", O_RDONLY);
117290067Sbapt	assert (fd != -1);
118290067Sbapt	assert (read (fd, &rng, sizeof (rng)) == sizeof (rng));
119290067Sbapt	close (fd);
120290067Sbapt
121290067Sbapt	for (i = 0; i < niter; i ++) {
122290067Sbapt		if (fname_out != NULL) {
123290067Sbapt			out = fopen (fname_out, "w");
124290067Sbapt			if (out == NULL) {
125290067Sbapt				exit (-errno);
126290067Sbapt			}
127290067Sbapt		}
128290067Sbapt		else {
129290067Sbapt			out = NULL;
130290067Sbapt		}
131290067Sbapt
132290067Sbapt		/* Generate phase */
133290067Sbapt		obj = ucl_object_typed_new (UCL_OBJECT);
134290067Sbapt
135290067Sbapt		for (j = 0; j < ntests; j ++) {
136290067Sbapt			sel = pcg32_random () % NTESTS;
137290067Sbapt
138290067Sbapt			key = random_key (&klen);
139290067Sbapt			recursion = 0;
140290067Sbapt			elt = tests[sel]();
141290067Sbapt			assert (elt != NULL);
142290067Sbapt			assert (klen != 0);
143290067Sbapt
144290067Sbapt			ucl_object_insert_key (obj, elt, key, klen, true);
145290067Sbapt		}
146290067Sbapt
147290067Sbapt		emitted = ucl_object_emit_len (obj, UCL_EMIT_MSGPACK, &elen);
148290067Sbapt
149290067Sbapt		assert (emitted != NULL);
150290067Sbapt
151290067Sbapt		if (out) {
152290067Sbapt			fprintf (out, "%*.s\n", (int)elen, emitted);
153290067Sbapt
154290067Sbapt			fclose (out);
155290067Sbapt		}
156290067Sbapt		ucl_object_unref (obj);
157290067Sbapt
158290067Sbapt		parser = ucl_parser_new (0);
159290067Sbapt
160290067Sbapt		if (!ucl_parser_add_chunk_full (parser, emitted, elen, 0,
161290067Sbapt				UCL_DUPLICATE_APPEND, UCL_PARSE_MSGPACK)) {
162290067Sbapt			fprintf (stderr, "error parsing input: %s",
163290067Sbapt					ucl_parser_get_error (parser));
164290067Sbapt			assert (0);
165290067Sbapt		}
166290067Sbapt
167290067Sbapt		obj = ucl_parser_get_object (parser);
168290067Sbapt		assert (obj != NULL);
169290067Sbapt
170290067Sbapt		emitted2 = ucl_object_emit_len (obj, UCL_EMIT_MSGPACK, &elen2);
171290067Sbapt
172290067Sbapt		assert (emitted2 != NULL);
173290067Sbapt		assert (elen2 == elen);
174290067Sbapt		assert (memcmp (emitted, emitted2, elen) == 0);
175290067Sbapt
176290067Sbapt		ucl_parser_free (parser);
177290067Sbapt		ucl_object_unref (obj);
178290067Sbapt		free (emitted);
179290067Sbapt		free (emitted2);
180290067Sbapt	}
181290067Sbapt
182290067Sbapt	return 0;
183290067Sbapt}
184290067Sbapt
185290067Sbapt
186290067Sbaptstatic ucl_object_t*
187290067Sbaptucl_test_integer (void)
188290067Sbapt{
189290067Sbapt	ucl_object_t *res;
190290067Sbapt	int count, i;
191290067Sbapt	uint64_t cur;
192290067Sbapt
193290067Sbapt	res = ucl_object_typed_new (UCL_ARRAY);
194290067Sbapt	count = pcg32_random () % nelt;
195290067Sbapt
196290067Sbapt	for (i = 0; i < count; i ++) {
197290067Sbapt		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
198290067Sbapt		ucl_array_append (res, ucl_object_fromint (cur % 128));
199290067Sbapt		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
200290067Sbapt		ucl_array_append (res, ucl_object_fromint (-cur % 128));
201290067Sbapt		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
202290067Sbapt		ucl_array_append (res, ucl_object_fromint (cur % 65536));
203290067Sbapt		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
204290067Sbapt		ucl_array_append (res, ucl_object_fromint (cur % INT32_MAX));
205290067Sbapt		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
206290067Sbapt		ucl_array_append (res, ucl_object_fromint (cur));
207290067Sbapt	}
208290067Sbapt
209290067Sbapt	return res;
210290067Sbapt}
211290067Sbapt
212290067Sbaptstatic ucl_object_t*
213290067Sbaptucl_test_string (void)
214290067Sbapt{
215290067Sbapt	ucl_object_t *res, *elt;
216290067Sbapt	int count, i;
217290067Sbapt	uint32_t cur_len;
218290067Sbapt	char *str;
219290067Sbapt
220290067Sbapt	res = ucl_object_typed_new (UCL_ARRAY);
221290067Sbapt	count = pcg32_random () % nelt;
222290067Sbapt
223290067Sbapt	for (i = 0; i < count; i ++) {
224290067Sbapt		while ((cur_len = pcg32_random ()) % 128 == 0);
225290067Sbapt
226290067Sbapt		str = malloc (cur_len % 128);
227290067Sbapt		ucl_array_append (res, ucl_object_fromstring_common (str, cur_len % 128,
228290067Sbapt				UCL_STRING_RAW));
229290067Sbapt		free (str);
230290067Sbapt
231290067Sbapt		while ((cur_len = pcg32_random ()) % 512 == 0);
232290067Sbapt		str = malloc (cur_len % 512);
233290067Sbapt		ucl_array_append (res, ucl_object_fromstring_common (str, cur_len % 512,
234290067Sbapt				UCL_STRING_RAW));
235290067Sbapt		free (str);
236290067Sbapt
237290067Sbapt		while ((cur_len = pcg32_random ()) % 128 == 0);
238290067Sbapt		str = malloc (cur_len % 128);
239290067Sbapt		elt = ucl_object_fromstring_common (str, cur_len % 128,
240290067Sbapt				UCL_STRING_RAW);
241290067Sbapt		elt->flags |= UCL_OBJECT_BINARY;
242290067Sbapt		ucl_array_append (res, elt);
243290067Sbapt		free (str);
244290067Sbapt
245290067Sbapt		while ((cur_len = pcg32_random ()) % 512 == 0);
246290067Sbapt		str = malloc (cur_len % 512);
247290067Sbapt		elt = ucl_object_fromstring_common (str, cur_len % 512,
248290067Sbapt				UCL_STRING_RAW);
249290067Sbapt		elt->flags |= UCL_OBJECT_BINARY;
250290067Sbapt		ucl_array_append (res, elt);
251290067Sbapt		free (str);
252290067Sbapt	}
253290067Sbapt
254290067Sbapt	return res;
255290067Sbapt}
256290067Sbapt
257290067Sbaptstatic ucl_object_t*
258290067Sbaptucl_test_boolean (void)
259290067Sbapt{
260290067Sbapt	ucl_object_t *res;
261290067Sbapt	int count, i;
262290067Sbapt
263290067Sbapt	res = ucl_object_typed_new (UCL_ARRAY);
264290067Sbapt	count = pcg32_random () % nelt;
265290067Sbapt
266290067Sbapt	for (i = 0; i < count; i ++) {
267290067Sbapt		ucl_array_append (res, ucl_object_frombool (pcg32_random () % 2));
268290067Sbapt	}
269290067Sbapt
270290067Sbapt	return res;
271290067Sbapt}
272290067Sbapt
273290067Sbaptstatic ucl_object_t*
274290067Sbaptucl_test_map (void)
275290067Sbapt{
276290067Sbapt	ucl_object_t *res, *cur;
277290067Sbapt	int count, i;
278290067Sbapt	uint32_t cur_len, sel;
279290067Sbapt	size_t klen;
280290067Sbapt	const char *key;
281290067Sbapt
282290067Sbapt	res = ucl_object_typed_new (UCL_OBJECT);
283290067Sbapt	count = pcg32_random () % nelt;
284290067Sbapt
285290067Sbapt	recursion ++;
286290067Sbapt
287290067Sbapt	for (i = 0; i < count; i ++) {
288290067Sbapt
289290067Sbapt		if (recursion > 10) {
290290067Sbapt			sel = pcg32_random () % (NTESTS - 2);
291290067Sbapt		}
292290067Sbapt		else {
293290067Sbapt			sel = pcg32_random () % NTESTS;
294290067Sbapt		}
295290067Sbapt
296290067Sbapt		key = random_key (&klen);
297290067Sbapt		cur = tests[sel]();
298290067Sbapt		assert (cur != NULL);
299290067Sbapt		assert (klen != 0);
300290067Sbapt
301290067Sbapt		ucl_object_insert_key (res, cur, key, klen, true);
302290067Sbapt
303290067Sbapt		/* Multi value key */
304290067Sbapt		cur = tests[sel]();
305290067Sbapt		assert (cur != NULL);
306290067Sbapt
307290067Sbapt		ucl_object_insert_key (res, cur, key, klen, true);
308290067Sbapt	}
309290067Sbapt
310290067Sbapt	return res;
311290067Sbapt}
312290067Sbapt
313290067Sbaptstatic ucl_object_t*
314290067Sbaptucl_test_array (void)
315290067Sbapt{
316290067Sbapt	ucl_object_t *res, *cur;
317290067Sbapt	int count, i;
318290067Sbapt	uint32_t cur_len, sel;
319290067Sbapt
320290067Sbapt	res = ucl_object_typed_new (UCL_ARRAY);
321290067Sbapt	count = pcg32_random () % nelt;
322290067Sbapt
323290067Sbapt	recursion ++;
324290067Sbapt
325290067Sbapt	for (i = 0; i < count; i ++) {
326290067Sbapt		if (recursion > 10) {
327290067Sbapt			sel = pcg32_random () % (NTESTS - 2);
328290067Sbapt		}
329290067Sbapt		else {
330290067Sbapt			sel = pcg32_random () % NTESTS;
331290067Sbapt		}
332290067Sbapt
333290067Sbapt		cur = tests[sel]();
334290067Sbapt		assert (cur != NULL);
335290067Sbapt
336290067Sbapt		ucl_array_append (res, cur);
337290067Sbapt	}
338290067Sbapt
339290067Sbapt	return res;
340290067Sbapt}
341