学习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;
}