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 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 * 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 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* 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* 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* 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* 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* 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* 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* 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* 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 460 return res; 461 } 462 463 static ucl_object_t* 464 ucl_test_null (void) 465 { 466 return ucl_object_typed_new (UCL_NULL); 467 } 468