参考链接
https://github.com/miloyip/json-tutorial
本文主要是代码,要看讲解的话,见参考链接。
说明:本文主要是学习库文件的编写规则与规范,宏函数写法,与测试驱动开发的过程。
leptjson.h
#ifndef LEPTJSON_H__
#define LEPTJSON_H__
#include <stddef.h> /* size_t */
typedef enum { LEPT_NULL, LEPT_FALSE, LEPT_TRUE, LEPT_NUMBER, LEPT_STRING, LEPT_ARRAY, LEPT_OBJECT } lept_type;
#define LEPT_KEY_NOT_EXIST ((size_t)-1)
/*
lept_value 内使用了自身类型的指针,我们必须前向声明(forward declare)此类型。
*/
typedef struct lept_value lept_value;
typedef struct lept_member lept_member;
//节点的结构体
struct lept_value{
union {
struct { lept_member* m; size_t size, capacity; }o;/* object: members, member count */
struct { lept_value* e; size_t size, capacity; }a; /* array: elements, element count */
struct { char*s; size_t len; }s;/* string: null-terminated string, string length */
double n; /*number*/
}u;
lept_type type;
};
struct lept_member {
char* k; size_t klen; /* member key string, key string length */
lept_value v; /* member value */
};
/*
返回值是以下这些枚举值,无错误会返回 LEPT_PARSE_OK
*/
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_BRACKET,
LEPT_PARSE_MISS_KEY,
LEPT_PARSE_MISS_COLON,
LEPT_PARSE_MISS_COMMA_OR_CURLY_BRACKET
};
#define lept_init(v) do { (v)->type = LEPT_NULL; } while(0)
/*
lept_value v;
const char json[] = ...;
int ret = lept_parse(&v, json);
*/
//解析json函数
int lept_parse(lept_value* v, const char* json);
char* lept_stringify(const lept_value* v, size_t* length);
void lept_copy(lept_value* dst, const lept_value* src);
void lept_move(lept_value* dst, lept_value* src);
void lept_swap(lept_value* lhs, lept_value* rhs);
void lept_free(lept_value* v);
//获取类型
lept_type lept_get_type(const lept_value* v);
int lept_is_equal(const lept_value* lhs, const lept_value* rhs);
#define lept_set_null(v) lept_free(v)
int lept_get_boolean(const lept_value* v);
void lept_set_boolean(lept_value* v, int b);
double lept_get_number(const lept_value* v);
void lept_set_number(lept_value* v, double n);
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);
void lept_set_array(lept_value* v, size_t capacity);
size_t lept_get_array_size(const lept_value* v);
size_t lept_get_array_capacity(const lept_value* v);
void lept_reserve_array(lept_value* v, size_t capacity);
void lept_shrink_array(lept_value* v);
void lept_clear_array(lept_value* v);
lept_value* lept_get_array_element(lept_value* v, size_t index);
lept_value* lept_pushback_array_element(lept_value* v);
void lept_popback_array_element(lept_value* v);
lept_value* lept_insert_array_element(lept_value* v, size_t index);
void lept_erase_array_element(lept_value* v, size_t index, size_t count);
void lept_set_object(lept_value* v, size_t capacity);
size_t lept_get_object_size(const lept_value* v);
size_t lept_get_object_capacity(const lept_value* v);
void lept_reserve_object(lept_value* v, size_t capacity);
void lept_shrink_object(lept_value* v);
void lept_clear_object(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(lept_value* v, size_t index);
size_t lept_find_object_index(const lept_value* v, const char* key, size_t klen);
lept_value* lept_find_object_value(lept_value* v, const char* key, size_t klen);
lept_value* lept_set_object_value(lept_value* v, const char* key, size_t klen);
void lept_remove_object_value(lept_value* v, size_t index);
#endif // LEPTJSON_H__
leptjson.c
//启动vs自带的内存泄漏检查工具
#ifdef _WINDOWS
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#include "leptjson.h"
#include <assert.h> /* assert() */
#include <errno.h> /* errno, ERANGE */
#include <math.h> /* HUGE_VAL */
#include <stdio.h> /* sprintf() */
#include <stdlib.h> /* NULL, malloc(), realloc(), free(), strtod() */
#include <string.h> /* memcpy() */
#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; //stack 是栈的起始位置
size_t size, top; //会扩展 stack,所以不要把 top 用指针形式存储,size是数据的size,top是起始位置加size与各数据的结果
}lept_context;
//它会返回数据起始的指针
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->size * 1.5 */
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);
}
/* 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;
}
static int lept_parse_literal(lept_context* c, lept_value* v, const char* literal, lept_type type) {
size_t i;
EXPECT(c, literal[0]);
for (i = 0; literal[i + 1]; 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++);
}
/*
https://www.cnblogs.com/yocichen/p/6435461.html
转换为double类型,超出界限errno 置为ERANGE
*/
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;
}
static const 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;
}
static void lept_encode_utf8(lept_context* c, unsigned u) {
if (u <= 0x7F)
PUTC(c, u & 0xFF);
else if (u <= 0x7FF) {
PUTC(c, 0xC0 | ((u >> 6) & 0xFF));
PUTC(c, 0x80 | (u & 0x3F));
}
else if (u <= 0xFFFF) {
PUTC(c, 0xE0 | ((u >> 12) & 0xFF));
PUTC(c, 0x80 | ((u >> 6) & 0x3F));
PUTC(c, 0x80 | (u & 0x3F));
}
else {
assert(u <= 0x10FFFF);
PUTC(c, 0xF0 | ((u >> 18) & 0xFF));
PUTC(c, 0x80 | ((u >> 12) & 0x3F));
PUTC(c, 0x80 | ((u >> 6) & 0x3F));
PUTC(c, 0x80 | (u & 0x3F));
}
}
#define STRING_ERROR(ret) do { c->top = head; return ret; } while(0)
//解析字符串
static int lept_parse_string_raw(lept_context* c, char** str, size_t* len) {
size_t head = c->top;
unsigned u, u2;
const char* p;
EXPECT(c, '\"');
p = c->json;
for (;;) {
char ch = *p++;
switch (ch) {
case '\"':
*len = c->top - head;
*str = 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_SURROGATE);
if (*p++ != 'u')
STRING_ERROR(LEPT_PARSE_INVALID_UNICODE_SURROGATE);
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_SURROGATE);
u = (((u - 0xD800) << 10) | (u2 - 0xDC00)) + 0x10000;
}
lept_encode_utf8(c, u);
break;
default:
STRING_ERROR(LEPT_PARSE_INVALID_STRING_ESCAPE);
}
break;
case '\0':
STRING_ERROR(LEPT_PARSE_MISS_QUOTATION_MARK);
default:
if ((unsigned char)ch < 0x20)
STRING_ERROR(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* c, lept_value* v);
static int lept_parse_array(lept_context* c, lept_value* v) {
size_t i,size = 0;
int ret;
EXPECT(c, '[');
lept_parse_whitespace(c);
if (*c->json == ']') {
c->json++;
lept_set_array(v, 0);
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++;
lept_set_array(v, size);
memcpy(v->u.a.e, lept_context_pop(c, size * sizeof(lept_value)), size * sizeof(lept_value));
v->u.a.size = size;
return LEPT_PARSE_OK;
}
else{
ret = LEPT_PARSE_MISS_COMMA_OR_SQUARE_BRACKET;
break;
}
}
/* Pop and free values on the stack */
for (i = 0; i < size; i++)
lept_free((lept_value*)lept_context_pop(c, sizeof(lept_value)));
return ret;
}
static int lept_parse_object(lept_context* c, lept_value* v) {
size_t i,size;
lept_member m;
int ret;
EXPECT(c, '{');
lept_parse_whitespace(c);
if (*c->json == '}') {
c->json++;
lept_set_object(v, 0);
return LEPT_PARSE_OK;
}
m.k = NULL;
size = 0;
for (;;) {
char* str;
lept_init(&m.v);
/* parse key */
if (*c->json != '"') {
ret = LEPT_PARSE_MISS_KEY;
break;
}
if ((ret = lept_parse_string_raw(c, &str, &m.klen)) != LEPT_PARSE_OK)
break;
memcpy(m.k = (char*)malloc(m.klen + 1), str, m.klen);
m.k[m.klen] = '\0';
/* parse ws colon ws */
lept_parse_whitespace(c);
if (*c->json != ':') {
ret = LEPT_PARSE_MISS_COLON;
break;
}
c->json++;
lept_parse_whitespace(c);
/* parse value */
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; /* ownership is transferred to member on stack */
/* parse ws [comma | right-curly-brace] ws */
lept_parse_whitespace(c);
if (*c->json == ',') {
c->json++;
lept_parse_whitespace(c);
}
else if (*c->json == '}') {
c->json++;
lept_set_object(v, size);
memcpy(v->u.o.m, lept_context_pop(c, sizeof(lept_member) * size), sizeof(lept_member) * size);
v->u.o.size = size;
return LEPT_PARSE_OK;
}
else {
ret = LEPT_PARSE_MISS_COMMA_OR_CURLY_BRACKET;
break;
}
}
/* Pop and free members on the stack */
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;
}
/* value = null / false / true */
/* 提示:下面代码没处理 false / true,将会是练习之一 */
static int lept_parse_value(lept_context* c, lept_value* v) {
switch (*c->json) {
case 't': return lept_parse_literal(c, v, "true", LEPT_TRUE);
case 'f': return lept_parse_literal(c, v, "false", LEPT_FALSE);
case 'n': return lept_parse_literal(c, v, "null", LEPT_NULL);
default: return lept_parse_number(c, v);
case '"': return lept_parse_string(c, v);
case '[': return lept_parse_array(c, v);
case '{': return lept_parse_object(c, v);
case '\0': return LEPT_PARSE_EXPECT_VALUE;
}
}
/* ... */
/* 提示:这里应该是 JSON-text = ws value ws */
/* 以下实现没处理最后的 ws 和 LEPT_PARSE_ROOT_NOT_SINGULAR */
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;
lept_init(v);
lept_parse_whitespace(&c);
if ((ret = lept_parse_value(&c, v)) == LEPT_PARSE_OK) {
lept_parse_whitespace(&c);
if (*c.json != '\0') {
v->type= LEPT_NULL;
ret = LEPT_PARSE_ROOT_NOT_SINGULAR;
}
}
assert(c.top ==0);
free(c.stack);
return ret;
}
static void lept_stringify_string(lept_context* c, const char* s, size_t len) {
static const char hex_digits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
size_t i, size;
char* head, *p;
assert(s != NULL);
p = head = lept_context_push(c, size = len * 6 + 2); /* "\u00xx..." */
*p++ = '"';
for (i = 0; i < len; i++) {
unsigned char ch = (unsigned char)s[i];
switch (ch) {
case '\"': *p++ = '\\'; *p++ = '\"'; break;
case '\\': *p++ = '\\'; *p++ = '\\'; break;
case '\b': *p++ = '\\'; *p++ = 'b'; break;
case '\f': *p++ = '\\'; *p++ = 'f'; break;
case '\n': *p++ = '\\'; *p++ = 'n'; break;
case '\r': *p++ = '\\'; *p++ = 'r'; break;
case '\t': *p++ = '\\'; *p++ = 't'; break;
default:
if (ch < 0x20) {
*p++ = '\\'; *p++ = 'u'; *p++ = '0'; *p++ = '0';
*p++ = hex_digits[ch >> 4];
*p++ = hex_digits[ch & 15];
}
else
*p++ = s[i];
}
}
*p++ = '"';
c->top -= size - (p - head);
}
static void 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: c->top -= 32 - sprintf(lept_context_push(c, 32), "%.17g", v->u.n); break;
case LEPT_STRING: lept_stringify_string(c, v->u.s.s, v->u.s.len); break;
case LEPT_ARRAY:
PUTC(c, '[');
for (i = 0; i < v->u.a.size; i++) {
if (i > 0)
PUTC(c, ',');
lept_stringify_value(c, &v->u.a.e[i]);
}
PUTC(c, ']');
break;
case LEPT_OBJECT:
PUTC(c, '{');
for (i = 0; i < v->u.o.size; i++) {
if (i > 0)
PUTC(c, ',');
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);
}
PUTC(c, '}');
break;
default: assert(0 && "invalid type");
}
}
char* lept_stringify(const lept_value* v, size_t* length) {
lept_context c;
assert(v != NULL);
c.stack = (char*)malloc(c.size = LEPT_PARSE_STRINGIFY_INIT_SIZE);
c.top = 0;
lept_stringify_value(&c, v);
if (length)
*length = c.top;
PUTC(&c, '\0');
return c.stack;
}
void lept_copy(lept_value* dst, const lept_value* src) {
assert(src != NULL && dst != NULL && src != dst);
switch (src->type) {
case LEPT_STRING:
lept_set_string(dst, src->u.s.s, src->u.s.len);
break;
case LEPT_ARRAY:
/* \todo */
break;
case LEPT_OBJECT:
/* \todo */
break;
default:
lept_free(dst);
memcpy(dst, src, sizeof(lept_value));
break;
}
}
void lept_move(lept_value* dst, lept_value* src) {
assert(dst != NULL && src != NULL && src != dst);
lept_free(dst);
memcpy(dst, src, sizeof(lept_value));
lept_init(src);
}
void lept_swap(lept_value* lhs, lept_value* rhs) {
assert(lhs != NULL && rhs != NULL);
if (lhs != rhs) {
lept_value temp;
memcpy(&temp, lhs, sizeof(lept_value));
memcpy(lhs, rhs, sizeof(lept_value));
memcpy(rhs, &temp, sizeof(lept_value));
}
}
void lept_free(lept_value* v) {
size_t i;
assert(v != NULL);
switch (v->type) {
case LEPT_STRING:
free(v->u.s.s);
break;
case LEPT_ARRAY:
for (i = 0; i < v->u.a.size; i++)
lept_free(&v->u.a.e[i]);
free(v->u.a.e);
break;
case 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);
break;
default: break;
}
v->type = LEPT_NULL;
}
lept_type lept_get_type(const lept_value* v) {
assert(v != NULL);
return v->type;
}
int lept_is_equal(const lept_value* lhs, const lept_value* rhs) {
size_t i;
assert(lhs != NULL && rhs != NULL);
if (lhs->type != rhs->type)
return 0;
switch (lhs->type) {
case LEPT_STRING:
return lhs->u.s.len == rhs->u.s.len &&
memcmp(lhs->u.s.s, rhs->u.s.s, lhs->u.s.len) == 0;
case LEPT_NUMBER:
return lhs->u.n == rhs->u.n;
case LEPT_ARRAY:
if (lhs->u.a.size != rhs->u.a.size)
return 0;
for (i = 0; i < lhs->u.a.size; i++)
if (!lept_is_equal(&lhs->u.a.e[i], &rhs->u.a.e[i]))
return 0;
return 1;
case LEPT_OBJECT:
/* \todo */
return 1;
default:
return 1;
}
}
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;
}
double lept_get_number(const lept_value* v) {
assert(v!=NULL && v->type==LEPT_NUMBER);
return v->u.n;
}
void lept_set_number(lept_value* v, double n) {
lept_free(v);
v->u.n = n;
v->type = LEPT_NUMBER;
}
const char* lept_get_string(const lept_value* v) {
assert(v != NULL && v->type == LEPT_STRING);
return v->u.s.s;
}
size_t lept_get_string_length(const lept_value* v) {
assert(v != NULL && v->type == LEPT_STRING);
return v->u.s.len;
}
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;
}
void lept_set_array(lept_value* v, size_t capacity) {
assert(v != NULL);
lept_free(v);
v->type = LEPT_ARRAY;
v->u.a.size = 0;
v->u.a.capacity = capacity;
v->u.a.e = capacity > 0 ? (lept_value*)malloc(capacity * sizeof(lept_value)) : NULL;
}
size_t lept_get_array_size(const lept_value* v) {
assert(v != NULL && v->type == LEPT_ARRAY);
return v->u.a.size;
}
size_t lept_get_array_capacity(const lept_value* v) {
assert(v != NULL && v->type == LEPT_ARRAY);
return v->u.a.capacity;
}
void lept_reserve_array(lept_value* v, size_t capacity) {
assert(v != NULL && v->type == LEPT_ARRAY);
if (v->u.a.capacity < capacity) {
v->u.a.capacity = capacity;
v->u.a.e = (lept_value*)realloc(v->u.a.e, capacity * sizeof(lept_value));
}
}
void lept_shrink_array(lept_value* v) {
assert(v != NULL && v->type == LEPT_ARRAY);
if (v->u.a.capacity > v->u.a.size) {
v->u.a.capacity = v->u.a.size;
v->u.a.e = (lept_value*)realloc(v->u.a.e, v->u.a.capacity * sizeof(lept_value));
}
}
void lept_clear_array(lept_value* v) {
assert(v != NULL && v->type == LEPT_ARRAY);
lept_erase_array_element(v, 0, v->u.a.size);
}
lept_value* lept_get_array_element(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];
}
lept_value* lept_pushback_array_element(lept_value* v) {
assert(v != NULL && v->type == LEPT_ARRAY);
if (v->u.a.size == v->u.a.capacity)
lept_reserve_array(v, v->u.a.capacity == 0 ? 1 : v->u.a.capacity * 2);
lept_init(&v->u.a.e[v->u.a.size]);
return &v->u.a.e[v->u.a.size++];
}
void lept_popback_array_element(lept_value* v) {
assert(v != NULL && v->type == LEPT_ARRAY && v->u.a.size > 0);
lept_free(&v->u.a.e[--v->u.a.size]);
}
lept_value* lept_insert_array_element(lept_value* v, size_t index) {
assert(v != NULL && v->type == LEPT_ARRAY && index <= v->u.a.size);
/* \todo */
return NULL;
}
void lept_erase_array_element(lept_value* v, size_t index, size_t count) {
assert(v != NULL && v->type == LEPT_ARRAY && index + count <= v->u.a.size);
/* \todo */
}
void lept_set_object(lept_value* v, size_t capacity) {
assert(v != NULL);
lept_free(v);
v->type = LEPT_OBJECT;
v->u.o.size = 0;
v->u.o.capacity = capacity;
v->u.o.m = capacity > 0 ? (lept_member*)malloc(capacity * sizeof(lept_member)) : NULL;
}
size_t lept_get_object_size(const lept_value* v) {
assert(v != NULL && v->type == LEPT_OBJECT);
return v->u.o.size;
}
size_t lept_get_object_capacity(const lept_value* v) {
assert(v != NULL && v->type == LEPT_OBJECT);
/* \todo */
return 0;
}
void lept_reserve_object(lept_value* v, size_t capacity) {
assert(v != NULL && v->type == LEPT_OBJECT);
/* \todo */
}
void lept_shrink_object(lept_value* v) {
assert(v != NULL && v->type == LEPT_OBJECT);
/* \todo */
}
void lept_clear_object(lept_value* v) {
assert(v != NULL && v->type == LEPT_OBJECT);
/* \todo */
}
const char* lept_get_object_key(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].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(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].v;
}
size_t lept_find_object_index(const lept_value* v, const char* key, size_t klen) {
size_t i;
assert(v != NULL && v->type == LEPT_OBJECT && key != NULL);
for (i = 0; i < v->u.o.size; i++)
if (v->u.o.m[i].klen == klen && memcmp(v->u.o.m[i].k, key, klen) == 0)
return i;
return LEPT_KEY_NOT_EXIST;
}
lept_value* lept_find_object_value(lept_value* v, const char* key, size_t klen) {
size_t index = lept_find_object_index(v, key, klen);
return index != LEPT_KEY_NOT_EXIST ? &v->u.o.m[index].v : NULL;
}
lept_value* lept_set_object_value(lept_value* v, const char* key, size_t klen) {
assert(v != NULL && v->type == LEPT_OBJECT && key != NULL);
/* \todo */
return NULL;
}
void lept_remove_object_value(lept_value* v, size_t index) {
assert(v != NULL && v->type == LEPT_OBJECT && index < v->u.o.size);
/* \todo */
}
test.c
/// 检查内存泄漏
#ifdef _WINDOWS
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
// 按理说通过定义上面的宏再引入头文件,new就会被重新定义成记录文件和行号的
// 但是实际测试下来没有,不知道为什么,而手动定义是起作用的,
#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "leptjson.h"
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, "%.17g")
#define EXPECT_EQ_STRING(expect, actual, alength) \
EXPECT_EQ_BASE(sizeof(expect) - 1 == alength && memcmp(expect, actual, alength+1) == 0, expect, actual, "%s")
#define EXPECT_TRUE(actual) EXPECT_EQ_BASE((actual) != 0, "true", "false", "%s")
#define EXPECT_FALSE(actual) EXPECT_EQ_BASE((actual) == 0, "false", "true", "%s")
#if defined(_MSC_VER)
#define EXPECT_EQ_SIZE_T(expect, actual) EXPECT_EQ_BASE((expect) == (actual), (size_t)expect, (size_t)actual, "%Iu")
#else
//size_t output type is "%zu"
#define EXPECT_EQ_SIZE_T(expect, actual) EXPECT_EQ_BASE((expect) == (actual), (size_t)expect, (size_t)actual, "%zu")
#endif
static void test_parse_null() {
lept_value v;
lept_init(&v);
lept_set_boolean(&v, 0);
//设置类型为bull
EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v, "null"));
//获取类型并检查
EXPECT_EQ_INT(LEPT_NULL, lept_get_type(&v));
lept_free(&v);
}
static void test_parse_true() {
lept_value v;
lept_init(&v);
lept_set_boolean(&v, 0);
EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v, "true"));
EXPECT_EQ_INT(LEPT_TRUE, lept_get_type(&v));
lept_free(&v);
}
static void test_parse_false() {
lept_value v;
lept_init(&v);
lept_set_boolean(&v, 1);
EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v, "false"));
EXPECT_EQ_INT(LEPT_FALSE, lept_get_type(&v));
lept_free(&v);
}
/
#define TEST_NUMBER(expect,json)\
do{\
lept_value v;\
lept_init(&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));\
lept_free(&v);\
}while(0)
static void test_parse_number() {
TEST_NUMBER(0.0, "0");
TEST_NUMBER(0.0, "-0");
TEST_NUMBER(0.0, "-0.0");
TEST_NUMBER(1.0, "1");
TEST_NUMBER(-1.0, "-1");
TEST_NUMBER(1.5, "1.5");
TEST_NUMBER(-1.5, "-1.5");
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(-1E10, "-1E10");
TEST_NUMBER(-1e10, "-1e10");
TEST_NUMBER(-1E+10, "-1E+10");
TEST_NUMBER(-1E-10, "-1E-10");
TEST_NUMBER(1.234E+10, "1.234E+10");
TEST_NUMBER(1.234E-10, "1.234E-10");
TEST_NUMBER(0.0, "1e-10000"); /* must underflow */
TEST_NUMBER(1.0000000000000002, "1.0000000000000002"); /* the smallest number > 1 */
TEST_NUMBER(4.9406564584124654e-324, "4.9406564584124654e-324"); /* minimum denormal */
TEST_NUMBER(-4.9406564584124654e-324, "-4.9406564584124654e-324");
TEST_NUMBER(2.2250738585072009e-308, "2.2250738585072009e-308"); /* Max subnormal double */
TEST_NUMBER(-2.2250738585072009e-308, "-2.2250738585072009e-308");
TEST_NUMBER(2.2250738585072014e-308, "2.2250738585072014e-308"); /* Min normal positive double */
TEST_NUMBER(-2.2250738585072014e-308, "-2.2250738585072014e-308");
TEST_NUMBER(1.7976931348623157e+308, "1.7976931348623157e+308"); /* Max double */
TEST_NUMBER(-1.7976931348623157e+308, "-1.7976931348623157e+308");
//TEST_NUMBER(1.7976931348623157e+308, "-1.7976931348623157e+308");
}
#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("", "\"\"");
TEST_STRING("Hello", "\"Hello\"");
TEST_STRING("Hello\nWorld", "\"Hello\\nWorld\"");
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 */
}
static void test_parse_array() {
size_t i, j;
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));
lept_free(&v);
lept_init(&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)));
EXPECT_EQ_INT(LEPT_FALSE, lept_get_type(lept_get_array_element(&v, 1)));
EXPECT_EQ_INT(LEPT_TRUE, lept_get_type(lept_get_array_element(&v, 2)));
EXPECT_EQ_INT(LEPT_NUMBER, lept_get_type(lept_get_array_element(&v, 3)));
EXPECT_EQ_INT(LEPT_STRING, lept_get_type(lept_get_array_element(&v, 4)));
EXPECT_EQ_DOUBLE(123.0, lept_get_number(lept_get_array_element(&v, 3)));
EXPECT_EQ_STRING("abc", lept_get_string(lept_get_array_element(&v, 4)), lept_get_string_length(lept_get_array_element(&v, 4)));
lept_free(&v);
lept_init(&v);
EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v, "[ [ ] , [ 0 ] , [ 0 , 1 ] , [ 0 , 1 , 2 ] ]"));
EXPECT_EQ_INT(LEPT_ARRAY, lept_get_type(&v));
EXPECT_EQ_SIZE_T(4, lept_get_array_size(&v));
for (i = 0; i < 4; i++) {
lept_value* a = lept_get_array_element(&v, i);
EXPECT_EQ_INT(LEPT_ARRAY, lept_get_type(a));
EXPECT_EQ_SIZE_T(i, lept_get_array_size(a));
for (j = 0; j < i; j++) {
lept_value* e = lept_get_array_element(a, j);
EXPECT_EQ_INT(LEPT_NUMBER, lept_get_type(e));
EXPECT_EQ_DOUBLE((double)j, lept_get_number(e));
}
}
lept_free(&v);
}
static void test_parse_object() {
lept_value v;
size_t i;
lept_init(&v);
EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v, " { } "));
EXPECT_EQ_INT(LEPT_OBJECT, lept_get_type(&v));
EXPECT_EQ_SIZE_T(0, lept_get_object_size(&v));
lept_free(&v);
lept_init(&v);
EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v,
" { "
"\"n\" : null , "
"\"f\" : false , "
"\"t\" : true , "
"\"i\" : 123 , "
"\"s\" : \"abc\", "
"\"a\" : [ 1, 2, 3 ],"
"\"o\" : { \"1\" : 1, \"2\" : 2, \"3\" : 3 }"
" } "
));
EXPECT_EQ_INT(LEPT_OBJECT, lept_get_type(&v));
EXPECT_EQ_SIZE_T(7, lept_get_object_size(&v));
EXPECT_EQ_STRING("n", lept_get_object_key(&v, 0), lept_get_object_key_length(&v, 0));
EXPECT_EQ_INT(LEPT_NULL, lept_get_type(lept_get_object_value(&v, 0)));
EXPECT_EQ_STRING("f", lept_get_object_key(&v, 1), lept_get_object_key_length(&v, 1));
EXPECT_EQ_INT(LEPT_FALSE, lept_get_type(lept_get_object_value(&v, 1)));
EXPECT_EQ_STRING("t", lept_get_object_key(&v, 2), lept_get_object_key_length(&v, 2));
EXPECT_EQ_INT(LEPT_TRUE, lept_get_type(lept_get_object_value(&v, 2)));
EXPECT_EQ_STRING("i", lept_get_object_key(&v, 3), lept_get_object_key_length(&v, 3));
EXPECT_EQ_INT(LEPT_NUMBER, lept_get_type(lept_get_object_value(&v, 3)));
EXPECT_EQ_DOUBLE(123.0, lept_get_number(lept_get_object_value(&v, 3)));
EXPECT_EQ_STRING("s", lept_get_object_key(&v, 4), lept_get_object_key_length(&v, 4));
EXPECT_EQ_INT(LEPT_STRING, lept_get_type(lept_get_object_value(&v, 4)));
EXPECT_EQ_STRING("abc", lept_get_string(lept_get_object_value(&v, 4)), lept_get_string_length(lept_get_object_value(&v, 4)));
EXPECT_EQ_STRING("a", lept_get_object_key(&v, 5), lept_get_object_key_length(&v, 5));
EXPECT_EQ_INT(LEPT_ARRAY, lept_get_type(lept_get_object_value(&v, 5)));
EXPECT_EQ_SIZE_T(3, lept_get_array_size(lept_get_object_value(&v, 5)));
for (i = 0; i < 3; i++) {
lept_value* e = lept_get_array_element(lept_get_object_value(&v, 5), i);
EXPECT_EQ_INT(LEPT_NUMBER, lept_get_type(e));
EXPECT_EQ_DOUBLE(i + 1.0, lept_get_number(e));
}
EXPECT_EQ_STRING("o", lept_get_object_key(&v, 6), lept_get_object_key_length(&v, 6));
{
lept_value* o = lept_get_object_value(&v, 6);
EXPECT_EQ_INT(LEPT_OBJECT, lept_get_type(o));
for (i = 0; i < 3; i++) {
lept_value* ov = lept_get_object_value(o, i);
EXPECT_TRUE('1' + i == lept_get_object_key(o, i)[0]);
EXPECT_EQ_SIZE_T(1, lept_get_object_key_length(o, i));
EXPECT_EQ_INT(LEPT_NUMBER, lept_get_type(ov));
EXPECT_EQ_DOUBLE(i + 1.0, lept_get_number(ov));
}
}
lept_free(&v);
}
/
#define TEST_PARSE_ERROR(error, json)\
do {\
lept_value v;\
lept_init(&v);\
v.type = LEPT_FALSE;\
EXPECT_EQ_INT(error, lept_parse(&v, json));\
EXPECT_EQ_INT(LEPT_NULL, lept_get_type(&v));\
lept_free(&v);\
} while(0)
static void test_parse_expect_value() {
TEST_PARSE_ERROR(LEPT_PARSE_EXPECT_VALUE, "");
TEST_PARSE_ERROR(LEPT_PARSE_EXPECT_VALUE, " ");
}
static void test_parse_invalid_value() {
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_VALUE, "nul");
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_VALUE, "?");
/* invalid number */
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_VALUE, "+0");
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_VALUE, "+1");
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_VALUE, ".123"); /* at least one digit before '.' */
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_VALUE, "1."); /* at least one digit after '.' */
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_VALUE, "INF");
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_VALUE, "inf");
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_VALUE, "NAN");
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_VALUE, "nan");
/* invalid value in array */
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_VALUE, "[1,]");
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_VALUE, "[\"a\", nul]");
}
static void test_parse_root_not_singular() {
TEST_PARSE_ERROR(LEPT_PARSE_ROOT_NOT_SINGULAR, "null x");
/* invalid number */
TEST_PARSE_ERROR(LEPT_PARSE_ROOT_NOT_SINGULAR, "0123"); /* after zero should be '.' , 'E' , 'e' or nothing */
TEST_PARSE_ERROR(LEPT_PARSE_ROOT_NOT_SINGULAR, "0x0");
TEST_PARSE_ERROR(LEPT_PARSE_ROOT_NOT_SINGULAR, "0x123");
}
static void test_parse_number_too_big() {
TEST_PARSE_ERROR(LEPT_PARSE_NUMBER_TOO_BIG, "1e309");
TEST_PARSE_ERROR(LEPT_PARSE_NUMBER_TOO_BIG, "-1e309");
}
static void test_parse_miss_quotation_mark() {
TEST_PARSE_ERROR(LEPT_PARSE_MISS_QUOTATION_MARK, "\"");
TEST_PARSE_ERROR(LEPT_PARSE_MISS_QUOTATION_MARK, "\"abc");
}
static void test_parse_invalid_string_escape() {
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_STRING_ESCAPE, "\"\\v\"");
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_STRING_ESCAPE, "\"\\'\"");
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_STRING_ESCAPE, "\"\\0\"");
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_STRING_ESCAPE, "\"\\x12\"");
}
static void test_parse_invalid_string_char() {
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_STRING_CHAR, "\"\x01\"");
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_STRING_CHAR, "\"\x1F\"");
}
static void test_parse_invalid_unicode_hex() {
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_UNICODE_HEX, "\"\\u\"");
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_UNICODE_HEX, "\"\\u0\"");
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_UNICODE_HEX, "\"\\u01\"");
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_UNICODE_HEX, "\"\\u012\"");
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_UNICODE_HEX, "\"\\u/000\"");
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_UNICODE_HEX, "\"\\uG000\"");
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_UNICODE_HEX, "\"\\u0/00\"");
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_UNICODE_HEX, "\"\\u0G00\"");
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_UNICODE_HEX, "\"\\u0/00\"");
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_UNICODE_HEX, "\"\\u00G0\"");
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_UNICODE_HEX, "\"\\u000/\"");
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_UNICODE_HEX, "\"\\u000G\"");
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_UNICODE_HEX, "\"\\u 123\"");
}
static void test_parse_invalid_unicode_surrogate() {
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_UNICODE_SURROGATE, "\"\\uD800\"");
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_UNICODE_SURROGATE, "\"\\uDBFF\"");
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_UNICODE_SURROGATE, "\"\\uD800\\\\\"");
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_UNICODE_SURROGATE, "\"\\uD800\\uDBFF\"");
TEST_PARSE_ERROR(LEPT_PARSE_INVALID_UNICODE_SURROGATE, "\"\\uD800\\uE000\"");
}
static void test_parse_miss_comma_or_square_bracket() {
TEST_PARSE_ERROR(LEPT_PARSE_MISS_COMMA_OR_SQUARE_BRACKET, "[1");
TEST_PARSE_ERROR(LEPT_PARSE_MISS_COMMA_OR_SQUARE_BRACKET, "[1}");
TEST_PARSE_ERROR(LEPT_PARSE_MISS_COMMA_OR_SQUARE_BRACKET, "[1 2");
TEST_PARSE_ERROR(LEPT_PARSE_MISS_COMMA_OR_SQUARE_BRACKET, "[[]");
}
static void test_parse_miss_key() {
TEST_PARSE_ERROR(LEPT_PARSE_MISS_KEY, "{:1,");
TEST_PARSE_ERROR(LEPT_PARSE_MISS_KEY, "{1:1,");
TEST_PARSE_ERROR(LEPT_PARSE_MISS_KEY, "{true:1,");
TEST_PARSE_ERROR(LEPT_PARSE_MISS_KEY, "{false:1,");
TEST_PARSE_ERROR(LEPT_PARSE_MISS_KEY, "{null:1,");
TEST_PARSE_ERROR(LEPT_PARSE_MISS_KEY, "{[]:1,");
TEST_PARSE_ERROR(LEPT_PARSE_MISS_KEY, "{{}:1,");
TEST_PARSE_ERROR(LEPT_PARSE_MISS_KEY, "{\"a\":1,");
}
static void test_parse_miss_colon() {
TEST_PARSE_ERROR(LEPT_PARSE_MISS_COLON, "{\"a\"}");
TEST_PARSE_ERROR(LEPT_PARSE_MISS_COLON, "{\"a\",\"b\"}");
}
static void test_parse_miss_comma_or_curly_bracket() {
TEST_PARSE_ERROR(LEPT_PARSE_MISS_COMMA_OR_CURLY_BRACKET, "{\"a\":1");
TEST_PARSE_ERROR(LEPT_PARSE_MISS_COMMA_OR_CURLY_BRACKET, "{\"a\":1]");
TEST_PARSE_ERROR(LEPT_PARSE_MISS_COMMA_OR_CURLY_BRACKET, "{\"a\":1 \"b\"");
TEST_PARSE_ERROR(LEPT_PARSE_MISS_COMMA_OR_CURLY_BRACKET, "{\"a\":{}");
}
static void test_parse() {
test_parse_null();
test_parse_true();
test_parse_false();
test_parse_number();
test_parse_string();
test_parse_array();
test_parse_object();
test_parse_expect_value();
test_parse_invalid_value();
test_parse_root_not_singular();
test_parse_number_too_big();
test_parse_miss_quotation_mark();
test_parse_invalid_string_escape();
test_parse_invalid_string_char();
test_parse_invalid_unicode_hex();
test_parse_invalid_unicode_surrogate();
test_parse_miss_comma_or_square_bracket();
test_parse_miss_key();
test_parse_miss_colon();
test_parse_miss_comma_or_curly_bracket();
}
#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));\
json2 = lept_stringify(&v, &length);\
EXPECT_EQ_STRING(json, json2, length);\
lept_free(&v);\
free(json2);\
} while(0)
static void 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");
TEST_ROUNDTRIP("1.0000000000000002"); /* the smallest number > 1 */
TEST_ROUNDTRIP("4.9406564584124654e-324"); /* minimum denormal */
TEST_ROUNDTRIP("-4.9406564584124654e-324");
TEST_ROUNDTRIP("2.2250738585072009e-308"); /* Max subnormal double */
TEST_ROUNDTRIP("-2.2250738585072009e-308");
TEST_ROUNDTRIP("2.2250738585072014e-308"); /* Min normal positive double */
TEST_ROUNDTRIP("-2.2250738585072014e-308");
TEST_ROUNDTRIP("1.7976931348623157e+308"); /* Max double */
TEST_ROUNDTRIP("-1.7976931348623157e+308");
}
static void test_stringify_string() {
TEST_ROUNDTRIP("\"\"");
TEST_ROUNDTRIP("\"Hello\"");
TEST_ROUNDTRIP("\"Hello\\nWorld\"");
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();
}
#define TEST_EQUAL(json1, json2, equality) \
do {\
lept_value v1, v2;\
lept_init(&v1);\
lept_init(&v2);\
EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v1, json1));\
EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v2, json2));\
EXPECT_EQ_INT(equality, lept_is_equal(&v1, &v2));\
lept_free(&v1);\
lept_free(&v2);\
} while(0)
static void test_equal() {
TEST_EQUAL("true", "true", 1);
TEST_EQUAL("true", "false", 0);
TEST_EQUAL("false", "false", 1);
TEST_EQUAL("null", "null", 1);
TEST_EQUAL("null", "0", 0);
TEST_EQUAL("123", "123", 1);
TEST_EQUAL("123", "456", 0);
TEST_EQUAL("\"abc\"", "\"abc\"", 1);
TEST_EQUAL("\"abc\"", "\"abcd\"", 0);
TEST_EQUAL("[]", "[]", 1);
TEST_EQUAL("[]", "null", 0);
TEST_EQUAL("[1,2,3]", "[1,2,3]", 1);
TEST_EQUAL("[1,2,3]", "[1,2,3,4]", 0);
TEST_EQUAL("[[]]", "[[]]", 1);
TEST_EQUAL("{}", "{}", 1);
TEST_EQUAL("{}", "null", 0);
TEST_EQUAL("{}", "[]", 0);
TEST_EQUAL("{\"a\":1,\"b\":2}", "{\"a\":1,\"b\":2}", 1);
TEST_EQUAL("{\"a\":1,\"b\":2}", "{\"b\":2,\"a\":1}", 1);
TEST_EQUAL("{\"a\":1,\"b\":2}", "{\"a\":1,\"b\":3}", 0);
TEST_EQUAL("{\"a\":1,\"b\":2}", "{\"a\":1,\"b\":2,\"c\":3}", 0);
TEST_EQUAL("{\"a\":{\"b\":{\"c\":{}}}}", "{\"a\":{\"b\":{\"c\":{}}}}", 1);
TEST_EQUAL("{\"a\":{\"b\":{\"c\":{}}}}", "{\"a\":{\"b\":{\"c\":[]}}}", 0);
}
static void test_copy() {
lept_value v1, v2;
lept_init(&v1);
lept_parse(&v1, "{\"t\":true,\"f\":false,\"n\":null,\"d\":1.5,\"a\":[1,2,3]}");
lept_init(&v2);
lept_copy(&v2, &v1);
EXPECT_TRUE(lept_is_equal(&v2, &v1));
lept_free(&v1);
lept_free(&v2);
}
static void test_move() {
lept_value v1, v2, v3;
lept_init(&v1);
lept_parse(&v1, "{\"t\":true,\"f\":false,\"n\":null,\"d\":1.5,\"a\":[1,2,3]}");
lept_init(&v2);
lept_copy(&v2, &v1);
lept_init(&v3);
lept_move(&v3, &v2);
EXPECT_EQ_INT(LEPT_NULL, lept_get_type(&v2));
EXPECT_TRUE(lept_is_equal(&v3, &v1));
lept_free(&v1);
lept_free(&v2);
lept_free(&v3);
}
static void test_swap() {
lept_value v1, v2;
lept_init(&v1);
lept_init(&v2);
lept_set_string(&v1, "Hello", 5);
lept_set_string(&v2, "World!", 6);
lept_swap(&v1, &v2);
EXPECT_EQ_STRING("World!", lept_get_string(&v1), lept_get_string_length(&v1));
EXPECT_EQ_STRING("Hello", lept_get_string(&v2), lept_get_string_length(&v2));
lept_free(&v1);
lept_free(&v2);
}
static void test_access_null() {
lept_value v;
lept_init(&v);
lept_set_string(&v, "a", 1);
lept_set_null(&v);
EXPECT_EQ_INT(LEPT_NULL, lept_get_type(&v));
lept_free(&v);
}
static void test_access_boolean() {
lept_value v;
lept_init(&v);
lept_set_string(&v, "a", 1);
lept_set_boolean(&v, 1);
EXPECT_TRUE(lept_get_boolean(&v));
lept_set_boolean(&v, 0);
EXPECT_FALSE(lept_get_boolean(&v));
lept_free(&v);
}
static void test_access_number() {
lept_value v;
lept_init(&v);
lept_set_string(&v, "a", 1);
lept_set_number(&v, 1234.5);
EXPECT_EQ_DOUBLE(1234.5, lept_get_number(&v));
lept_free(&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_access_array() {
lept_value a, e;
size_t i, j;
lept_init(&a);
for (j = 0; j <= 5; j += 5) {
lept_set_array(&a, j);
EXPECT_EQ_SIZE_T(0, lept_get_array_size(&a));
EXPECT_EQ_SIZE_T(j, lept_get_array_capacity(&a));
for (i = 0; i < 10; i++) {
lept_init(&e);
lept_set_number(&e, i);
lept_move(lept_pushback_array_element(&a), &e);
lept_free(&e);
}
EXPECT_EQ_SIZE_T(10, lept_get_array_size(&a));
for (i = 0; i < 10; i++)
EXPECT_EQ_DOUBLE((double)i, lept_get_number(lept_get_array_element(&a, i)));
}
lept_popback_array_element(&a);
EXPECT_EQ_SIZE_T(9, lept_get_array_size(&a));
for (i = 0; i < 9; i++)
EXPECT_EQ_DOUBLE((double)i, lept_get_number(lept_get_array_element(&a, i)));
lept_erase_array_element(&a, 4, 0);
EXPECT_EQ_SIZE_T(9, lept_get_array_size(&a));
for (i = 0; i < 9; i++)
EXPECT_EQ_DOUBLE((double)i, lept_get_number(lept_get_array_element(&a, i)));
lept_erase_array_element(&a, 8, 1);
EXPECT_EQ_SIZE_T(8, lept_get_array_size(&a));
for (i = 0; i < 8; i++)
EXPECT_EQ_DOUBLE((double)i, lept_get_number(lept_get_array_element(&a, i)));
lept_erase_array_element(&a, 0, 2);
EXPECT_EQ_SIZE_T(6, lept_get_array_size(&a));
for (i = 0; i < 6; i++)
EXPECT_EQ_DOUBLE((double)i + 2, lept_get_number(lept_get_array_element(&a, i)));
#if 0
for (i = 0; i < 2; i++) {
lept_init(&e);
lept_set_number(&e, i);
lept_move(lept_insert_array_element(&a, i), &e);
lept_free(&e);
}
#endif
EXPECT_EQ_SIZE_T(8, lept_get_array_size(&a));
for (i = 0; i < 8; i++)
EXPECT_EQ_DOUBLE((double)i, lept_get_number(lept_get_array_element(&a, i)));
EXPECT_TRUE(lept_get_array_capacity(&a) > 8);
lept_shrink_array(&a);
EXPECT_EQ_SIZE_T(8, lept_get_array_capacity(&a));
EXPECT_EQ_SIZE_T(8, lept_get_array_size(&a));
for (i = 0; i < 8; i++)
EXPECT_EQ_DOUBLE((double)i, lept_get_number(lept_get_array_element(&a, i)));
lept_set_string(&e, "Hello", 5);
lept_move(lept_pushback_array_element(&a), &e); /* Test if element is freed */
lept_free(&e);
i = lept_get_array_capacity(&a);
lept_clear_array(&a);
EXPECT_EQ_SIZE_T(0, lept_get_array_size(&a));
EXPECT_EQ_SIZE_T(i, lept_get_array_capacity(&a)); /* capacity remains unchanged */
lept_shrink_array(&a);
EXPECT_EQ_SIZE_T(0, lept_get_array_capacity(&a));
lept_free(&a);
}
static void test_access_object() {
#if 0
lept_value o, v, *pv;
size_t i, j, index;
lept_init(&o);
for (j = 0; j <= 5; j += 5) {
lept_set_object(&o, j);
EXPECT_EQ_SIZE_T(0, lept_get_object_size(&o));
EXPECT_EQ_SIZE_T(j, lept_get_object_capacity(&o));
for (i = 0; i < 10; i++) {
char key[2] = "a";
key[0] += i;
lept_init(&v);
lept_set_number(&v, i);
lept_move(lept_set_object_value(&o, key, 1), &v);
lept_free(&v);
}
EXPECT_EQ_SIZE_T(10, lept_get_object_size(&o));
for (i = 0; i < 10; i++) {
char key[] = "a";
key[0] += i;
index = lept_find_object_index(&o, key, 1);
EXPECT_TRUE(index != LEPT_KEY_NOT_EXIST);
pv = lept_get_object_value(&o, index);
EXPECT_EQ_DOUBLE((double)i, lept_get_number(pv));
}
}
index = lept_find_object_index(&o, "j", 1);
EXPECT_TRUE(index != LEPT_KEY_NOT_EXIST);
lept_remove_object_value(&o, index);
index = lept_find_object_index(&o, "j", 1);
EXPECT_TRUE(index == LEPT_KEY_NOT_EXIST);
EXPECT_EQ_SIZE_T(9, lept_get_object_size(&o));
index = lept_find_object_index(&o, "a", 1);
EXPECT_TRUE(index != LEPT_KEY_NOT_EXIST);
lept_remove_object_value(&o, index);
index = lept_find_object_index(&o, "a", 1);
EXPECT_TRUE(index == LEPT_KEY_NOT_EXIST);
EXPECT_EQ_SIZE_T(8, lept_get_object_size(&o));
EXPECT_TRUE(lept_get_object_capacity(&o) > 8);
lept_shrink_object(&o);
EXPECT_EQ_SIZE_T(8, lept_get_object_capacity(&o));
EXPECT_EQ_SIZE_T(8, lept_get_object_size(&o));
for (i = 0; i < 8; i++) {
char key[] = "a";
key[0] += i + 1;
EXPECT_EQ_DOUBLE((double)i + 1, lept_get_number(lept_get_object_value(&o, lept_find_object_index(&o, key, 1))));
}
lept_set_string(&v, "Hello", 5);
lept_move(lept_set_object_value(&o, "World", 5), &v); /* Test if element is freed */
lept_free(&v);
pv = lept_find_object_value(&o, "World", 5);
EXPECT_TRUE(pv != NULL);
EXPECT_EQ_STRING("Hello", lept_get_string(pv), lept_get_string_length(pv));
i = lept_get_object_capacity(&o);
lept_clear_object(&o);
EXPECT_EQ_SIZE_T(0, lept_get_object_size(&o));
EXPECT_EQ_SIZE_T(i, lept_get_object_capacity(&o)); /* capacity remains unchanged */
lept_shrink_object(&o);
EXPECT_EQ_SIZE_T(0, lept_get_object_capacity(&o));
lept_free(&o);
#endif
}
static void test_access() {
test_access_null();
test_access_boolean();
test_access_number();
test_access_string();
test_access_array();
test_access_object();
}
int main() {
#ifdef _WINDOWS
//http://www.cnitblog.com/luckydmz/archive/2019/11/05/91938.aspx
//启动是否有内存泄露
//当没有定义_DEBUG宏时,下面的调用会被替换成一个哑的宏,什么都不做
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG);
#endif
test_parse();
test_stringify();
test_equal();
test_copy();
test_move();
test_swap();
test_access();
printf("%d/%d (%3.2f%%) passed\n", test_pass, test_count, test_pass * 100.0 / test_count);
system("pause");
return main_ret;
}