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