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
pcg32_random(void)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 *
random_key(size_t * lenptr)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
main(int argc,char ** argv)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*
ucl_test_integer(void)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*
ucl_test_string(void)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*
ucl_test_boolean(void)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*
ucl_test_map(void)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*
ucl_test_large_map(void)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*
ucl_test_array(void)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*
ucl_test_large_array(void)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*
ucl_test_large_string(void)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*
ucl_test_null(void)465 ucl_test_null (void)
466 {
467 return ucl_object_typed_new (UCL_NULL);
468 }
469