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
29298166Sbaptstatic const int niter = 20;
30298166Sbaptstatic const int ntests = 10;
31298166Sbaptstatic const int nelt = 20;
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);
42298166Sbaptstatic ucl_object_t* ucl_test_large_map (void);
43298166Sbaptstatic ucl_object_t* ucl_test_large_array (void);
44298166Sbaptstatic ucl_object_t* ucl_test_large_string (void);
45298166Sbaptstatic ucl_object_t* ucl_test_null (void);
46290067Sbapt
47290067Sbaptucl_msgpack_test tests[] = {
48290067Sbapt		ucl_test_integer,
49290067Sbapt		ucl_test_string,
50290067Sbapt		ucl_test_boolean,
51290067Sbapt		ucl_test_map,
52290067Sbapt		ucl_test_array,
53298166Sbapt		ucl_test_null
54290067Sbapt};
55290067Sbapt
56290067Sbapt#define NTESTS (sizeof(tests) / sizeof(tests[0]))
57290067Sbapt
58290067Sbapttypedef struct
59290067Sbapt{
60290067Sbapt	uint64_t state;
61290067Sbapt	uint64_t inc;
62290067Sbapt} pcg32_random_t;
63290067Sbapt
64290067Sbaptpcg32_random_t rng;
65290067Sbapt
66290067Sbapt/*
67290067Sbapt * From http://www.pcg-random.org/
68290067Sbapt */
69290067Sbaptstatic uint32_t
70290067Sbaptpcg32_random (void)
71290067Sbapt{
72290067Sbapt	uint64_t oldstate = rng.state;
73290067Sbapt
74290067Sbapt	rng.state = oldstate * 6364136223846793005ULL + (rng.inc | 1);
75290067Sbapt	uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u;
76290067Sbapt	uint32_t rot = oldstate >> 59u;
77290067Sbapt	return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
78290067Sbapt}
79290067Sbapt
80290067Sbaptstatic const char *
81290067Sbaptrandom_key (size_t *lenptr)
82290067Sbapt{
83290067Sbapt	static char keybuf[512];
84290067Sbapt	int keylen, i;
85290067Sbapt	char c;
86290067Sbapt
87290067Sbapt	keylen = pcg32_random () % (sizeof (keybuf) - 1) + 1;
88290067Sbapt
89290067Sbapt	for (i = 0; i < keylen; i ++) {
90290067Sbapt		do {
91290067Sbapt			c = pcg32_random () & 0xFF;
92290067Sbapt		} while (!isgraph (c));
93290067Sbapt
94290067Sbapt		keybuf[i] = c;
95290067Sbapt	}
96290067Sbapt
97290067Sbapt	*lenptr = keylen;
98290067Sbapt	return keybuf;
99290067Sbapt}
100290067Sbapt
101290067Sbaptint
102290067Sbaptmain (int argc, char **argv)
103290067Sbapt{
104290067Sbapt	int fd, i, j;
105290067Sbapt	uint32_t sel;
106290067Sbapt	ucl_object_t *obj, *elt;
107290067Sbapt	struct ucl_parser *parser;
108290067Sbapt	size_t klen, elen, elen2;
109290067Sbapt	const char *key;
110290067Sbapt	unsigned char *emitted, *emitted2;
111290067Sbapt	FILE *out;
112290067Sbapt	const char *fname_out = NULL;
113290067Sbapt
114290067Sbapt	switch (argc) {
115290067Sbapt	case 2:
116290067Sbapt		fname_out = argv[1];
117290067Sbapt		break;
118290067Sbapt	}
119290067Sbapt
120290067Sbapt	/* Seed prng */
121290067Sbapt	fd = open ("/dev/urandom", O_RDONLY);
122290067Sbapt	assert (fd != -1);
123290067Sbapt	assert (read (fd, &rng, sizeof (rng)) == sizeof (rng));
124290067Sbapt	close (fd);
125290067Sbapt
126290067Sbapt	for (i = 0; i < niter; i ++) {
127290067Sbapt		if (fname_out != NULL) {
128290067Sbapt			out = fopen (fname_out, "w");
129290067Sbapt			if (out == NULL) {
130290067Sbapt				exit (-errno);
131290067Sbapt			}
132290067Sbapt		}
133290067Sbapt		else {
134290067Sbapt			out = NULL;
135290067Sbapt		}
136290067Sbapt
137290067Sbapt		/* Generate phase */
138290067Sbapt		obj = ucl_object_typed_new (UCL_OBJECT);
139290067Sbapt
140290067Sbapt		for (j = 0; j < ntests; j ++) {
141290067Sbapt			sel = pcg32_random () % NTESTS;
142290067Sbapt
143290067Sbapt			key = random_key (&klen);
144290067Sbapt			recursion = 0;
145290067Sbapt			elt = tests[sel]();
146290067Sbapt			assert (elt != NULL);
147290067Sbapt			assert (klen != 0);
148290067Sbapt
149290067Sbapt			ucl_object_insert_key (obj, elt, key, klen, true);
150290067Sbapt		}
151290067Sbapt
152298166Sbapt		key = random_key (&klen);
153298166Sbapt		elt = ucl_test_large_array ();
154298166Sbapt		ucl_object_insert_key (obj, elt, key, klen, true);
155298166Sbapt
156298166Sbapt		key = random_key (&klen);
157298166Sbapt		elt = ucl_test_large_map ();
158298166Sbapt		ucl_object_insert_key (obj, elt, key, klen, true);
159298166Sbapt
160298166Sbapt		key = random_key (&klen);
161298166Sbapt		elt = ucl_test_large_string ();
162298166Sbapt		ucl_object_insert_key (obj, elt, key, klen, true);
163298166Sbapt
164290067Sbapt		emitted = ucl_object_emit_len (obj, UCL_EMIT_MSGPACK, &elen);
165290067Sbapt
166290067Sbapt		assert (emitted != NULL);
167290067Sbapt
168290067Sbapt		if (out) {
169290067Sbapt			fprintf (out, "%*.s\n", (int)elen, emitted);
170290067Sbapt
171290067Sbapt			fclose (out);
172290067Sbapt		}
173290067Sbapt		ucl_object_unref (obj);
174290067Sbapt
175290067Sbapt		parser = ucl_parser_new (0);
176290067Sbapt
177290067Sbapt		if (!ucl_parser_add_chunk_full (parser, emitted, elen, 0,
178290067Sbapt				UCL_DUPLICATE_APPEND, UCL_PARSE_MSGPACK)) {
179290067Sbapt			fprintf (stderr, "error parsing input: %s",
180290067Sbapt					ucl_parser_get_error (parser));
181290067Sbapt			assert (0);
182290067Sbapt		}
183290067Sbapt
184290067Sbapt		obj = ucl_parser_get_object (parser);
185290067Sbapt		assert (obj != NULL);
186290067Sbapt
187290067Sbapt		emitted2 = ucl_object_emit_len (obj, UCL_EMIT_MSGPACK, &elen2);
188290067Sbapt
189290067Sbapt		assert (emitted2 != NULL);
190290067Sbapt		assert (elen2 == elen);
191290067Sbapt		assert (memcmp (emitted, emitted2, elen) == 0);
192290067Sbapt
193290067Sbapt		ucl_parser_free (parser);
194290067Sbapt		ucl_object_unref (obj);
195290067Sbapt		free (emitted);
196290067Sbapt		free (emitted2);
197290067Sbapt	}
198290067Sbapt
199290067Sbapt	return 0;
200290067Sbapt}
201290067Sbapt
202290067Sbapt
203290067Sbaptstatic ucl_object_t*
204290067Sbaptucl_test_integer (void)
205290067Sbapt{
206290067Sbapt	ucl_object_t *res;
207290067Sbapt	int count, i;
208290067Sbapt	uint64_t cur;
209298166Sbapt	double curf;
210290067Sbapt
211290067Sbapt	res = ucl_object_typed_new (UCL_ARRAY);
212290067Sbapt	count = pcg32_random () % nelt;
213290067Sbapt
214290067Sbapt	for (i = 0; i < count; i ++) {
215290067Sbapt		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
216290067Sbapt		ucl_array_append (res, ucl_object_fromint (cur % 128));
217298166Sbapt		ucl_array_append (res, ucl_object_fromint (-(cur % 128)));
218290067Sbapt		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
219298166Sbapt		ucl_array_append (res, ucl_object_fromint (cur % UINT16_MAX));
220298166Sbapt		ucl_array_append (res, ucl_object_fromint (-(cur % INT16_MAX)));
221290067Sbapt		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
222298166Sbapt		ucl_array_append (res, ucl_object_fromint (cur % UINT32_MAX));
223298166Sbapt		ucl_array_append (res, ucl_object_fromint (-(cur % INT32_MAX)));
224290067Sbapt		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
225298166Sbapt		ucl_array_append (res, ucl_object_fromint (cur));
226298166Sbapt		ucl_array_append (res, ucl_object_fromint (-cur));
227298166Sbapt		/* Double version */
228290067Sbapt		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
229298166Sbapt		curf = (cur % 128) / 19 * 16;
230298166Sbapt		ucl_array_append (res, ucl_object_fromdouble (curf));
231298166Sbapt		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
232298166Sbapt		curf = -(cur % 128) / 19 * 16;
233298166Sbapt		ucl_array_append (res, ucl_object_fromdouble (curf));
234298166Sbapt		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
235298166Sbapt		curf = (cur % 65536) / 19 * 16;
236298166Sbapt		ucl_array_append (res, ucl_object_fromdouble (curf));
237298166Sbapt		ucl_array_append (res, ucl_object_fromdouble (-curf));
238298166Sbapt		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
239298166Sbapt		curf = (cur % INT32_MAX) / 19 * 16;
240298166Sbapt		ucl_array_append (res, ucl_object_fromdouble (curf));
241298166Sbapt		cur = ((uint64_t)pcg32_random ()) << 32 | pcg32_random ();
242298166Sbapt		memcpy (&curf, &cur, sizeof (curf));
243290067Sbapt		ucl_array_append (res, ucl_object_fromint (cur));
244290067Sbapt	}
245290067Sbapt
246290067Sbapt	return res;
247290067Sbapt}
248290067Sbapt
249290067Sbaptstatic ucl_object_t*
250290067Sbaptucl_test_string (void)
251290067Sbapt{
252290067Sbapt	ucl_object_t *res, *elt;
253290067Sbapt	int count, i;
254290067Sbapt	uint32_t cur_len;
255290067Sbapt	char *str;
256290067Sbapt
257290067Sbapt	res = ucl_object_typed_new (UCL_ARRAY);
258290067Sbapt	count = pcg32_random () % nelt;
259290067Sbapt
260290067Sbapt	for (i = 0; i < count; i ++) {
261290067Sbapt		while ((cur_len = pcg32_random ()) % 128 == 0);
262290067Sbapt
263290067Sbapt		str = malloc (cur_len % 128);
264290067Sbapt		ucl_array_append (res, ucl_object_fromstring_common (str, cur_len % 128,
265290067Sbapt				UCL_STRING_RAW));
266290067Sbapt		free (str);
267290067Sbapt
268290067Sbapt		while ((cur_len = pcg32_random ()) % 512 == 0);
269290067Sbapt		str = malloc (cur_len % 512);
270290067Sbapt		ucl_array_append (res, ucl_object_fromstring_common (str, cur_len % 512,
271290067Sbapt				UCL_STRING_RAW));
272290067Sbapt		free (str);
273290067Sbapt
274290067Sbapt		while ((cur_len = pcg32_random ()) % 128 == 0);
275290067Sbapt		str = malloc (cur_len % 128);
276290067Sbapt		elt = ucl_object_fromstring_common (str, cur_len % 128,
277290067Sbapt				UCL_STRING_RAW);
278290067Sbapt		elt->flags |= UCL_OBJECT_BINARY;
279290067Sbapt		ucl_array_append (res, elt);
280290067Sbapt		free (str);
281290067Sbapt
282290067Sbapt		while ((cur_len = pcg32_random ()) % 512 == 0);
283290067Sbapt		str = malloc (cur_len % 512);
284290067Sbapt		elt = ucl_object_fromstring_common (str, cur_len % 512,
285290067Sbapt				UCL_STRING_RAW);
286290067Sbapt		elt->flags |= UCL_OBJECT_BINARY;
287290067Sbapt		ucl_array_append (res, elt);
288290067Sbapt		free (str);
289290067Sbapt	}
290290067Sbapt
291298166Sbapt	/* One large string */
292298166Sbapt	str = malloc (65537);
293298166Sbapt	elt = ucl_object_fromstring_common (str, 65537,
294298166Sbapt			UCL_STRING_RAW);
295298166Sbapt	elt->flags |= UCL_OBJECT_BINARY;
296298166Sbapt	ucl_array_append (res, elt);
297298166Sbapt	free (str);
298298166Sbapt
299290067Sbapt	return res;
300290067Sbapt}
301290067Sbapt
302290067Sbaptstatic ucl_object_t*
303290067Sbaptucl_test_boolean (void)
304290067Sbapt{
305290067Sbapt	ucl_object_t *res;
306290067Sbapt	int count, i;
307290067Sbapt
308290067Sbapt	res = ucl_object_typed_new (UCL_ARRAY);
309290067Sbapt	count = pcg32_random () % nelt;
310290067Sbapt
311290067Sbapt	for (i = 0; i < count; i ++) {
312290067Sbapt		ucl_array_append (res, ucl_object_frombool (pcg32_random () % 2));
313290067Sbapt	}
314290067Sbapt
315290067Sbapt	return res;
316290067Sbapt}
317290067Sbapt
318290067Sbaptstatic ucl_object_t*
319290067Sbaptucl_test_map (void)
320290067Sbapt{
321290067Sbapt	ucl_object_t *res, *cur;
322290067Sbapt	int count, i;
323290067Sbapt	uint32_t cur_len, sel;
324290067Sbapt	size_t klen;
325290067Sbapt	const char *key;
326290067Sbapt
327290067Sbapt	res = ucl_object_typed_new (UCL_OBJECT);
328290067Sbapt	count = pcg32_random () % nelt;
329290067Sbapt
330290067Sbapt	recursion ++;
331290067Sbapt
332290067Sbapt	for (i = 0; i < count; i ++) {
333290067Sbapt
334290067Sbapt		if (recursion > 10) {
335298166Sbapt			for (;;) {
336298166Sbapt				sel = pcg32_random () % NTESTS;
337298166Sbapt				if (tests[sel] != ucl_test_map &&
338298166Sbapt						tests[sel] != ucl_test_array) {
339298166Sbapt					break;
340298166Sbapt				}
341298166Sbapt			}
342290067Sbapt		}
343290067Sbapt		else {
344290067Sbapt			sel = pcg32_random () % NTESTS;
345290067Sbapt		}
346290067Sbapt
347290067Sbapt		key = random_key (&klen);
348290067Sbapt		cur = tests[sel]();
349290067Sbapt		assert (cur != NULL);
350290067Sbapt		assert (klen != 0);
351290067Sbapt
352290067Sbapt		ucl_object_insert_key (res, cur, key, klen, true);
353290067Sbapt
354290067Sbapt		/* Multi value key */
355290067Sbapt		cur = tests[sel]();
356290067Sbapt		assert (cur != NULL);
357290067Sbapt
358290067Sbapt		ucl_object_insert_key (res, cur, key, klen, true);
359290067Sbapt	}
360290067Sbapt
361290067Sbapt	return res;
362290067Sbapt}
363290067Sbapt
364290067Sbaptstatic ucl_object_t*
365298166Sbaptucl_test_large_map (void)
366298166Sbapt{
367298166Sbapt	ucl_object_t *res, *cur;
368298166Sbapt	int count, i;
369298166Sbapt	uint32_t cur_len;
370298166Sbapt	size_t klen;
371298166Sbapt	const char *key;
372298166Sbapt
373298166Sbapt	res = ucl_object_typed_new (UCL_OBJECT);
374298166Sbapt	count = 65537;
375298166Sbapt
376298166Sbapt	recursion ++;
377298166Sbapt
378298166Sbapt	for (i = 0; i < count; i ++) {
379298166Sbapt		key = random_key (&klen);
380298166Sbapt		cur = ucl_test_boolean ();
381298166Sbapt		assert (cur != NULL);
382298166Sbapt		assert (klen != 0);
383298166Sbapt
384298166Sbapt		ucl_object_insert_key (res, cur, key, klen, true);
385298166Sbapt	}
386298166Sbapt
387298166Sbapt	return res;
388298166Sbapt}
389298166Sbapt
390298166Sbaptstatic ucl_object_t*
391290067Sbaptucl_test_array (void)
392290067Sbapt{
393290067Sbapt	ucl_object_t *res, *cur;
394290067Sbapt	int count, i;
395290067Sbapt	uint32_t cur_len, sel;
396290067Sbapt
397290067Sbapt	res = ucl_object_typed_new (UCL_ARRAY);
398290067Sbapt	count = pcg32_random () % nelt;
399290067Sbapt
400290067Sbapt	recursion ++;
401290067Sbapt
402290067Sbapt	for (i = 0; i < count; i ++) {
403290067Sbapt		if (recursion > 10) {
404298166Sbapt			for (;;) {
405298166Sbapt				sel = pcg32_random () % NTESTS;
406298166Sbapt				if (tests[sel] != ucl_test_map &&
407298166Sbapt						tests[sel] != ucl_test_array) {
408298166Sbapt					break;
409298166Sbapt				}
410298166Sbapt			}
411290067Sbapt		}
412290067Sbapt		else {
413290067Sbapt			sel = pcg32_random () % NTESTS;
414290067Sbapt		}
415290067Sbapt
416290067Sbapt		cur = tests[sel]();
417290067Sbapt		assert (cur != NULL);
418290067Sbapt
419290067Sbapt		ucl_array_append (res, cur);
420290067Sbapt	}
421290067Sbapt
422290067Sbapt	return res;
423290067Sbapt}
424298166Sbapt
425298166Sbaptstatic ucl_object_t*
426298166Sbaptucl_test_large_array (void)
427298166Sbapt{
428298166Sbapt	ucl_object_t *res, *cur;
429298166Sbapt	int count, i;
430298166Sbapt	uint32_t cur_len;
431298166Sbapt
432298166Sbapt	res = ucl_object_typed_new (UCL_ARRAY);
433298166Sbapt	count = 65537;
434298166Sbapt
435298166Sbapt	recursion ++;
436298166Sbapt
437298166Sbapt	for (i = 0; i < count; i ++) {
438298166Sbapt		cur = ucl_test_boolean ();
439298166Sbapt		assert (cur != NULL);
440298166Sbapt
441298166Sbapt		ucl_array_append (res, cur);
442298166Sbapt	}
443298166Sbapt
444298166Sbapt	return res;
445298166Sbapt}
446298166Sbapt
447298166Sbaptstatic ucl_object_t*
448298166Sbaptucl_test_large_string (void)
449298166Sbapt{
450298166Sbapt	ucl_object_t *res;
451298166Sbapt	char *str;
452298166Sbapt	uint32_t cur_len;
453298166Sbapt
454298166Sbapt	while ((cur_len = pcg32_random ()) % 100000 == 0);
455298166Sbapt	str = malloc (cur_len % 100000);
456298166Sbapt	res = ucl_object_fromstring_common (str, cur_len % 100000,
457298166Sbapt				UCL_STRING_RAW);
458298166Sbapt	res->flags |= UCL_OBJECT_BINARY;
459298166Sbapt
460298166Sbapt	return res;
461298166Sbapt}
462298166Sbapt
463298166Sbaptstatic ucl_object_t*
464298166Sbaptucl_test_null (void)
465298166Sbapt{
466298166Sbapt	return ucl_object_typed_new (UCL_NULL);
467298166Sbapt}
468