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 = 1000; 30 static const int ntests = 100; 31 static const int nelt = 10; 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 43 ucl_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 53 typedef struct 54 { 55 uint64_t state; 56 uint64_t inc; 57 } pcg32_random_t; 58 59 pcg32_random_t rng; 60 61 /* 62 * From http://www.pcg-random.org/ 63 */ 64 static uint32_t 65 pcg32_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 75 static const char * 76 random_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 96 int 97 main (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 186 static ucl_object_t* 187 ucl_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 212 static ucl_object_t* 213 ucl_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 257 static ucl_object_t* 258 ucl_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 273 static ucl_object_t* 274 ucl_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 313 static ucl_object_t* 314 ucl_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