qemu/check-qjson.c
<<
>>
Prefs
   1/*
   2 * Copyright IBM, Corp. 2009
   3 *
   4 * Authors:
   5 *  Anthony Liguori   <aliguori@us.ibm.com>
   6 *
   7 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
   8 * See the COPYING.LIB file in the top-level directory.
   9 *
  10 */
  11#include <check.h>
  12
  13#include "qstring.h"
  14#include "qint.h"
  15#include "qdict.h"
  16#include "qlist.h"
  17#include "qfloat.h"
  18#include "qbool.h"
  19#include "qjson.h"
  20
  21#include "qemu-common.h"
  22
  23START_TEST(escaped_string)
  24{
  25    int i;
  26    struct {
  27        const char *encoded;
  28        const char *decoded;
  29        int skip;
  30    } test_cases[] = {
  31        { "\"\\b\"", "\b" },
  32        { "\"\\f\"", "\f" },
  33        { "\"\\n\"", "\n" },
  34        { "\"\\r\"", "\r" },
  35        { "\"\\t\"", "\t" },
  36        { "\"\\/\"", "\\/" },
  37        { "\"\\\\\"", "\\" },
  38        { "\"\\\"\"", "\"" },
  39        { "\"hello world \\\"embedded string\\\"\"",
  40          "hello world \"embedded string\"" },
  41        { "\"hello world\\nwith new line\"", "hello world\nwith new line" },
  42        { "\"single byte utf-8 \\u0020\"", "single byte utf-8  ", .skip = 1 },
  43        { "\"double byte utf-8 \\u00A2\"", "double byte utf-8 \xc2\xa2" },
  44        { "\"triple byte utf-8 \\u20AC\"", "triple byte utf-8 \xe2\x82\xac" },
  45        {}
  46    };
  47
  48    for (i = 0; test_cases[i].encoded; i++) {
  49        QObject *obj;
  50        QString *str;
  51
  52        obj = qobject_from_json(test_cases[i].encoded);
  53
  54        fail_unless(obj != NULL);
  55        fail_unless(qobject_type(obj) == QTYPE_QSTRING);
  56        
  57        str = qobject_to_qstring(obj);
  58        fail_unless(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0,
  59                    "%s != %s\n", qstring_get_str(str), test_cases[i].decoded);
  60
  61        if (test_cases[i].skip == 0) {
  62            str = qobject_to_json(obj);
  63            fail_unless(strcmp(qstring_get_str(str),test_cases[i].encoded) == 0,
  64                        "%s != %s\n", qstring_get_str(str),
  65                                      test_cases[i].encoded);
  66
  67            qobject_decref(obj);
  68        }
  69
  70        QDECREF(str);
  71    }
  72}
  73END_TEST
  74
  75START_TEST(simple_string)
  76{
  77    int i;
  78    struct {
  79        const char *encoded;
  80        const char *decoded;
  81    } test_cases[] = {
  82        { "\"hello world\"", "hello world" },
  83        { "\"the quick brown fox jumped over the fence\"",
  84          "the quick brown fox jumped over the fence" },
  85        {}
  86    };
  87
  88    for (i = 0; test_cases[i].encoded; i++) {
  89        QObject *obj;
  90        QString *str;
  91
  92        obj = qobject_from_json(test_cases[i].encoded);
  93
  94        fail_unless(obj != NULL);
  95        fail_unless(qobject_type(obj) == QTYPE_QSTRING);
  96        
  97        str = qobject_to_qstring(obj);
  98        fail_unless(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
  99
 100        str = qobject_to_json(obj);
 101        fail_unless(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0);
 102
 103        qobject_decref(obj);
 104        
 105        QDECREF(str);
 106    }
 107}
 108END_TEST
 109
 110START_TEST(single_quote_string)
 111{
 112    int i;
 113    struct {
 114        const char *encoded;
 115        const char *decoded;
 116    } test_cases[] = {
 117        { "'hello world'", "hello world" },
 118        { "'the quick brown fox \\' jumped over the fence'",
 119          "the quick brown fox ' jumped over the fence" },
 120        {}
 121    };
 122
 123    for (i = 0; test_cases[i].encoded; i++) {
 124        QObject *obj;
 125        QString *str;
 126
 127        obj = qobject_from_json(test_cases[i].encoded);
 128
 129        fail_unless(obj != NULL);
 130        fail_unless(qobject_type(obj) == QTYPE_QSTRING);
 131        
 132        str = qobject_to_qstring(obj);
 133        fail_unless(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
 134
 135        QDECREF(str);
 136    }
 137}
 138END_TEST
 139
 140START_TEST(vararg_string)
 141{
 142    int i;
 143    struct {
 144        const char *decoded;
 145    } test_cases[] = {
 146        { "hello world" },
 147        { "the quick brown fox jumped over the fence" },
 148        {}
 149    };
 150
 151    for (i = 0; test_cases[i].decoded; i++) {
 152        QObject *obj;
 153        QString *str;
 154
 155        obj = qobject_from_jsonf("%s", test_cases[i].decoded);
 156
 157        fail_unless(obj != NULL);
 158        fail_unless(qobject_type(obj) == QTYPE_QSTRING);
 159        
 160        str = qobject_to_qstring(obj);
 161        fail_unless(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
 162
 163        QDECREF(str);
 164    }
 165}
 166END_TEST
 167
 168START_TEST(simple_number)
 169{
 170    int i;
 171    struct {
 172        const char *encoded;
 173        int64_t decoded;
 174        int skip;
 175    } test_cases[] = {
 176        { "0", 0 },
 177        { "1234", 1234 },
 178        { "1", 1 },
 179        { "-32", -32 },
 180        { "-0", 0, .skip = 1 },
 181        { },
 182    };
 183
 184    for (i = 0; test_cases[i].encoded; i++) {
 185        QObject *obj;
 186        QInt *qint;
 187
 188        obj = qobject_from_json(test_cases[i].encoded);
 189        fail_unless(obj != NULL);
 190        fail_unless(qobject_type(obj) == QTYPE_QINT);
 191
 192        qint = qobject_to_qint(obj);
 193        fail_unless(qint_get_int(qint) == test_cases[i].decoded);
 194        if (test_cases[i].skip == 0) {
 195            QString *str;
 196
 197            str = qobject_to_json(obj);
 198            fail_unless(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0);
 199            QDECREF(str);
 200        }
 201
 202        QDECREF(qint);
 203    }
 204}
 205END_TEST
 206
 207START_TEST(float_number)
 208{
 209    int i;
 210    struct {
 211        const char *encoded;
 212        double decoded;
 213        int skip;
 214    } test_cases[] = {
 215        { "32.43", 32.43 },
 216        { "0.222", 0.222 },
 217        { "-32.12313", -32.12313 },
 218        { "-32.20e-10", -32.20e-10, .skip = 1 },
 219        { },
 220    };
 221
 222    for (i = 0; test_cases[i].encoded; i++) {
 223        QObject *obj;
 224        QFloat *qfloat;
 225
 226        obj = qobject_from_json(test_cases[i].encoded);
 227        fail_unless(obj != NULL);
 228        fail_unless(qobject_type(obj) == QTYPE_QFLOAT);
 229
 230        qfloat = qobject_to_qfloat(obj);
 231        fail_unless(qfloat_get_double(qfloat) == test_cases[i].decoded);
 232
 233        if (test_cases[i].skip == 0) {
 234            QString *str;
 235
 236            str = qobject_to_json(obj);
 237            fail_unless(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0);
 238            QDECREF(str);
 239        }
 240
 241        QDECREF(qfloat);
 242    }
 243}
 244END_TEST
 245
 246START_TEST(vararg_number)
 247{
 248    QObject *obj;
 249    QInt *qint;
 250    QFloat *qfloat;
 251    int value = 0x2342;
 252    int64_t value64 = 0x2342342343LL;
 253    double valuef = 2.323423423;
 254
 255    obj = qobject_from_jsonf("%d", value);
 256    fail_unless(obj != NULL);
 257    fail_unless(qobject_type(obj) == QTYPE_QINT);
 258
 259    qint = qobject_to_qint(obj);
 260    fail_unless(qint_get_int(qint) == value);
 261
 262    QDECREF(qint);
 263
 264    obj = qobject_from_jsonf("%" PRId64, value64);
 265    fail_unless(obj != NULL);
 266    fail_unless(qobject_type(obj) == QTYPE_QINT);
 267
 268    qint = qobject_to_qint(obj);
 269    fail_unless(qint_get_int(qint) == value64);
 270
 271    QDECREF(qint);
 272
 273    obj = qobject_from_jsonf("%f", valuef);
 274    fail_unless(obj != NULL);
 275    fail_unless(qobject_type(obj) == QTYPE_QFLOAT);
 276
 277    qfloat = qobject_to_qfloat(obj);
 278    fail_unless(qfloat_get_double(qfloat) == valuef);
 279
 280    QDECREF(qfloat);
 281}
 282END_TEST
 283
 284START_TEST(keyword_literal)
 285{
 286    QObject *obj;
 287    QBool *qbool;
 288    QString *str;
 289
 290    obj = qobject_from_json("true");
 291    fail_unless(obj != NULL);
 292    fail_unless(qobject_type(obj) == QTYPE_QBOOL);
 293
 294    qbool = qobject_to_qbool(obj);
 295    fail_unless(qbool_get_int(qbool) != 0);
 296
 297    str = qobject_to_json(obj);
 298    fail_unless(strcmp(qstring_get_str(str), "true") == 0);
 299    QDECREF(str);
 300
 301    QDECREF(qbool);
 302
 303    obj = qobject_from_json("false");
 304    fail_unless(obj != NULL);
 305    fail_unless(qobject_type(obj) == QTYPE_QBOOL);
 306
 307    qbool = qobject_to_qbool(obj);
 308    fail_unless(qbool_get_int(qbool) == 0);
 309
 310    str = qobject_to_json(obj);
 311    fail_unless(strcmp(qstring_get_str(str), "false") == 0);
 312    QDECREF(str);
 313
 314    QDECREF(qbool);
 315
 316    obj = qobject_from_jsonf("%i", false);
 317    fail_unless(obj != NULL);
 318    fail_unless(qobject_type(obj) == QTYPE_QBOOL);
 319
 320    qbool = qobject_to_qbool(obj);
 321    fail_unless(qbool_get_int(qbool) == 0);
 322
 323    QDECREF(qbool);
 324    
 325    obj = qobject_from_jsonf("%i", true);
 326    fail_unless(obj != NULL);
 327    fail_unless(qobject_type(obj) == QTYPE_QBOOL);
 328
 329    qbool = qobject_to_qbool(obj);
 330    fail_unless(qbool_get_int(qbool) != 0);
 331
 332    QDECREF(qbool);
 333}
 334END_TEST
 335
 336typedef struct LiteralQDictEntry LiteralQDictEntry;
 337typedef struct LiteralQObject LiteralQObject;
 338
 339struct LiteralQObject
 340{
 341    int type;
 342    union {
 343        int64_t qint;
 344        const char *qstr;
 345        LiteralQDictEntry *qdict;
 346        LiteralQObject *qlist;
 347    } value;
 348};
 349
 350struct LiteralQDictEntry
 351{
 352    const char *key;
 353    LiteralQObject value;
 354};
 355
 356#define QLIT_QINT(val) (LiteralQObject){.type = QTYPE_QINT, .value.qint = (val)}
 357#define QLIT_QSTR(val) (LiteralQObject){.type = QTYPE_QSTRING, .value.qstr = (val)}
 358#define QLIT_QDICT(val) (LiteralQObject){.type = QTYPE_QDICT, .value.qdict = (val)}
 359#define QLIT_QLIST(val) (LiteralQObject){.type = QTYPE_QLIST, .value.qlist = (val)}
 360
 361typedef struct QListCompareHelper
 362{
 363    int index;
 364    LiteralQObject *objs;
 365    int result;
 366} QListCompareHelper;
 367
 368static int compare_litqobj_to_qobj(LiteralQObject *lhs, QObject *rhs);
 369
 370static void compare_helper(QObject *obj, void *opaque)
 371{
 372    QListCompareHelper *helper = opaque;
 373
 374    if (helper->result == 0) {
 375        return;
 376    }
 377
 378    if (helper->objs[helper->index].type == QTYPE_NONE) {
 379        helper->result = 0;
 380        return;
 381    }
 382
 383    helper->result = compare_litqobj_to_qobj(&helper->objs[helper->index++], obj);
 384}
 385
 386static int compare_litqobj_to_qobj(LiteralQObject *lhs, QObject *rhs)
 387{
 388    if (lhs->type != qobject_type(rhs)) {
 389        return 0;
 390    }
 391
 392    switch (lhs->type) {
 393    case QTYPE_QINT:
 394        return lhs->value.qint == qint_get_int(qobject_to_qint(rhs));
 395    case QTYPE_QSTRING:
 396        return (strcmp(lhs->value.qstr, qstring_get_str(qobject_to_qstring(rhs))) == 0);
 397    case QTYPE_QDICT: {
 398        int i;
 399
 400        for (i = 0; lhs->value.qdict[i].key; i++) {
 401            QObject *obj = qdict_get(qobject_to_qdict(rhs), lhs->value.qdict[i].key);
 402
 403            if (!compare_litqobj_to_qobj(&lhs->value.qdict[i].value, obj)) {
 404                return 0;
 405            }
 406        }
 407
 408        return 1;
 409    }
 410    case QTYPE_QLIST: {
 411        QListCompareHelper helper;
 412
 413        helper.index = 0;
 414        helper.objs = lhs->value.qlist;
 415        helper.result = 1;
 416        
 417        qlist_iter(qobject_to_qlist(rhs), compare_helper, &helper);
 418
 419        return helper.result;
 420    }
 421    default:
 422        break;
 423    }
 424
 425    return 0;
 426}
 427
 428START_TEST(simple_dict)
 429{
 430    int i;
 431    struct {
 432        const char *encoded;
 433        LiteralQObject decoded;
 434    } test_cases[] = {
 435        {
 436            .encoded = "{\"foo\": 42, \"bar\": \"hello world\"}",
 437            .decoded = QLIT_QDICT(((LiteralQDictEntry[]){
 438                        { "foo", QLIT_QINT(42) },
 439                        { "bar", QLIT_QSTR("hello world") },
 440                        { }
 441                    })),
 442        }, {
 443            .encoded = "{}",
 444            .decoded = QLIT_QDICT(((LiteralQDictEntry[]){
 445                        { }
 446                    })),
 447        }, {
 448            .encoded = "{\"foo\": 43}",
 449            .decoded = QLIT_QDICT(((LiteralQDictEntry[]){
 450                        { "foo", QLIT_QINT(43) },
 451                        { }
 452                    })),
 453        },
 454        { }
 455    };
 456
 457    for (i = 0; test_cases[i].encoded; i++) {
 458        QObject *obj;
 459        QString *str;
 460
 461        obj = qobject_from_json(test_cases[i].encoded);
 462        fail_unless(obj != NULL);
 463        fail_unless(qobject_type(obj) == QTYPE_QDICT);
 464
 465        fail_unless(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
 466
 467        str = qobject_to_json(obj);
 468        qobject_decref(obj);
 469
 470        obj = qobject_from_json(qstring_get_str(str));
 471        fail_unless(obj != NULL);
 472        fail_unless(qobject_type(obj) == QTYPE_QDICT);
 473
 474        fail_unless(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
 475        qobject_decref(obj);
 476        QDECREF(str);
 477    }
 478}
 479END_TEST
 480
 481START_TEST(simple_list)
 482{
 483    int i;
 484    struct {
 485        const char *encoded;
 486        LiteralQObject decoded;
 487    } test_cases[] = {
 488        {
 489            .encoded = "[43,42]",
 490            .decoded = QLIT_QLIST(((LiteralQObject[]){
 491                        QLIT_QINT(43),
 492                        QLIT_QINT(42),
 493                        { }
 494                    })),
 495        },
 496        {
 497            .encoded = "[43]",
 498            .decoded = QLIT_QLIST(((LiteralQObject[]){
 499                        QLIT_QINT(43),
 500                        { }
 501                    })),
 502        },
 503        {
 504            .encoded = "[]",
 505            .decoded = QLIT_QLIST(((LiteralQObject[]){
 506                        { }
 507                    })),
 508        },
 509        {
 510            .encoded = "[{}]",
 511            .decoded = QLIT_QLIST(((LiteralQObject[]){
 512                        QLIT_QDICT(((LiteralQDictEntry[]){
 513                                    {},
 514                                        })),
 515                        {},
 516                            })),
 517        },
 518        { }
 519    };
 520
 521    for (i = 0; test_cases[i].encoded; i++) {
 522        QObject *obj;
 523        QString *str;
 524
 525        obj = qobject_from_json(test_cases[i].encoded);
 526        fail_unless(obj != NULL);
 527        fail_unless(qobject_type(obj) == QTYPE_QLIST);
 528
 529        fail_unless(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
 530
 531        str = qobject_to_json(obj);
 532        qobject_decref(obj);
 533
 534        obj = qobject_from_json(qstring_get_str(str));
 535        fail_unless(obj != NULL);
 536        fail_unless(qobject_type(obj) == QTYPE_QLIST);
 537
 538        fail_unless(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
 539        qobject_decref(obj);
 540        QDECREF(str);
 541    }
 542}
 543END_TEST
 544
 545START_TEST(simple_whitespace)
 546{
 547    int i;
 548    struct {
 549        const char *encoded;
 550        LiteralQObject decoded;
 551    } test_cases[] = {
 552        {
 553            .encoded = " [ 43 , 42 ]",
 554            .decoded = QLIT_QLIST(((LiteralQObject[]){
 555                        QLIT_QINT(43),
 556                        QLIT_QINT(42),
 557                        { }
 558                    })),
 559        },
 560        {
 561            .encoded = " [ 43 , { 'h' : 'b' }, [ ], 42 ]",
 562            .decoded = QLIT_QLIST(((LiteralQObject[]){
 563                        QLIT_QINT(43),
 564                        QLIT_QDICT(((LiteralQDictEntry[]){
 565                                    { "h", QLIT_QSTR("b") },
 566                                    { }})),
 567                        QLIT_QLIST(((LiteralQObject[]){
 568                                    { }})),
 569                        QLIT_QINT(42),
 570                        { }
 571                    })),
 572        },
 573        {
 574            .encoded = " [ 43 , { 'h' : 'b' , 'a' : 32 }, [ ], 42 ]",
 575            .decoded = QLIT_QLIST(((LiteralQObject[]){
 576                        QLIT_QINT(43),
 577                        QLIT_QDICT(((LiteralQDictEntry[]){
 578                                    { "h", QLIT_QSTR("b") },
 579                                    { "a", QLIT_QINT(32) },
 580                                    { }})),
 581                        QLIT_QLIST(((LiteralQObject[]){
 582                                    { }})),
 583                        QLIT_QINT(42),
 584                        { }
 585                    })),
 586        },
 587        { }
 588    };
 589
 590    for (i = 0; test_cases[i].encoded; i++) {
 591        QObject *obj;
 592        QString *str;
 593
 594        obj = qobject_from_json(test_cases[i].encoded);
 595        fail_unless(obj != NULL);
 596        fail_unless(qobject_type(obj) == QTYPE_QLIST);
 597
 598        fail_unless(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
 599
 600        str = qobject_to_json(obj);
 601        qobject_decref(obj);
 602
 603        obj = qobject_from_json(qstring_get_str(str));
 604        fail_unless(obj != NULL);
 605        fail_unless(qobject_type(obj) == QTYPE_QLIST);
 606
 607        fail_unless(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
 608
 609        qobject_decref(obj);
 610        QDECREF(str);
 611    }
 612}
 613END_TEST
 614
 615START_TEST(simple_varargs)
 616{
 617    QObject *embedded_obj;
 618    QObject *obj;
 619    LiteralQObject decoded = QLIT_QLIST(((LiteralQObject[]){
 620            QLIT_QINT(1),
 621            QLIT_QINT(2),
 622            QLIT_QLIST(((LiteralQObject[]){
 623                        QLIT_QINT(32),
 624                        QLIT_QINT(42),
 625                        {}})),
 626            {}}));
 627
 628    embedded_obj = qobject_from_json("[32, 42]");
 629    fail_unless(embedded_obj != NULL);
 630
 631    obj = qobject_from_jsonf("[%d, 2, %p]", 1, embedded_obj);
 632    fail_unless(obj != NULL);
 633
 634    fail_unless(compare_litqobj_to_qobj(&decoded, obj) == 1);
 635
 636    qobject_decref(obj);
 637}
 638END_TEST
 639
 640START_TEST(empty_input)
 641{
 642    const char *empty = "";
 643
 644    QObject *obj = qobject_from_json(empty);
 645    fail_unless(obj == NULL);
 646}
 647END_TEST
 648
 649START_TEST(unterminated_string)
 650{
 651    QObject *obj = qobject_from_json("\"abc");
 652    fail_unless(obj == NULL);
 653}
 654END_TEST
 655
 656START_TEST(unterminated_sq_string)
 657{
 658    QObject *obj = qobject_from_json("'abc");
 659    fail_unless(obj == NULL);
 660}
 661END_TEST
 662
 663START_TEST(unterminated_escape)
 664{
 665    QObject *obj = qobject_from_json("\"abc\\\"");
 666    fail_unless(obj == NULL);
 667}
 668END_TEST
 669
 670START_TEST(unterminated_array)
 671{
 672    QObject *obj = qobject_from_json("[32");
 673    fail_unless(obj == NULL);
 674}
 675END_TEST
 676
 677START_TEST(unterminated_array_comma)
 678{
 679    QObject *obj = qobject_from_json("[32,");
 680    fail_unless(obj == NULL);
 681}
 682END_TEST
 683
 684START_TEST(invalid_array_comma)
 685{
 686    QObject *obj = qobject_from_json("[32,}");
 687    fail_unless(obj == NULL);
 688}
 689END_TEST
 690
 691START_TEST(unterminated_dict)
 692{
 693    QObject *obj = qobject_from_json("{'abc':32");
 694    fail_unless(obj == NULL);
 695}
 696END_TEST
 697
 698START_TEST(unterminated_dict_comma)
 699{
 700    QObject *obj = qobject_from_json("{'abc':32,");
 701    fail_unless(obj == NULL);
 702}
 703END_TEST
 704
 705#if 0
 706START_TEST(invalid_dict_comma)
 707{
 708    QObject *obj = qobject_from_json("{'abc':32,}");
 709    fail_unless(obj == NULL);
 710}
 711END_TEST
 712
 713START_TEST(unterminated_literal)
 714{
 715    QObject *obj = qobject_from_json("nul");
 716    fail_unless(obj == NULL);
 717}
 718END_TEST
 719#endif
 720
 721static Suite *qjson_suite(void)
 722{
 723    Suite *suite;
 724    TCase *string_literals, *number_literals, *keyword_literals;
 725    TCase *dicts, *lists, *whitespace, *varargs, *errors;
 726
 727    string_literals = tcase_create("String Literals");
 728    tcase_add_test(string_literals, simple_string);
 729    tcase_add_test(string_literals, escaped_string);
 730    tcase_add_test(string_literals, single_quote_string);
 731    tcase_add_test(string_literals, vararg_string);
 732
 733    number_literals = tcase_create("Number Literals");
 734    tcase_add_test(number_literals, simple_number);
 735    tcase_add_test(number_literals, float_number);
 736    tcase_add_test(number_literals, vararg_number);
 737
 738    keyword_literals = tcase_create("Keywords");
 739    tcase_add_test(keyword_literals, keyword_literal);
 740    dicts = tcase_create("Objects");
 741    tcase_add_test(dicts, simple_dict);
 742    lists = tcase_create("Lists");
 743    tcase_add_test(lists, simple_list);
 744
 745    whitespace = tcase_create("Whitespace");
 746    tcase_add_test(whitespace, simple_whitespace);
 747
 748    varargs = tcase_create("Varargs");
 749    tcase_add_test(varargs, simple_varargs);
 750
 751    errors = tcase_create("Invalid JSON");
 752    tcase_add_test(errors, empty_input);
 753    tcase_add_test(errors, unterminated_string);
 754    tcase_add_test(errors, unterminated_escape);
 755    tcase_add_test(errors, unterminated_sq_string);
 756    tcase_add_test(errors, unterminated_array);
 757    tcase_add_test(errors, unterminated_array_comma);
 758    tcase_add_test(errors, invalid_array_comma);
 759    tcase_add_test(errors, unterminated_dict);
 760    tcase_add_test(errors, unterminated_dict_comma);
 761#if 0
 762    /* FIXME: this print parse error messages on stderr.  */
 763    tcase_add_test(errors, invalid_dict_comma);
 764    tcase_add_test(errors, unterminated_literal);
 765#endif
 766
 767    suite = suite_create("QJSON test-suite");
 768    suite_add_tcase(suite, string_literals);
 769    suite_add_tcase(suite, number_literals);
 770    suite_add_tcase(suite, keyword_literals);
 771    suite_add_tcase(suite, dicts);
 772    suite_add_tcase(suite, lists);
 773    suite_add_tcase(suite, whitespace);
 774    suite_add_tcase(suite, varargs);
 775    suite_add_tcase(suite, errors);
 776
 777    return suite;
 778}
 779
 780int main(void)
 781{
 782    int nf;
 783    Suite *s;
 784    SRunner *sr;
 785
 786    s = qjson_suite();
 787    sr = srunner_create(s);
 788        
 789    srunner_run_all(sr, CK_NORMAL);
 790    nf = srunner_ntests_failed(sr);
 791    srunner_free(sr);
 792    
 793    return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
 794}
 795