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      /* NULL, strtod(), malloc(), realloc(), free()*/
#include "leptjson.h"
#include 
#include       /* errno, ERANGE */
#include        /* HUGE_VAL */
#include      /* 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 == '
'
|| *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, '
'
); 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 '
' : PUTS(c, "\
" , 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 '
'
: memcpy(p, "\
"
, 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 "
", __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\
Word\"
"); TEST_STRING("\" \\ / \b \f
\r \t"
, "\"\\\" \\\\ \\/ \\b \\f \
\\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\
Word\"
"); 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
"
, test_pass, test_count, test_pass * 100.0 / test_count); return main_ret; }

좋은 웹페이지 즐겨찾기