json parse

学习Moli的代码
leptjson.h

#ifndef LEPTJSON_H__
#define LEPTJSON_H__

typedef enum { 
    LEPT_NULL, LEPT_FALSE, LEPT_TRUE, LEPT_NUMBER, LEPT_STRING, LEPT_ARRAY, LEPT_OBJECT } lept_type;


typedef struct lept_value lept_value;
typedef struct lept_member lept_member;

struct lept_value{
    union {
        struct { lept_member* m; size_t size; } o;
        struct { lept_value* e; size_t size; } a; /* array */
        struct { char* s; size_t len; } s;
        double n;
    } u;    
    lept_type type;
};

struct lept_member {
    char* k; size_t klen;   /* member key string, key string length */
    lept_value v;           /* member value */ 
};


int lept_parse(lept_value* v, const char* json);

/* return value */
enum {
    LEPT_PARSE_OK = 0,
    LEPT_PARSE_EXPECT_VALUE,
    LEPT_PARSE_INVALID_VALUE,
    LEPT_PARSE_ROOT_NOT_SINGULAR,
    LEPT_PARSE_NUMBER_TOO_BIG,
    LEPT_PARSE_MISS_QUOTATION_MARK,
    LEPT_PARSE_INVALID_STRING_ESCAPE,
    LEPT_PARSE_INVALID_STRING_CHAR,
    LEPT_PARSE_INVALID_UNICODE_HEX,
    LEPT_PARSE_INVALID_UNICODE_SURROGATE,
    LEPT_PARSE_MISS_COMMA_OR_SQUARE_BACKET,
    LEPT_PARSE_MISS_KEY,
    LEPT_PARSE_MISS_COLON,
    LEPT_PARSE_MISS_COMMA_OR_CURLY_BRACKET,
    LEPT_STRINGIFY_OK
};

/* 由于我们会检查v的类型,在调用所有访问函数之前,我们必须初始化该类型 */
#define lept_init(v) do { (v)->type = LEPT_NULL; } while (0)
lept_type lept_get_type(const lept_value* v);
void lept_free(lept_value* v);

double lept_get_number(const lept_value* v);

const char* lept_get_string(const lept_value* v);
size_t lept_get_string_length(const lept_value* v);
void lept_set_string(lept_value* v, const char* s, size_t len);

int lept_get_boolean(const lept_value* v);
void lept_set_boolean(lept_value* v, int b);

size_t lept_get_array_size(const lept_value* v);
lept_value* lept_get_array_element(const lept_value* v, size_t index);

size_t lept_get_object_size(const lept_value* v);
const char* lept_get_object_key(const lept_value* v, size_t index);
size_t lept_get_object_key_length(const lept_value* v, size_t index);
lept_value* lept_get_object_value(const lept_value* v, size_t index);

int lept_stringify(const lept_value* v, char** json, size_t* len);
#endif 
#include <stdlib.h>     /* NULL, strtod(), malloc(), realloc(), free()*/
#include "leptjson.h"
#include <assert.h>
#include <errno.h>      /* errno, ERANGE */
#include <math.h>       /* HUGE_VAL */
#include <string.h>     /* memecpy() */

#ifndef LEPT_PARSE_STACK_INIT_SIZE
#define LEPT_PARSE_STACK_INIT_SIZE 256
#endif

#ifndef LEPT_PARSE_STRINGIFY_INIT_SIZE
#define LEPT_PARSE_STRINGIFY_INIT_SIZE 256
#endif

#define EXPECT(c, ch) do { assert(*c->json == (ch)); c->json++; } while(0)
#define ISDIGIT(ch) ((ch) >= '0' && (ch) <= '9')
#define ISDIGIT1TO9(ch) ((ch) >= '1' && (ch) <= '9')
#define PUTC(c, ch) do { *(char*)lept_context_push(c, sizeof(char)) = (ch); } while (0)
#define PUTS(c, s, len) memcpy(lept_context_push(c, len), s, len)

typedef struct {
    const char* json;
    char* stack;
    size_t size, top;
} lept_context;


/* ws = *(%x20 / %x09 / %x0A / %x0D) */
static void lept_parse_whitespace(lept_context* c) {
    const char *p = c->json;
    while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r')
        ++p;
    c->json = p;            
}

#if 0
static int lept_parse_null(lept_context* c, lept_value* v) {
    EXPECT(c, 'n');
    if (c->json[0] != 'u' || c->json[1] != 'l' || c->json[2] != 'l')
        return LEPT_PARSE_INVALID_VALUE;
    c->json += 3;
    v->type = LEPT_NULL;
    return LEPT_PARSE_OK;
}

static int lept_parse_true(lept_context* c, lept_value* v) {
    EXPECT(c, 't');
    if (c->json[0] != 'r' || c->json[1] != 'u' || c->json[2] != 'e')
        return LEPT_PARSE_INVALID_VALUE;
    c->json += 3;
    v->type = LEPT_TRUE;
    return LEPT_PARSE_OK;
}

static int lept_parse_false(lept_context* c, lept_value* v) {
    EXPECT(c, 'f');
    if (c->json[0] != 'a' || c->json[1] != 'l' || c->json[2] != 's' || c->json[3] != 'e')
        return LEPT_PARSE_INVALID_VALUE;
    c->json += 4;
    v->type = LEPT_FALSE;
    return LEPT_PARSE_OK;
}
#endif

static int lept_parse_literal(lept_context* c, lept_value* v, const char* literal, lept_type type) {
    EXPECT(c, literal[0]);
    size_t i;
    for (i = 0; literal[i + 1] != '\0'; ++i) {
        if (c->json[i] != literal[i + 1] )
            return LEPT_PARSE_INVALID_VALUE;
    }
    c->json += i;
    v->type = type;
    return LEPT_PARSE_OK;
}

static int lept_parse_number(lept_context* c, lept_value* v) {
    const char* p = c->json;
    if (*p == '-') ++p;
    if (*p == '0') ++p;
    else {
        if(!ISDIGIT1TO9(*p)) return LEPT_PARSE_INVALID_VALUE;
        for (++p; ISDIGIT(*p); ++p) ;
    }
    if (*p == '.') {
        ++p;
        if (!ISDIGIT(*p)) return LEPT_PARSE_INVALID_VALUE;
        for (++p; ISDIGIT(*p); ++p) ;
    }

    if (*p == 'e' || *p == 'E') {
        ++p;
        if (*p == '-' || *p == '+') ++p;
        if (!ISDIGIT(*p)) return LEPT_PARSE_INVALID_VALUE;
        for (++p; ISDIGIT(*p); ++p) ;
    }

    errno = 0;
    v->u.n = strtod(c->json, NULL);
    if (errno == ERANGE && (v->u.n == HUGE_VAL || v->u.n == -HUGE_VAL))
        return LEPT_PARSE_NUMBER_TOO_BIG;
    v->type = LEPT_NUMBER;
    c->json = p;
    return LEPT_PARSE_OK;
}

/* chapter 3 */

void lept_free(lept_value* v) {
    size_t i;
    assert(v != NULL);
    if (v->type == LEPT_STRING)
        free(v->u.s.s);
    if (v->type == LEPT_ARRAY) {
        for (i = 0; i != v->u.a.size; ++i) 
            lept_free(&v->u.a.e[i]);
        free(v->u.a.e);
    }
    if (v->type == LEPT_OBJECT) {
        for (i = 0; i != v->u.o.size; ++i) {
            free(v->u.o.m[i].k);
            lept_free(&v->u.o.m[i].v);
        }   
        free(v->u.o.m);
    }

    v->type = LEPT_NULL;
}

/* 返回数据起始指针 */
static void* lept_context_push(lept_context* c, size_t size) {
    void* ret;
    assert(size > 0);
    if (c->top + size >= c->size) {
        if (c->size == 0)
            c->size = LEPT_PARSE_STACK_INIT_SIZE;
        while (c->top + size >= c->size)
            c->size += c->size >> 1;
        c->stack = (char*)realloc(c->stack, c->size);
    }
    ret = c->stack + c->top;
    c->top += size;
    return ret;
}

static void* lept_context_pop(lept_context* c, size_t size) {
    assert(c->top >= size);
    return c->stack + (c->top -= size);
}

#define STRING_ERROR(ret) do { c->top = head; return ret; } while (0)

char* lept_parse_hex4(const char*p, unsigned* u) {
    int i;
    *u = 0;
    for (i = 0; i != 4; ++i) {
        char ch = *p++;
        *u <<= 4;
        if (ch >= '0' && ch <= '9')
            *u |= ch - '0';
        else if (ch >= 'a' && ch <= 'f') 
            *u |= ch - 'a' + 10;
        else if (ch >= 'A' && ch <= 'F')
            *u |= ch - 'A' + 10;
        else
           return NULL;
    }
    return p;
}   

void lept_encode_utf8(lept_context* c, unsigned u) {
    if (u <= 0x007F) 
        PUTC(c, u);
    else if (u <= 0x07FF) {
        PUTC(c, ((u >> 6) & 0xFF) | 0xC0);
        PUTC(c, ( u       & 0x3F) | 0x80);
    }
    else if (u <= 0xFFFF) {
        PUTC(c, ((u >> 12) & 0xFF) | 0xE0);
        PUTC(c, ((u >>  6) & 0x3F) | 0x80);
        PUTC(c, ( u        & 0x3F) | 0x80);
    }
    else if (u <= 0x10FFFF) {
        PUTC(c, ((u >> 18) & 0xFF) | 0xF0);
        PUTC(c, ((u >> 12) & 0x3F) | 0x80);
        PUTC(c, ((u >>  6) & 0x3F) | 0x80);
        PUTC(c, ( u        & 0x3F) | 0x80);
    }
}

static int lept_parse_string_raw(lept_context* c, char** str, size_t* len) {
    size_t head = c->top;
    const char* p;
    EXPECT(c, '\"');
    p = c->json;
    unsigned u, u2;
    for (;;) {
        char ch = *p++;
        switch (ch) {
            case '\"':
                *len = c->top - head;
                *str = (char*)lept_context_pop(c,*len);
                c->json = p;
                return LEPT_PARSE_OK;
            case '\\':
                switch (*p++) {
                    case '\"' : PUTC(c, '\"'); break;
                    case '\\' : PUTC(c, '\\'); break;
                    case '/'  : PUTC(c, '/' ); break;
                    case 'b'  : PUTC(c, '\b'); break;
                    case 'f'  : PUTC(c, '\f'); break;
                    case 'n'  : PUTC(c, '\n'); break;
                    case 'r'  : PUTC(c, '\r'); break;
                    case 't'  : PUTC(c, '\t'); break;
                    case 'u'  : 
                        if (!(p = lept_parse_hex4(p, &u)))
                            STRING_ERROR(LEPT_PARSE_INVALID_UNICODE_HEX);
                        if (u >= 0xD800 && u <= 0xDBFF) { /* surrogate pair */
                            if (*p++ != '\\')
                                STRING_ERROR(LEPT_PARSE_INVALID_UNICODE_HEX);
                            if (*p++ != 'u')
                                STRING_ERROR(LEPT_PARSE_INVALID_UNICODE_HEX);
                            if (!(p = lept_parse_hex4(p, &u2)))
                                STRING_ERROR(LEPT_PARSE_INVALID_UNICODE_HEX);
                            if (u2 <= 0xDC00 || u2 >= 0xDFFF)
                                STRING_ERROR(LEPT_PARSE_INVALID_UNICODE_HEX);
                            u = 0x10000 + (((u - 0xD800) << 10) | (u2 - 0xDC00));
                        }
                        lept_encode_utf8(c, u);
                        break;
                    default:
                        c->top = head;
                        return LEPT_PARSE_INVALID_STRING_ESCAPE;
                }
                break;
                case '\0':
                c->top = head;
                return LEPT_PARSE_MISS_QUOTATION_MARK;
            default:
                if ((unsigned char)ch < 0x20){
                    c->top = head;
                    return LEPT_PARSE_INVALID_STRING_CHAR;
                }
                PUTC(c, ch);
        }
    }
}


static int lept_parse_string(lept_context* c, lept_value* v) {
    int ret;
    char* s;
    size_t len;
    if ((ret = lept_parse_string_raw(c, &s, &len)) == LEPT_PARSE_OK)
        lept_set_string(v, s, len);
    return ret;
}


/* 前向声明 */
static int lept_parse_value(lept_context*, lept_value*);

static int lept_parse_array(lept_context* c, lept_value* v) {
    size_t size = 0;
    int ret;
    EXPECT(c, '[');
    lept_parse_whitespace(c);
    if (*c->json == ']') {
        c->json++;
        v->type = LEPT_ARRAY;
        v->u.a.size = 0;
        v->u.a.e = NULL;
        return LEPT_PARSE_OK;
    }

    for (;;) {
        lept_value e;
        lept_init(&e);
        if ((ret = lept_parse_value(c, &e)) != LEPT_PARSE_OK)
            break;
        memcpy(lept_context_push(c, sizeof(lept_value)), &e, sizeof(lept_value));
        size++;
        lept_parse_whitespace(c);
        if (*c->json == ',') {
            c->json++;
            lept_parse_whitespace(c);
        }
        else if (*c->json == ']') {
            c->json++;
            v->type = LEPT_ARRAY;
            v->u.a.size = size;
            int s = size * sizeof(lept_value);
            memcpy(v->u.a.e = (lept_value*)malloc(s), lept_context_pop(c, s), s);
            return LEPT_PARSE_OK;
        }
        else {
            ret = LEPT_PARSE_MISS_COMMA_OR_SQUARE_BACKET;
            break;
        }
    }

    size_t i;
    for (i = 0; i != size; ++i) {
        lept_value* v = (lept_value*)lept_context_pop(c, sizeof(lept_value));
        lept_free(v);
    }
    v->type = LEPT_NULL;
    return ret;
}

static int lept_parse_object(lept_context* c, lept_value* v) {
    size_t size;
    lept_member m;
    int ret;
    EXPECT(c, '{');
    lept_parse_whitespace(c);
    if (*c->json == '}') {
        c->json++;
        v->type = LEPT_OBJECT;
        v->u.o.m = 0;
        v->u.o.size = 0;
        return LEPT_PARSE_OK;
    }
    m.k = NULL;
    size = 0;
    for (; ; ) {
        lept_init(&m.v);
        char* str;
        if ((*c->json != '\"') || (*c->json == '\"' && lept_parse_string_raw(c, &str, &m.klen) != LEPT_PARSE_OK)) {
                ret = LEPT_PARSE_MISS_KEY;
                break;
        }
        memcpy(m.k = (char*)malloc(m.klen + 1), str, m.klen);
        m.k[m.klen] = '\0';
        lept_parse_whitespace(c);
        if (*c->json != ':') {
            ret = LEPT_PARSE_MISS_COLON;
            break;
        }
        c->json++;
        lept_parse_whitespace(c);
        if ((ret = lept_parse_value(c, &m.v)) != LEPT_PARSE_OK)
            break;
        memcpy(lept_context_push(c, sizeof(lept_member)), &m, sizeof(lept_member));
        size++;
        m.k = NULL;
        lept_parse_whitespace(c);
        if (*c->json == ',') {
            c->json++;
            lept_parse_whitespace(c);
        }
        else if (*c->json == '}') {
            c->json++;
            v->type = LEPT_OBJECT;
            v->u.o.size = size;
            size *= sizeof(lept_member);
            memcpy(v->u.o.m = (lept_member*)malloc(size), lept_context_pop(c,size), size);
            return LEPT_PARSE_OK;
        }
        else{
            ret = LEPT_PARSE_MISS_COMMA_OR_CURLY_BRACKET;
            break;
        }
    }
    size_t i;
    free(m.k);
    for (i = 0; i != size; ++i) {
        lept_member* m =  (lept_member*)lept_context_pop(c, sizeof(lept_member));
        free(m->k);
        lept_free(&m->v);
    }
    v->type = LEPT_NULL;
    return ret;
}

static int lept_parse_value(lept_context* c, lept_value* v) {
    switch (*c->json) {
        case 'n' : return lept_parse_literal(c, v, "null", LEPT_NULL);
        case 't' : return lept_parse_literal(c, v, "true", LEPT_TRUE);
        case 'f' : return lept_parse_literal(c, v, "false", LEPT_FALSE);
        case '\"' : return lept_parse_string(c, v);
        case '[' : return lept_parse_array(c, v);
        case '{' : return lept_parse_object(c, v);
        default: return lept_parse_number(c, v);
        case '\0' : return LEPT_PARSE_EXPECT_VALUE;
    }
}

int lept_parse(lept_value* v, const char* json) {
    lept_context c;
    int ret;
    assert(v != NULL);
    c.json = json;
    c.stack = NULL;
    c.size = c.top = 0;
    v->type = LEPT_NULL;
    lept_parse_whitespace(&c);
    if ((ret = lept_parse_value(&c, v)) == LEPT_PARSE_OK) {

        lept_parse_whitespace(&c);
        if (*c.json !='\0')
            ret = LEPT_PARSE_ROOT_NOT_SINGULAR;
    }
    assert(c.top == 0); 
    free(c.stack);
    return ret;
}

lept_type lept_get_type(const lept_value* v) {
    assert(v != NULL); 
    return v->type;
}

double lept_get_number(const lept_value* v) {
    assert( v!= NULL && v->type == LEPT_NUMBER);
    return v->u.n;
}

const char* lept_get_string(const lept_value* v) {
    assert( v!= NULL);
    return v->u.s.s;
}

void lept_set_string(lept_value* v, const char* s, size_t len) {
    assert(v != NULL && (s != NULL || len == 0));
    lept_free(v);
    v->u.s.s = (char*)malloc(len + 1);
    memcpy(v->u.s.s, s, len);
    v->u.s.s[len] = '\0';
    v->u.s.len = len;
    v->type = LEPT_STRING;
}

size_t lept_get_string_length(const lept_value* v) {
    assert(v != NULL);
    return v->u.s.len;
}

int lept_get_boolean(const lept_value* v) {
    assert(v != NULL && (v->type == LEPT_TRUE || v->type == LEPT_FALSE));
    return v->type== LEPT_TRUE;
}

void lept_set_boolean(lept_value*v, int b) {
    lept_free(v);
    v->type = b ? LEPT_TRUE : LEPT_FALSE;
}

size_t lept_get_array_size(const lept_value* v) {
    assert(v != NULL && v->type == LEPT_ARRAY);
    return v->u.a.size;
}

lept_value* lept_get_array_element(const lept_value*v, size_t index) {
    assert(v != NULL && v->type == LEPT_ARRAY);
    assert(index < v->u.a.size);
    return &v->u.a.e[index];
}

size_t lept_get_object_size(const lept_value* v) {
    assert(v != NULL && v->type == LEPT_OBJECT);
    return v->u.o.m->klen;
}

const char* lept_get_object_key(const lept_value* v, size_t index) {
    assert(v != NULL && v->type == LEPT_OBJECT);
    return v->u.o.m[index].k;
}

size_t lept_get_object_key_length(const lept_value* v, size_t index) {
    assert(v != NULL && v->type == LEPT_OBJECT);
    assert(index < v->u.o.size);
    return v->u.o.m[index].klen;
}

lept_value* lept_get_object_value(const lept_value* v, size_t index) {
    assert(v != NULL && v->type == LEPT_OBJECT);
    assert(index < v->u.o.size);
    return &v->u.o.m[index];
}

static void lept_stringify_string(lept_context* c, const char* s, size_t len) {
/*  PUTC(c, '\"');
    size_t i = 0;
    while (i++ != len) {
        char ch = *s++;
        switch (ch) {
            case '\"' : PUTS(c, "\\\"", 2); break;
            case '\\' : PUTS(c, "\\\\", 2); break;
            case '/'  : PUTS(c, "\\/" , 2); break;
            case '\b' : PUTS(c, "\\b", 2); break;
            case '\f' : PUTS(c, "\\f", 2); break;
            case '\n' : PUTS(c, "\\n" , 2); break;
            case '\r' : PUTS(c, "\\r" , 2); break;
            case '\t' : PUTS(c, "\\t" , 2); break;
            default :
                if (ch < 0x20) {
                    PUTS(c, "\\u00", 4);
                    char buffer[2];
                    int n = sprintf(buffer, "%02x", ch);
                    PUTS(c, buffer, n);
                } else 
                    PUTC(c, ch);
        }
    }
    PUTC(c, '\"'); 
*/

    static const char hex_digits[] = { '0', '1', '2', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
    char *start = lept_context_push(c, LEPT_PARSE_STRINGIFY_INIT_SIZE);
    char *p = start;
    *p++ = '\"';
    size_t i = 0;
    while (i++ != len) {
        char ch = *s++;
        switch (ch) {
            case '\"' : 
                memcpy(p, "\\\"", 2);
                p += 2;
                break;
            case '\\' : 
                memcpy(p, "\\\\", 2);
                p += 2;
                break;
            case '/'  :
                memcpy(p, "\\/", 2);
                p += 2;
                break;
            case '\b' :
                memcpy(p, "\\b", 2);
                p += 2;
                break;
            case '\f' :
                memcpy(p, "\\f", 2);
                p += 2;
                break;
            case '\n' : 
                memcpy(p, "\\n", 2);
                p += 2;
                break;
            case '\r' : 
                memcpy(p, "\\r", 2);
                p += 2;
                break;
            case '\t' : 
                memcpy(p, "\\t", 2);
                p += 2;
                break;
            default :
                if (ch < 0x20) {
                    *p++ = '\\';
                    *p++ = 'u';
                    *p++ = '0';
                    *p++ = '0';
                    *p++ = hex_digits[ch >> 4];
                    *p++ = hex_digits[ch & 15];
                } else
                   *p++ = ch;   
        }
    }
    *p++ = '\"';
    c->top -= (LEPT_PARSE_STRINGIFY_INIT_SIZE - (p - start));
}

static int lept_stringify_value(lept_context* c, const lept_value* v) {
    size_t i;
    switch (v->type) {
        case LEPT_NULL: PUTS(c, "null", 4); break;
        case LEPT_FALSE: PUTS(c, "false", 5); break;
        case LEPT_TRUE: PUTS(c, "true", 4); break;
        case LEPT_NUMBER: 
                        {
                            char* buffer = lept_context_push(c, 32);
                            int length = sprintf(buffer, "%.17g", v->u.n);
                            c->top -= (32 - length);
                        }
                        break;
        case LEPT_ARRAY: 
                        {
                             PUTC(c, '[');
                             for (i = 0; i != v->u.a.size; ++i) {
                            /*  char* buffer;
                                size_t length;
                                lept_stringify(&v->u.a.e[i], &buffer, &length);
                                PUTS(c, buffer, length);
                                free(buffer);
                            */  
                                 lept_stringify_value(c, &v->u.a.e[i]);
                                 if (i != v->u.a.size - 1) PUTC(c, ',');
                             }
                             PUTC(c, ']');
                         }
                        break;
        case LEPT_OBJECT:
                        {   
                            PUTC(c, '{');
                            for (i = 0; i != v->u.o.size; ++i) {
                                lept_stringify_string(c, v->u.o.m[i].k, v->u.o.m[i].klen);
                                PUTC(c, ':');
                                lept_stringify_value(c, &v->u.o.m[i].v);
                                if (i != v->u.o.size - 1) PUTC(c, ',');
                            }
                            PUTC(c, '}');   
                        }
                        break;
        case LEPT_STRING:
                        lept_stringify_string(c, v->u.s.s, v->u.s.len);
                        break;
        default:
                        assert(0 && "invalid type");

    }
    return LEPT_STRINGIFY_OK;
}

int lept_stringify(const lept_value* v, char** json, size_t* length){
    lept_context c;
    int ret;
    assert(v != NULL);
    assert(json != NULL);
    c.stack = (char*)malloc(c.size = LEPT_PARSE_STRINGIFY_INIT_SIZE);
    c.top = 0;
    if ((ret = lept_stringify_value(&c, v)) != LEPT_STRINGIFY_OK) {
            free(c.stack);
            *json = NULL;
            return ret;
    }
    if (length) 
        *length = c.top;
    PUTC(&c, '\0');
    *json = c.stack;
    return LEPT_STRINGIFY_OK;
}
#include <stdio.h>
#include <stdlib.h>
#include "leptjson.h"
#include <string.h>     /* memcmp() */ 

static int main_ret = 0;
static int test_count = 0;
static int test_pass = 0;

#define EXPECT_EQ_BASE(equality, expect, actual, format) \
    do {\
        test_count++;\
        if (equality)\
            test_pass++;\
        else {\
            fprintf(stderr, "%s:%d: expect: " format " actual: " format "\n", __FILE__, __LINE__, expect, actual);\
            main_ret = 1;\
        }\
    } while(0);

#define EXPECT_EQ_INT(expect, actual) EXPECT_EQ_BASE((expect) == (actual), expect, actual, "%d")

#define EXPECT_EQ_DOUBLE(expect, actual) EXPECT_EQ_BASE((expect) == (actual), expect, actual, "%f")

#define EXPECT_EQ_STRING(expect, actual, alength) \
    EXPECT_EQ_BASE(sizeof(expect) - 1 == alength && memcmp(expect, actual, alength) == 0, expect, actual, "%s")
#define EXPECT_FALSE(expect) EXPECT_EQ_BASE((expect) == 0, expect, 0, "%d")

#define EXPECT_TRUE(expect) EXPECT_EQ_BASE((expect) == 1, expect, 1, "%d")

#if defined(_MSC_VER)
#define EXPECT_EQ_SIZE_T(expect, actual) EXPECT_EQ_BASE((expect) == (actual), (size_t)expect, (size_t)actual, "%Iu")
#else
#define EXPECT_EQ_SIZE_T(expect, actual) EXPECT_EQ_BASE((expect) == (actual), (size_t)expect, (size_t)actual, "%zu")
#endif


#define TEST_NUMBER(expect, json)\
    do {\
        lept_value v;\
        EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v, json));\
        EXPECT_EQ_INT(LEPT_NUMBER, lept_get_type(&v));\
        EXPECT_EQ_DOUBLE(expect, lept_get_number(&v));\
    } while (0)

static void test_parse_number() {
    TEST_NUMBER(0.0, "0");
    TEST_NUMBER(0.0, "-0");
    TEST_NUMBER(1.0, "1");
    TEST_NUMBER(3.1416, "3.1416");
    TEST_NUMBER(1E10, "1E10");
    TEST_NUMBER(1e10, "1e10");
    TEST_NUMBER(1E+10, "1E+10");
    TEST_NUMBER(-1E-10, "-1E-10");
    TEST_NUMBER(0.0, "1e-10000"); /* must underflow */

}

static void test_parse_number_too_big() {

    /* the smallest number > 1 */
    TEST_NUMBER(1.0000000000000002, "1.000000000000002");

    /* the minimum denormal */
    TEST_NUMBER(4.9406564584124654E-324, "4.9406564584124654E-324");

    /* Max subnormal double */
    TEST_NUMBER(2.2250738585072009E-308, "2.2250738585072009E-308");

    /* Min normal positive double */
    TEST_NUMBER(2.2250738585072014E-308, "2.2250738585072014E-308");

    /* Max double */
    TEST_NUMBER(1.7976931348623157E+308, "1.7976931348623157E+308");
    /* TEST_NUMBER(1E309, "1E309"); */
}

#define TEST_ERROR(error, json)\
    do {\
        lept_value v;\
        v.type = LEPT_NULL;\
        EXPECT_EQ_INT(error, lept_parse(&v, json));\
        EXPECT_EQ_INT(LEPT_NULL, lept_get_type(&v));\
    } while (0)

/* test stri    ng */
static void test_parse_missing_quotation_mark() {
    TEST_ERROR(LEPT_PARSE_MISS_QUOTATION_MARK, "\"");
    TEST_ERROR(LEPT_PARSE_MISS_QUOTATION_MARK, "\"abc");
    TEST_ERROR(LEPT_PARSE_MISS_QUOTATION_MARK, "\"abc");
}

/* invalid number */
static void test_parse_invalid_value() {
    TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "+0");
    TEST_ERROR(LEPT_PARSE_INVALID_VALUE, ".123");   /* at least one digit befor '.' */
    TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "1.");     /* at least one digit after '.' */      
    TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "INF");
    TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "inf");
    TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "kang");
    TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "NAN");
}

static void test_parse_null() {
    TEST_ERROR(LEPT_PARSE_OK, "null ");
}

static void test_parse_true() {
    TEST_ERROR(LEPT_PARSE_OK, "true ");
}

static void test_parse_false() {
    TEST_ERROR(LEPT_PARSE_OK, "false ");
}

static void test_parse_invalid_string_escape() {
#if 1 
    TEST_ERROR(LEPT_PARSE_INVALID_STRING_ESCAPE, "\"\\v\"");
    TEST_ERROR(LEPT_PARSE_INVALID_STRING_ESCAPE, "\"\\'\"");
    TEST_ERROR(LEPT_PARSE_INVALID_STRING_ESCAPE, "\"\\0\"");
    TEST_ERROR(LEPT_PARSE_INVALID_STRING_ESCAPE, "\"\\x12\"");
#endif
}

static void test_parse_invalid_string_char() {
#if 1 
    TEST_ERROR(LEPT_PARSE_INVALID_STRING_CHAR, "\"\x01\"");
    TEST_ERROR(LEPT_PARSE_INVALID_STRING_CHAR, "\"\x1F\"");
#endif
}

static void test_parse_miss_key() {
    TEST_ERROR(LEPT_PARSE_MISS_KEY, "{:1,");
    TEST_ERROR(LEPT_PARSE_MISS_KEY, "{1:1,");
    TEST_ERROR(LEPT_PARSE_MISS_KEY, "{true:1,");
    TEST_ERROR(LEPT_PARSE_MISS_KEY, "{false:1,");
    TEST_ERROR(LEPT_PARSE_MISS_KEY, "{null:1,");
    TEST_ERROR(LEPT_PARSE_MISS_KEY, "{[]:1,");
    TEST_ERROR(LEPT_PARSE_MISS_KEY, "{{}:1,");
    TEST_ERROR(LEPT_PARSE_MISS_KEY, "{\"a\":1,");
}

static void test_parse_miss_colon() {
    TEST_ERROR(LEPT_PARSE_MISS_COLON, "{\"a\"}");
    TEST_ERROR(LEPT_PARSE_MISS_COLON, "{\"a\",\"b\"}");
}

static void test_parse_miss_comma_or_curly_bracket() {
    TEST_ERROR(LEPT_PARSE_MISS_COMMA_OR_CURLY_BRACKET, "{\"a\":1");
    TEST_ERROR(LEPT_PARSE_MISS_COMMA_OR_CURLY_BRACKET, "{\"a\":1]");
    TEST_ERROR(LEPT_PARSE_MISS_COMMA_OR_CURLY_BRACKET, "{\"a\":1 \"b\"");
    TEST_ERROR(LEPT_PARSE_MISS_COMMA_OR_CURLY_BRACKET, "{\"a\":{}");
}

#define TEST_STRING(expect, json)\
    do {\
        lept_value v;\
        lept_init(&v);\
        EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v, json));\
        EXPECT_EQ_INT(LEPT_STRING, lept_get_type(&v));\
        EXPECT_EQ_STRING(expect, lept_get_string(&v), lept_get_string_length(&v));\
        lept_free(&v);\
    } while (0)

static void test_parse_string() {
    TEST_STRING("", "\"\"");
#if 1
    TEST_STRING("Hello\nWord", "\"Hello\\nWord\"");
    TEST_STRING("\" \\ / \b \f \n \r \t", "\"\\\" \\\\ \\/ \\b \\f \\n \\r \\t\""); 
    TEST_STRING("Hello\0World", "\"Hello\\u0000World\"");
    TEST_STRING("\x24", "\"\\u0024\""); /* Dollar sign U+0024 */
    TEST_STRING("\xC2\xA2", "\"\\u00A2\""); /* Cents sign U+00A2 */
    TEST_STRING("\xE2\x82\xAC", "\"\\u20AC\""); /* Euro sign U+20AC */
    TEST_STRING("\xF0\x9D\x84\x9E", "\"\\ud834\\uDD1E\""); /* G clef sign U+1D11E */
    TEST_STRING("\xF0\x9D\x84\x9E", "\"\\ud834\\udd1e\""); /* G clef sign U+1D11E */
#endif 
}




/* test access */
static void test_access_boolean() {
    lept_value v;
    lept_init(&v);
    lept_set_boolean(&v, 0);
    EXPECT_FALSE(lept_get_boolean(&v));
    lept_set_boolean(&v, 1);
    EXPECT_TRUE(lept_get_boolean(&v));
}

static void test_access_string() {
    lept_value v;
    lept_init(&v);
    lept_set_string(&v, "",0);
    EXPECT_EQ_STRING("", lept_get_string(&v), lept_get_string_length(&v));
    lept_set_string(&v, "Hello", 5);
    EXPECT_EQ_STRING("Hello", lept_get_string(&v), lept_get_string_length(&v));
    lept_free(&v);
}

static void test_parse_array() {
    lept_value v;
    lept_init(&v);
    EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v, "[ ]"));
    EXPECT_EQ_INT(LEPT_ARRAY, lept_get_type(&v));
    EXPECT_EQ_SIZE_T(0, lept_get_array_size(&v));
    EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v, "[ null, false, true, 123, \"abc\" ]"));
    EXPECT_EQ_INT(LEPT_ARRAY, lept_get_type(&v));
    EXPECT_EQ_SIZE_T(5, lept_get_array_size(&v));
    EXPECT_EQ_INT(LEPT_NULL, lept_get_type(lept_get_array_element(&v, 0)));

    lept_free(&v);
}

#define TEST_ROUNDTRIP(json)\
    do {\
        lept_value v; \
        char* json2; \
        size_t length;\
        lept_init(&v);\
        EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v, json));\
        EXPECT_EQ_INT(LEPT_STRINGIFY_OK, lept_stringify(&v, &json2, &length));\
        EXPECT_EQ_STRING(json, json2, length);\
        lept_free(&v);\
        free(json2);\
    } while(0)

static test_stringify_number() {
    TEST_ROUNDTRIP("0");
    TEST_ROUNDTRIP("-0");
    TEST_ROUNDTRIP("1");
    TEST_ROUNDTRIP("-1");
    TEST_ROUNDTRIP("1.5");
    TEST_ROUNDTRIP("-1.5");
    TEST_ROUNDTRIP("3.25");
    TEST_ROUNDTRIP("1e+20");
    TEST_ROUNDTRIP("1.234e+20");
    TEST_ROUNDTRIP("1.234e-20");

    /* the smallest number > 1 */
    TEST_ROUNDTRIP("1.000000000000002");

    /* the minimum denormal */
    TEST_ROUNDTRIP("4.9406564584124654e-324");

    /* Max subnormal double */
    TEST_ROUNDTRIP("2.2250738585072009e-308");

    /* Min normal positive double */
    TEST_ROUNDTRIP("2.2250738585072014e-308");

    /* Max double */
    TEST_ROUNDTRIP("1.7976931348623157e+308");
    /* TEST_NUMBER(1E309, "1E309"); */
}

static test_stringify_string() {
    TEST_ROUNDTRIP("\"\"");
    TEST_ROUNDTRIP("\"Hello\"");
    TEST_ROUNDTRIP("\"Hello\\nWord\"");
    TEST_ROUNDTRIP("\"\\\" \\\\ \\/ \\b \\f \\n \\r \\t\""); 
    TEST_ROUNDTRIP("\"Hello\\u0000World\"");
}

static void test_stringify_array() {
    TEST_ROUNDTRIP("[]");
    TEST_ROUNDTRIP("[null,false,true,123,\"abc\",[1,2,3]]");
}

static void test_stringify_object() {
    TEST_ROUNDTRIP("{}");
    TEST_ROUNDTRIP("{\"n\":null,\"f\":false,\"t\":true,\"i\":123,\"s\":\"abc\",\"a\":[1,2,3],\"o\":{\"1\":1,\"2\":2,\"3\":3}}");
}

static void test_stringify() {
    TEST_ROUNDTRIP("null");
    TEST_ROUNDTRIP("false");
    TEST_ROUNDTRIP("true");
    test_stringify_number();
    test_stringify_string();
    test_stringify_array();
    test_stringify_object();
}

static void test_parse() {
    test_parse_null();      
    test_parse_true();
    test_parse_false(); 
    test_parse_number();
    test_parse_number_too_big();
    test_parse_invalid_value();
    test_access_string();
    test_access_boolean();
    test_parse_invalid_string_char();
    test_parse_missing_quotation_mark();
    test_parse_invalid_string_escape(); 
    test_parse_string();
    test_parse_array(); 
    test_parse_miss_key();
    test_parse_miss_colon();
    test_parse_miss_comma_or_curly_bracket(); 
    test_stringify();
}

int main() {
    test_parse();
    printf("%d/%d (%3.2f%%) passed\n", test_pass, test_count, test_pass * 100.0 / test_count);
    return main_ret;
}   
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值