1#include "test/jemalloc_test.h" 2 3typedef enum { 4 TOKEN_TYPE_NONE, 5 TOKEN_TYPE_ERROR, 6 TOKEN_TYPE_EOI, 7 TOKEN_TYPE_NULL, 8 TOKEN_TYPE_FALSE, 9 TOKEN_TYPE_TRUE, 10 TOKEN_TYPE_LBRACKET, 11 TOKEN_TYPE_RBRACKET, 12 TOKEN_TYPE_LBRACE, 13 TOKEN_TYPE_RBRACE, 14 TOKEN_TYPE_COLON, 15 TOKEN_TYPE_COMMA, 16 TOKEN_TYPE_STRING, 17 TOKEN_TYPE_NUMBER 18} token_type_t; 19 20typedef struct parser_s parser_t; 21typedef struct { 22 parser_t *parser; 23 token_type_t token_type; 24 size_t pos; 25 size_t len; 26 size_t line; 27 size_t col; 28} token_t; 29 30struct parser_s { 31 bool verbose; 32 char *buf; /* '\0'-terminated. */ 33 size_t len; /* Number of characters preceding '\0' in buf. */ 34 size_t pos; 35 size_t line; 36 size_t col; 37 token_t token; 38}; 39 40static void 41token_init(token_t *token, parser_t *parser, token_type_t token_type, 42 size_t pos, size_t len, size_t line, size_t col) 43{ 44 token->parser = parser; 45 token->token_type = token_type; 46 token->pos = pos; 47 token->len = len; 48 token->line = line; 49 token->col = col; 50} 51 52static void 53token_error(token_t *token) 54{ 55 if (!token->parser->verbose) { 56 return; 57 } 58 switch (token->token_type) { 59 case TOKEN_TYPE_NONE: 60 not_reached(); 61 case TOKEN_TYPE_ERROR: 62 malloc_printf("%zu:%zu: Unexpected character in token: ", 63 token->line, token->col); 64 break; 65 default: 66 malloc_printf("%zu:%zu: Unexpected token: ", token->line, 67 token->col); 68 break; 69 } 70 write(STDERR_FILENO, &token->parser->buf[token->pos], token->len); 71 malloc_printf("\n"); 72} 73 74static void 75parser_init(parser_t *parser, bool verbose) 76{ 77 parser->verbose = verbose; 78 parser->buf = NULL; 79 parser->len = 0; 80 parser->pos = 0; 81 parser->line = 1; 82 parser->col = 0; 83} 84 85static void 86parser_fini(parser_t *parser) 87{ 88 if (parser->buf != NULL) { 89 dallocx(parser->buf, MALLOCX_TCACHE_NONE); 90 } 91} 92 93static bool 94parser_append(parser_t *parser, const char *str) 95{ 96 size_t len = strlen(str); 97 char *buf = (parser->buf == NULL) ? mallocx(len + 1, 98 MALLOCX_TCACHE_NONE) : rallocx(parser->buf, parser->len + len + 1, 99 MALLOCX_TCACHE_NONE); 100 if (buf == NULL) { 101 return true; 102 } 103 memcpy(&buf[parser->len], str, len + 1); 104 parser->buf = buf; 105 parser->len += len; 106 return false; 107} 108 109static bool 110parser_tokenize(parser_t *parser) 111{ 112 enum { 113 STATE_START, 114 STATE_EOI, 115 STATE_N, STATE_NU, STATE_NUL, STATE_NULL, 116 STATE_F, STATE_FA, STATE_FAL, STATE_FALS, STATE_FALSE, 117 STATE_T, STATE_TR, STATE_TRU, STATE_TRUE, 118 STATE_LBRACKET, 119 STATE_RBRACKET, 120 STATE_LBRACE, 121 STATE_RBRACE, 122 STATE_COLON, 123 STATE_COMMA, 124 STATE_CHARS, 125 STATE_CHAR_ESCAPE, 126 STATE_CHAR_U, STATE_CHAR_UD, STATE_CHAR_UDD, STATE_CHAR_UDDD, 127 STATE_STRING, 128 STATE_MINUS, 129 STATE_LEADING_ZERO, 130 STATE_DIGITS, 131 STATE_DECIMAL, 132 STATE_FRAC_DIGITS, 133 STATE_EXP, 134 STATE_EXP_SIGN, 135 STATE_EXP_DIGITS, 136 STATE_ACCEPT 137 } state = STATE_START; 138 size_t token_pos, token_line, token_col; 139 140 assert_zu_le(parser->pos, parser->len, 141 "Position is past end of buffer"); 142 143 while (state != STATE_ACCEPT) { 144 char c = parser->buf[parser->pos]; 145 146 switch (state) { 147 case STATE_START: 148 token_pos = parser->pos; 149 token_line = parser->line; 150 token_col = parser->col; 151 switch (c) { 152 case ' ': case '\b': case '\n': case '\r': case '\t': 153 break; 154 case '\0': 155 state = STATE_EOI; 156 break; 157 case 'n': 158 state = STATE_N; 159 break; 160 case 'f': 161 state = STATE_F; 162 break; 163 case 't': 164 state = STATE_T; 165 break; 166 case '[': 167 state = STATE_LBRACKET; 168 break; 169 case ']': 170 state = STATE_RBRACKET; 171 break; 172 case '{': 173 state = STATE_LBRACE; 174 break; 175 case '}': 176 state = STATE_RBRACE; 177 break; 178 case ':': 179 state = STATE_COLON; 180 break; 181 case ',': 182 state = STATE_COMMA; 183 break; 184 case '"': 185 state = STATE_CHARS; 186 break; 187 case '-': 188 state = STATE_MINUS; 189 break; 190 case '0': 191 state = STATE_LEADING_ZERO; 192 break; 193 case '1': case '2': case '3': case '4': 194 case '5': case '6': case '7': case '8': case '9': 195 state = STATE_DIGITS; 196 break; 197 default: 198 token_init(&parser->token, parser, 199 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 200 - token_pos, token_line, token_col); 201 return true; 202 } 203 break; 204 case STATE_EOI: 205 token_init(&parser->token, parser, 206 TOKEN_TYPE_EOI, token_pos, parser->pos - 207 token_pos, token_line, token_col); 208 state = STATE_ACCEPT; 209 break; 210 case STATE_N: 211 switch (c) { 212 case 'u': 213 state = STATE_NU; 214 break; 215 default: 216 token_init(&parser->token, parser, 217 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 218 - token_pos, token_line, token_col); 219 return true; 220 } 221 break; 222 case STATE_NU: 223 switch (c) { 224 case 'l': 225 state = STATE_NUL; 226 break; 227 default: 228 token_init(&parser->token, parser, 229 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 230 - token_pos, token_line, token_col); 231 return true; 232 } 233 break; 234 case STATE_NUL: 235 switch (c) { 236 case 'l': 237 state = STATE_NULL; 238 break; 239 default: 240 token_init(&parser->token, parser, 241 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 242 - token_pos, token_line, token_col); 243 return true; 244 } 245 break; 246 case STATE_NULL: 247 switch (c) { 248 case ' ': case '\b': case '\n': case '\r': case '\t': 249 case '\0': 250 case '[': case ']': case '{': case '}': case ':': 251 case ',': 252 break; 253 default: 254 token_init(&parser->token, parser, 255 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 256 - token_pos, token_line, token_col); 257 return true; 258 } 259 token_init(&parser->token, parser, TOKEN_TYPE_NULL, 260 token_pos, parser->pos - token_pos, token_line, 261 token_col); 262 state = STATE_ACCEPT; 263 break; 264 case STATE_F: 265 switch (c) { 266 case 'a': 267 state = STATE_FA; 268 break; 269 default: 270 token_init(&parser->token, parser, 271 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 272 - token_pos, token_line, token_col); 273 return true; 274 } 275 break; 276 case STATE_FA: 277 switch (c) { 278 case 'l': 279 state = STATE_FAL; 280 break; 281 default: 282 token_init(&parser->token, parser, 283 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 284 - token_pos, token_line, token_col); 285 return true; 286 } 287 break; 288 case STATE_FAL: 289 switch (c) { 290 case 's': 291 state = STATE_FALS; 292 break; 293 default: 294 token_init(&parser->token, parser, 295 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 296 - token_pos, token_line, token_col); 297 return true; 298 } 299 break; 300 case STATE_FALS: 301 switch (c) { 302 case 'e': 303 state = STATE_FALSE; 304 break; 305 default: 306 token_init(&parser->token, parser, 307 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 308 - token_pos, token_line, token_col); 309 return true; 310 } 311 break; 312 case STATE_FALSE: 313 switch (c) { 314 case ' ': case '\b': case '\n': case '\r': case '\t': 315 case '\0': 316 case '[': case ']': case '{': case '}': case ':': 317 case ',': 318 break; 319 default: 320 token_init(&parser->token, parser, 321 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 322 - token_pos, token_line, token_col); 323 return true; 324 } 325 token_init(&parser->token, parser, 326 TOKEN_TYPE_FALSE, token_pos, parser->pos - 327 token_pos, token_line, token_col); 328 state = STATE_ACCEPT; 329 break; 330 case STATE_T: 331 switch (c) { 332 case 'r': 333 state = STATE_TR; 334 break; 335 default: 336 token_init(&parser->token, parser, 337 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 338 - token_pos, token_line, token_col); 339 return true; 340 } 341 break; 342 case STATE_TR: 343 switch (c) { 344 case 'u': 345 state = STATE_TRU; 346 break; 347 default: 348 token_init(&parser->token, parser, 349 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 350 - token_pos, token_line, token_col); 351 return true; 352 } 353 break; 354 case STATE_TRU: 355 switch (c) { 356 case 'e': 357 state = STATE_TRUE; 358 break; 359 default: 360 token_init(&parser->token, parser, 361 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 362 - token_pos, token_line, token_col); 363 return true; 364 } 365 break; 366 case STATE_TRUE: 367 switch (c) { 368 case ' ': case '\b': case '\n': case '\r': case '\t': 369 case '\0': 370 case '[': case ']': case '{': case '}': case ':': 371 case ',': 372 break; 373 default: 374 token_init(&parser->token, parser, 375 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 376 - token_pos, token_line, token_col); 377 return true; 378 } 379 token_init(&parser->token, parser, TOKEN_TYPE_TRUE, 380 token_pos, parser->pos - token_pos, token_line, 381 token_col); 382 state = STATE_ACCEPT; 383 break; 384 case STATE_LBRACKET: 385 token_init(&parser->token, parser, TOKEN_TYPE_LBRACKET, 386 token_pos, parser->pos - token_pos, token_line, 387 token_col); 388 state = STATE_ACCEPT; 389 break; 390 case STATE_RBRACKET: 391 token_init(&parser->token, parser, TOKEN_TYPE_RBRACKET, 392 token_pos, parser->pos - token_pos, token_line, 393 token_col); 394 state = STATE_ACCEPT; 395 break; 396 case STATE_LBRACE: 397 token_init(&parser->token, parser, TOKEN_TYPE_LBRACE, 398 token_pos, parser->pos - token_pos, token_line, 399 token_col); 400 state = STATE_ACCEPT; 401 break; 402 case STATE_RBRACE: 403 token_init(&parser->token, parser, TOKEN_TYPE_RBRACE, 404 token_pos, parser->pos - token_pos, token_line, 405 token_col); 406 state = STATE_ACCEPT; 407 break; 408 case STATE_COLON: 409 token_init(&parser->token, parser, TOKEN_TYPE_COLON, 410 token_pos, parser->pos - token_pos, token_line, 411 token_col); 412 state = STATE_ACCEPT; 413 break; 414 case STATE_COMMA: 415 token_init(&parser->token, parser, TOKEN_TYPE_COMMA, 416 token_pos, parser->pos - token_pos, token_line, 417 token_col); 418 state = STATE_ACCEPT; 419 break; 420 case STATE_CHARS: 421 switch (c) { 422 case '\\': 423 state = STATE_CHAR_ESCAPE; 424 break; 425 case '"': 426 state = STATE_STRING; 427 break; 428 case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: 429 case 0x05: case 0x06: case 0x07: case 0x08: case 0x09: 430 case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: 431 case 0x0f: case 0x10: case 0x11: case 0x12: case 0x13: 432 case 0x14: case 0x15: case 0x16: case 0x17: case 0x18: 433 case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: 434 case 0x1e: case 0x1f: 435 token_init(&parser->token, parser, 436 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 437 - token_pos, token_line, token_col); 438 return true; 439 default: 440 break; 441 } 442 break; 443 case STATE_CHAR_ESCAPE: 444 switch (c) { 445 case '"': case '\\': case '/': case 'b': case 'n': 446 case 'r': case 't': 447 state = STATE_CHARS; 448 break; 449 case 'u': 450 state = STATE_CHAR_U; 451 break; 452 default: 453 token_init(&parser->token, parser, 454 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 455 - token_pos, token_line, token_col); 456 return true; 457 } 458 break; 459 case STATE_CHAR_U: 460 switch (c) { 461 case '0': case '1': case '2': case '3': case '4': 462 case '5': case '6': case '7': case '8': case '9': 463 case 'a': case 'b': case 'c': case 'd': case 'e': 464 case 'f': 465 case 'A': case 'B': case 'C': case 'D': case 'E': 466 case 'F': 467 state = STATE_CHAR_UD; 468 break; 469 default: 470 token_init(&parser->token, parser, 471 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 472 - token_pos, token_line, token_col); 473 return true; 474 } 475 break; 476 case STATE_CHAR_UD: 477 switch (c) { 478 case '0': case '1': case '2': case '3': case '4': 479 case '5': case '6': case '7': case '8': case '9': 480 case 'a': case 'b': case 'c': case 'd': case 'e': 481 case 'f': 482 case 'A': case 'B': case 'C': case 'D': case 'E': 483 case 'F': 484 state = STATE_CHAR_UDD; 485 break; 486 default: 487 token_init(&parser->token, parser, 488 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 489 - token_pos, token_line, token_col); 490 return true; 491 } 492 break; 493 case STATE_CHAR_UDD: 494 switch (c) { 495 case '0': case '1': case '2': case '3': case '4': 496 case '5': case '6': case '7': case '8': case '9': 497 case 'a': case 'b': case 'c': case 'd': case 'e': 498 case 'f': 499 case 'A': case 'B': case 'C': case 'D': case 'E': 500 case 'F': 501 state = STATE_CHAR_UDDD; 502 break; 503 default: 504 token_init(&parser->token, parser, 505 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 506 - token_pos, token_line, token_col); 507 return true; 508 } 509 break; 510 case STATE_CHAR_UDDD: 511 switch (c) { 512 case '0': case '1': case '2': case '3': case '4': 513 case '5': case '6': case '7': case '8': case '9': 514 case 'a': case 'b': case 'c': case 'd': case 'e': 515 case 'f': 516 case 'A': case 'B': case 'C': case 'D': case 'E': 517 case 'F': 518 state = STATE_CHARS; 519 break; 520 default: 521 token_init(&parser->token, parser, 522 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 523 - token_pos, token_line, token_col); 524 return true; 525 } 526 break; 527 case STATE_STRING: 528 token_init(&parser->token, parser, TOKEN_TYPE_STRING, 529 token_pos, parser->pos - token_pos, token_line, 530 token_col); 531 state = STATE_ACCEPT; 532 break; 533 case STATE_MINUS: 534 switch (c) { 535 case '0': 536 state = STATE_LEADING_ZERO; 537 break; 538 case '1': case '2': case '3': case '4': 539 case '5': case '6': case '7': case '8': case '9': 540 state = STATE_DIGITS; 541 break; 542 default: 543 token_init(&parser->token, parser, 544 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 545 - token_pos, token_line, token_col); 546 return true; 547 } 548 break; 549 case STATE_LEADING_ZERO: 550 switch (c) { 551 case '.': 552 state = STATE_DECIMAL; 553 break; 554 default: 555 token_init(&parser->token, parser, 556 TOKEN_TYPE_NUMBER, token_pos, parser->pos - 557 token_pos, token_line, token_col); 558 state = STATE_ACCEPT; 559 break; 560 } 561 break; 562 case STATE_DIGITS: 563 switch (c) { 564 case '0': case '1': case '2': case '3': case '4': 565 case '5': case '6': case '7': case '8': case '9': 566 break; 567 case '.': 568 state = STATE_DECIMAL; 569 break; 570 default: 571 token_init(&parser->token, parser, 572 TOKEN_TYPE_NUMBER, token_pos, parser->pos - 573 token_pos, token_line, token_col); 574 state = STATE_ACCEPT; 575 break; 576 } 577 break; 578 case STATE_DECIMAL: 579 switch (c) { 580 case '0': case '1': case '2': case '3': case '4': 581 case '5': case '6': case '7': case '8': case '9': 582 state = STATE_FRAC_DIGITS; 583 break; 584 default: 585 token_init(&parser->token, parser, 586 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 587 - token_pos, token_line, token_col); 588 return true; 589 } 590 break; 591 case STATE_FRAC_DIGITS: 592 switch (c) { 593 case '0': case '1': case '2': case '3': case '4': 594 case '5': case '6': case '7': case '8': case '9': 595 break; 596 case 'e': case 'E': 597 state = STATE_EXP; 598 break; 599 default: 600 token_init(&parser->token, parser, 601 TOKEN_TYPE_NUMBER, token_pos, parser->pos - 602 token_pos, token_line, token_col); 603 state = STATE_ACCEPT; 604 break; 605 } 606 break; 607 case STATE_EXP: 608 switch (c) { 609 case '-': case '+': 610 state = STATE_EXP_SIGN; 611 break; 612 case '0': case '1': case '2': case '3': case '4': 613 case '5': case '6': case '7': case '8': case '9': 614 state = STATE_EXP_DIGITS; 615 break; 616 default: 617 token_init(&parser->token, parser, 618 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 619 - token_pos, token_line, token_col); 620 return true; 621 } 622 break; 623 case STATE_EXP_SIGN: 624 switch (c) { 625 case '0': case '1': case '2': case '3': case '4': 626 case '5': case '6': case '7': case '8': case '9': 627 state = STATE_EXP_DIGITS; 628 break; 629 default: 630 token_init(&parser->token, parser, 631 TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 632 - token_pos, token_line, token_col); 633 return true; 634 } 635 break; 636 case STATE_EXP_DIGITS: 637 switch (c) { 638 case '0': case '1': case '2': case '3': case '4': 639 case '5': case '6': case '7': case '8': case '9': 640 break; 641 default: 642 token_init(&parser->token, parser, 643 TOKEN_TYPE_NUMBER, token_pos, parser->pos - 644 token_pos, token_line, token_col); 645 state = STATE_ACCEPT; 646 break; 647 } 648 break; 649 default: 650 not_reached(); 651 } 652 653 if (state != STATE_ACCEPT) { 654 if (c == '\n') { 655 parser->line++; 656 parser->col = 0; 657 } else { 658 parser->col++; 659 } 660 parser->pos++; 661 } 662 } 663 return false; 664} 665 666static bool parser_parse_array(parser_t *parser); 667static bool parser_parse_object(parser_t *parser); 668 669static bool 670parser_parse_value(parser_t *parser) 671{ 672 switch (parser->token.token_type) { 673 case TOKEN_TYPE_NULL: 674 case TOKEN_TYPE_FALSE: 675 case TOKEN_TYPE_TRUE: 676 case TOKEN_TYPE_STRING: 677 case TOKEN_TYPE_NUMBER: 678 return false; 679 case TOKEN_TYPE_LBRACE: 680 return parser_parse_object(parser); 681 case TOKEN_TYPE_LBRACKET: 682 return parser_parse_array(parser); 683 default: 684 return true; 685 } 686 not_reached(); 687} 688 689static bool 690parser_parse_pair(parser_t *parser) 691{ 692 assert_d_eq(parser->token.token_type, TOKEN_TYPE_STRING, 693 "Pair should start with string"); 694 if (parser_tokenize(parser)) { 695 return true; 696 } 697 switch (parser->token.token_type) { 698 case TOKEN_TYPE_COLON: 699 if (parser_tokenize(parser)) { 700 return true; 701 } 702 return parser_parse_value(parser); 703 default: 704 return true; 705 } 706} 707 708static bool 709parser_parse_values(parser_t *parser) 710{ 711 if (parser_parse_value(parser)) { 712 return true; 713 } 714 715 while (true) { 716 if (parser_tokenize(parser)) { 717 return true; 718 } 719 switch (parser->token.token_type) { 720 case TOKEN_TYPE_COMMA: 721 if (parser_tokenize(parser)) { 722 return true; 723 } 724 if (parser_parse_value(parser)) { 725 return true; 726 } 727 break; 728 case TOKEN_TYPE_RBRACKET: 729 return false; 730 default: 731 return true; 732 } 733 } 734} 735 736static bool 737parser_parse_array(parser_t *parser) 738{ 739 assert_d_eq(parser->token.token_type, TOKEN_TYPE_LBRACKET, 740 "Array should start with ["); 741 if (parser_tokenize(parser)) { 742 return true; 743 } 744 switch (parser->token.token_type) { 745 case TOKEN_TYPE_RBRACKET: 746 return false; 747 default: 748 return parser_parse_values(parser); 749 } 750 not_reached(); 751} 752 753static bool 754parser_parse_pairs(parser_t *parser) 755{ 756 assert_d_eq(parser->token.token_type, TOKEN_TYPE_STRING, 757 "Object should start with string"); 758 if (parser_parse_pair(parser)) { 759 return true; 760 } 761 762 while (true) { 763 if (parser_tokenize(parser)) { 764 return true; 765 } 766 switch (parser->token.token_type) { 767 case TOKEN_TYPE_COMMA: 768 if (parser_tokenize(parser)) { 769 return true; 770 } 771 switch (parser->token.token_type) { 772 case TOKEN_TYPE_STRING: 773 if (parser_parse_pair(parser)) { 774 return true; 775 } 776 break; 777 default: 778 return true; 779 } 780 break; 781 case TOKEN_TYPE_RBRACE: 782 return false; 783 default: 784 return true; 785 } 786 } 787} 788 789static bool 790parser_parse_object(parser_t *parser) 791{ 792 assert_d_eq(parser->token.token_type, TOKEN_TYPE_LBRACE, 793 "Object should start with {"); 794 if (parser_tokenize(parser)) { 795 return true; 796 } 797 switch (parser->token.token_type) { 798 case TOKEN_TYPE_STRING: 799 return parser_parse_pairs(parser); 800 case TOKEN_TYPE_RBRACE: 801 return false; 802 default: 803 return true; 804 } 805 not_reached(); 806} 807 808static bool 809parser_parse(parser_t *parser) 810{ 811 if (parser_tokenize(parser)) { 812 goto label_error; 813 } 814 if (parser_parse_value(parser)) { 815 goto label_error; 816 } 817 818 if (parser_tokenize(parser)) { 819 goto label_error; 820 } 821 switch (parser->token.token_type) { 822 case TOKEN_TYPE_EOI: 823 return false; 824 default: 825 goto label_error; 826 } 827 not_reached(); 828 829label_error: 830 token_error(&parser->token); 831 return true; 832} 833 834TEST_BEGIN(test_json_parser) 835{ 836 size_t i; 837 const char *invalid_inputs[] = { 838 /* Tokenizer error case tests. */ 839 "{ \"string\": X }", 840 "{ \"string\": nXll }", 841 "{ \"string\": nuXl }", 842 "{ \"string\": nulX }", 843 "{ \"string\": nullX }", 844 "{ \"string\": fXlse }", 845 "{ \"string\": faXse }", 846 "{ \"string\": falXe }", 847 "{ \"string\": falsX }", 848 "{ \"string\": falseX }", 849 "{ \"string\": tXue }", 850 "{ \"string\": trXe }", 851 "{ \"string\": truX }", 852 "{ \"string\": trueX }", 853 "{ \"string\": \"\n\" }", 854 "{ \"string\": \"\\z\" }", 855 "{ \"string\": \"\\uX000\" }", 856 "{ \"string\": \"\\u0X00\" }", 857 "{ \"string\": \"\\u00X0\" }", 858 "{ \"string\": \"\\u000X\" }", 859 "{ \"string\": -X }", 860 "{ \"string\": 0.X }", 861 "{ \"string\": 0.0eX }", 862 "{ \"string\": 0.0e+X }", 863 864 /* Parser error test cases. */ 865 "{\"string\": }", 866 "{\"string\" }", 867 "{\"string\": [ 0 }", 868 "{\"string\": {\"a\":0, 1 } }", 869 "{\"string\": {\"a\":0: } }", 870 "{", 871 "{}{", 872 }; 873 const char *valid_inputs[] = { 874 /* Token tests. */ 875 "null", 876 "false", 877 "true", 878 "{}", 879 "{\"a\": 0}", 880 "[]", 881 "[0, 1]", 882 "0", 883 "1", 884 "10", 885 "-10", 886 "10.23", 887 "10.23e4", 888 "10.23e-4", 889 "10.23e+4", 890 "10.23E4", 891 "10.23E-4", 892 "10.23E+4", 893 "-10.23", 894 "-10.23e4", 895 "-10.23e-4", 896 "-10.23e+4", 897 "-10.23E4", 898 "-10.23E-4", 899 "-10.23E+4", 900 "\"value\"", 901 "\" \\\" \\/ \\b \\n \\r \\t \\u0abc \\u1DEF \"", 902 903 /* Parser test with various nesting. */ 904 "{\"a\":null, \"b\":[1,[{\"c\":2},3]], \"d\":{\"e\":true}}", 905 }; 906 907 for (i = 0; i < sizeof(invalid_inputs)/sizeof(const char *); i++) { 908 const char *input = invalid_inputs[i]; 909 parser_t parser; 910 parser_init(&parser, false); 911 assert_false(parser_append(&parser, input), 912 "Unexpected input appending failure"); 913 assert_true(parser_parse(&parser), 914 "Unexpected parse success for input: %s", input); 915 parser_fini(&parser); 916 } 917 918 for (i = 0; i < sizeof(valid_inputs)/sizeof(const char *); i++) { 919 const char *input = valid_inputs[i]; 920 parser_t parser; 921 parser_init(&parser, true); 922 assert_false(parser_append(&parser, input), 923 "Unexpected input appending failure"); 924 assert_false(parser_parse(&parser), 925 "Unexpected parse error for input: %s", input); 926 parser_fini(&parser); 927 } 928} 929TEST_END 930 931void 932write_cb(void *opaque, const char *str) 933{ 934 parser_t *parser = (parser_t *)opaque; 935 if (parser_append(parser, str)) { 936 test_fail("Unexpected input appending failure"); 937 } 938} 939 940TEST_BEGIN(test_stats_print_json) 941{ 942 const char *opts[] = { 943 "J", 944 "Jg", 945 "Jm", 946 "Jd", 947 "Jmd", 948 "Jgd", 949 "Jgm", 950 "Jgmd", 951 "Ja", 952 "Jb", 953 "Jl", 954 "Jbl", 955 "Jal", 956 "Jab", 957 "Jabl", 958 "Jgmdabl", 959 }; 960 unsigned arena_ind, i; 961 962 for (i = 0; i < 3; i++) { 963 unsigned j; 964 965 switch (i) { 966 case 0: 967 break; 968 case 1: { 969 size_t sz = sizeof(arena_ind); 970 assert_d_eq(mallctl("arenas.create", (void *)&arena_ind, 971 &sz, NULL, 0), 0, "Unexpected mallctl failure"); 972 break; 973 } case 2: { 974 size_t mib[3]; 975 size_t miblen = sizeof(mib)/sizeof(size_t); 976 assert_d_eq(mallctlnametomib("arena.0.destroy", 977 mib, &miblen), 0, 978 "Unexpected mallctlnametomib failure"); 979 mib[1] = arena_ind; 980 assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 981 0), 0, "Unexpected mallctlbymib failure"); 982 break; 983 } default: 984 not_reached(); 985 } 986 987 for (j = 0; j < sizeof(opts)/sizeof(const char *); j++) { 988 parser_t parser; 989 990 parser_init(&parser, true); 991 malloc_stats_print(write_cb, (void *)&parser, opts[j]); 992 assert_false(parser_parse(&parser), 993 "Unexpected parse error, opts=\"%s\"", opts[j]); 994 parser_fini(&parser); 995 } 996 } 997} 998TEST_END 999 1000int 1001main(void) 1002{ 1003 return (test( 1004 test_json_parser, 1005 test_stats_print_json)); 1006} 1007