style: 应用 clang-format
This commit is contained in:
1 parent
016a45bc6e
commit
d1612f1d31
65 files changed
+7288
-5983
No files matched your search
+92
-68
@@ -9,25 +9,26 @@
|
||||
static int failures = 0;
|
||||
static int checks = 0;
|
||||
|
||||
#define CHECK(cond, ...) \
|
||||
do { \
|
||||
checks++; \
|
||||
if (!(cond)) { \
|
||||
failures++; \
|
||||
printf(" ✗ %s:%d: ", __FILE__, __LINE__); \
|
||||
printf(__VA_ARGS__); \
|
||||
printf("\n"); \
|
||||
} \
|
||||
#define CHECK(cond, ...) \
|
||||
do { \
|
||||
checks++; \
|
||||
if (!(cond)) { \
|
||||
failures++; \
|
||||
printf(" ✗ %s:%d: ", __FILE__, __LINE__); \
|
||||
printf(__VA_ARGS__); \
|
||||
printf("\n"); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static void test_basic(void)
|
||||
{
|
||||
static void test_basic(void) {
|
||||
puts("test_basic");
|
||||
char err[256];
|
||||
JsonValue *v = json_parse("{\"a\": 1, \"b\": [true, false, null], \"c\": \"hi\"}",
|
||||
err, sizeof err);
|
||||
JsonValue *v =
|
||||
json_parse("{\"a\": 1, \"b\": [true, false, null], \"c\": \"hi\"}", err,
|
||||
sizeof err);
|
||||
CHECK(v != NULL, "解析失败: %s", err);
|
||||
if (!v) return;
|
||||
if (!v)
|
||||
return;
|
||||
CHECK(json_get_number(v, "a", -1) == 1, "a 应为 1");
|
||||
CHECK(json_array_size(json_object_get(v, "b")) == 3, "b 应有 3 个元素");
|
||||
CHECK(json_bool_value(json_array_get(json_object_get(v, "b"), 0), 0) == 1,
|
||||
@@ -41,18 +42,20 @@ static void test_basic(void)
|
||||
CHECK(v2 != NULL, "往返解析失败: %s", err);
|
||||
char *dump2 = json_dump(v2);
|
||||
CHECK(strcmp(dump, dump2) == 0, "往返不一致:\n %s\n %s", dump, dump2);
|
||||
free(dump); free(dump2);
|
||||
json_free(v); json_free(v2);
|
||||
free(dump);
|
||||
free(dump2);
|
||||
json_free(v);
|
||||
json_free(v2);
|
||||
}
|
||||
|
||||
static void test_escapes(void)
|
||||
{
|
||||
static void test_escapes(void) {
|
||||
puts("test_escapes");
|
||||
char err[256];
|
||||
JsonValue *v = json_parse("\"a\\nb\\t\\\"c\\\\d\\u4e2d\\u6587\\uD83D\\uDE00\"",
|
||||
err, sizeof err);
|
||||
JsonValue *v = json_parse(
|
||||
"\"a\\nb\\t\\\"c\\\\d\\u4e2d\\u6587\\uD83D\\uDE00\"", err, sizeof err);
|
||||
CHECK(v != NULL, "解析失败: %s", err);
|
||||
if (!v) return;
|
||||
if (!v)
|
||||
return;
|
||||
const char *s = json_string_value(v);
|
||||
CHECK(strcmp(s, "a\nb\t\"c\\d中文😀") == 0, "转义解码错误: [%s]", s);
|
||||
|
||||
@@ -61,16 +64,18 @@ static void test_escapes(void)
|
||||
CHECK(v2 != NULL, "转义往返失败: %s / %s", q, err);
|
||||
CHECK(v2 && strcmp(json_string_value(v2), s) == 0, "转义往返内容不一致");
|
||||
free(q);
|
||||
json_free(v); json_free(v2);
|
||||
json_free(v);
|
||||
json_free(v2);
|
||||
}
|
||||
|
||||
static void test_numbers(void)
|
||||
{
|
||||
static void test_numbers(void) {
|
||||
puts("test_numbers");
|
||||
char err[256];
|
||||
JsonValue *v = json_parse("[0, -1, 3.5, 1e3, -2.5e-2, 123456789012]", err, sizeof err);
|
||||
JsonValue *v =
|
||||
json_parse("[0, -1, 3.5, 1e3, -2.5e-2, 123456789012]", err, sizeof err);
|
||||
CHECK(v != NULL, "解析失败: %s", err);
|
||||
if (!v) return;
|
||||
if (!v)
|
||||
return;
|
||||
CHECK(json_number_value(json_array_get(v, 0), -1) == 0, "[0]");
|
||||
CHECK(json_number_value(json_array_get(v, 1), 0) == -1, "[1]");
|
||||
CHECK(json_number_value(json_array_get(v, 2), 0) == 3.5, "[2]");
|
||||
@@ -92,24 +97,34 @@ static void test_numbers(void)
|
||||
}
|
||||
/* 边界上合法的写法不能被误伤 */
|
||||
const char *ok_nums[] = {
|
||||
"0", "-0", "0.0", "10", "-1.5", "1e3", "1E3", "1e+3", "1e-3", "0.1e10",
|
||||
"123456789012345678901234567890", "1e308",
|
||||
"0",
|
||||
"-0",
|
||||
"0.0",
|
||||
"10",
|
||||
"-1.5",
|
||||
"1e3",
|
||||
"1E3",
|
||||
"1e+3",
|
||||
"1e-3",
|
||||
"0.1e10",
|
||||
"123456789012345678901234567890",
|
||||
"1e308",
|
||||
};
|
||||
for (size_t i = 0; i < sizeof ok_nums / sizeof ok_nums[0]; i++) {
|
||||
JsonValue *g = json_parse(ok_nums[i], err, sizeof err);
|
||||
CHECK(g != NULL && g->type == JSON_NUMBER,
|
||||
"合法数字被拒: [%s] (%s)", ok_nums[i], err);
|
||||
CHECK(g != NULL && g->type == JSON_NUMBER, "合法数字被拒: [%s] (%s)",
|
||||
ok_nums[i], err);
|
||||
json_free(g);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_invalid(void)
|
||||
{
|
||||
static void test_invalid(void) {
|
||||
puts("test_invalid");
|
||||
char err[256];
|
||||
const char *bad[] = {
|
||||
"{", "}", "[1,]", "{\"a\":}", "\"unterminated", "tru", "{\"a\" 1}",
|
||||
"[1 2]", "01abc", "", " ", "{\"a\":1}}", "[1,2] extra",
|
||||
"{", "}", "[1,]", "{\"a\":}", "\"unterminated",
|
||||
"tru", "{\"a\" 1}", "[1 2]", "01abc", "",
|
||||
" ", "{\"a\":1}}", "[1,2] extra",
|
||||
};
|
||||
for (size_t i = 0; i < sizeof bad / sizeof bad[0]; i++) {
|
||||
JsonValue *v = json_parse(bad[i], err, sizeof err);
|
||||
@@ -118,12 +133,12 @@ static void test_invalid(void)
|
||||
}
|
||||
/* 空字符串是合法 JSON 字符串 */
|
||||
JsonValue *e = json_parse("\"\"", err, sizeof err);
|
||||
CHECK(e != NULL && strcmp(json_string_value(e), "") == 0, "空字符串应为合法");
|
||||
CHECK(e != NULL && strcmp(json_string_value(e), "") == 0,
|
||||
"空字符串应为合法");
|
||||
json_free(e);
|
||||
}
|
||||
|
||||
static void test_builders(void)
|
||||
{
|
||||
static void test_builders(void) {
|
||||
puts("test_builders");
|
||||
JsonValue *o = json_new_object();
|
||||
json_object_set_string(o, "model", "gpt-x");
|
||||
@@ -133,30 +148,34 @@ static void test_builders(void)
|
||||
json_array_push(arr, json_new_string("a"));
|
||||
json_array_push(arr, json_new_string("b"));
|
||||
json_object_set(o, "items", arr);
|
||||
json_object_set_string(o, "model", "gpt-y"); /* 覆盖 */
|
||||
json_object_set_string(o, "model", "gpt-y"); /* 覆盖 */
|
||||
|
||||
char *s = json_dump(o);
|
||||
CHECK(strcmp(s, "{\"model\":\"gpt-y\",\"n\":3,\"ok\":true,\"items\":[\"a\",\"b\"]}") == 0,
|
||||
CHECK(strcmp(s, "{\"model\":\"gpt-y\",\"n\":3,\"ok\":true,\"items\":[\"a\","
|
||||
"\"b\"]}") == 0,
|
||||
"构造结果不对: %s", s);
|
||||
free(s);
|
||||
|
||||
/* clone 独立性 */
|
||||
JsonValue *c = json_clone(o);
|
||||
json_object_set_string(o, "model", "changed");
|
||||
CHECK(strcmp(json_get_string(c, "model"), "gpt-y") == 0, "clone 应相互独立");
|
||||
CHECK(strcmp(json_get_string(c, "model"), "gpt-y") == 0,
|
||||
"clone 应相互独立");
|
||||
json_object_remove(o, "model");
|
||||
CHECK(json_object_get(o, "model") == NULL, "remove 应删除键");
|
||||
json_free(o); json_free(c);
|
||||
json_free(o);
|
||||
json_free(c);
|
||||
}
|
||||
|
||||
static void test_nested_depth(void)
|
||||
{
|
||||
static void test_nested_depth(void) {
|
||||
puts("test_nested_depth");
|
||||
char err[256];
|
||||
size_t n = 300;
|
||||
char *deep = xmalloc(n * 2 + 1);
|
||||
for (size_t i = 0; i < n; i++) deep[i] = '[';
|
||||
for (size_t i = 0; i < n; i++) deep[n + i] = ']';
|
||||
for (size_t i = 0; i < n; i++)
|
||||
deep[i] = '[';
|
||||
for (size_t i = 0; i < n; i++)
|
||||
deep[n + i] = ']';
|
||||
deep[n * 2] = '\0';
|
||||
JsonValue *v = json_parse(deep, err, sizeof err);
|
||||
CHECK(v == NULL, "超深嵌套应被拒绝");
|
||||
@@ -168,8 +187,7 @@ static void test_nested_depth(void)
|
||||
}
|
||||
|
||||
/* 报错必须能定位: 只有"语法错了"而不知道错在哪, 等于没有报错 */
|
||||
static void test_error_location(void)
|
||||
{
|
||||
static void test_error_location(void) {
|
||||
puts("test_error_location");
|
||||
char err[256];
|
||||
JsonValue *v;
|
||||
@@ -192,7 +210,8 @@ static void test_error_location(void)
|
||||
/* 缺冒号 */
|
||||
v = json_parse("{\"a\" 1}", err, sizeof err);
|
||||
CHECK(v == NULL, "缺冒号应报错");
|
||||
CHECK(strstr(err, "第 1 行") && strstr(err, "':'") != NULL, "缺冒号: %s", err);
|
||||
CHECK(strstr(err, "第 1 行") && strstr(err, "':'") != NULL, "缺冒号: %s",
|
||||
err);
|
||||
json_free(v);
|
||||
|
||||
/* 尾部多余内容 */
|
||||
@@ -220,30 +239,29 @@ static void test_error_location(void)
|
||||
json_free(v);
|
||||
}
|
||||
|
||||
/* 序列化出去的东西必须是**合法 UTF-8**.
|
||||
/* 序列化出去的东西必须是**合法 UTF-8**.
|
||||
*
|
||||
* 服务端会因为请求体里有非法 UTF-8 直接回
|
||||
* 400 ... invalid unicode code point
|
||||
* 而那段坏数据一旦进了对话历史, 之后每次请求都会失败 —— 除非丢掉整轮对话.
|
||||
* 而那段坏数据一旦进了对话历史, 之后每次请求都会失败 —— 除非丢掉整轮对话.
|
||||
* 坏字节的来源很日常: 某条命令在非 UTF-8 locale 下打出来的路径、被截断的多
|
||||
* 字节字符、二进制垃圾. 所以这条不能只靠"在入口清理", 必须在序列化器这层兜住:
|
||||
* 出口是唯一能保证"发出去的永远合法"的地方.
|
||||
* 字节字符、二进制垃圾. 所以这条不能只靠"在入口清理", 必须在序列化器这层兜住:
|
||||
* 出口是唯一能保证"发出去的永远合法"的地方.
|
||||
*
|
||||
* 这个校验函数故意用 utf8_seq_len 自己走一遍, 而不是信任 dump 的实现 ——
|
||||
* 断言的是**产物**的性质, 不是实现的自述. */
|
||||
static int utf8_all_valid(const char *s)
|
||||
{
|
||||
static int utf8_all_valid(const char *s) {
|
||||
size_t n = strlen(s), i = 0;
|
||||
while (i < n) {
|
||||
size_t adv = utf8_seq_len(s + i, n - i);
|
||||
if (adv == 0) return 0;
|
||||
if (adv == 0)
|
||||
return 0;
|
||||
i += adv;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void test_dump_utf8_safety(void)
|
||||
{
|
||||
static void test_dump_utf8_safety(void) {
|
||||
puts("test_dump_utf8_safety");
|
||||
|
||||
/* utf8_seq_len: 合法序列返回长度 */
|
||||
@@ -262,19 +280,25 @@ static void test_dump_utf8_safety(void)
|
||||
|
||||
/* 各种坏字节经 json_dump 之后, 整份输出必须是合法 UTF-8 */
|
||||
static const char *bad[] = {
|
||||
"a\x80" "b", /* 孤立续字节 */
|
||||
"a\xe4\xb8" "b", /* 截断的 3 字节序列 */
|
||||
"a\xc0\xaf" "b", /* 过长编码 (历史上被用来夹带 '/') */
|
||||
"a\xed\xa0\x80" "b", /* UTF-16 代理区 */
|
||||
"a\xf5\x80\x80\x80" "b", /* 超出 U+10FFFF */
|
||||
"\xff\xfe", /* 二进制垃圾 */
|
||||
"\xe4\xb8\xad\x80\xe6", /* 合法中文里夹一个坏字节 */
|
||||
"a\x80"
|
||||
"b", /* 孤立续字节 */
|
||||
"a\xe4\xb8"
|
||||
"b", /* 截断的 3 字节序列 */
|
||||
"a\xc0\xaf"
|
||||
"b", /* 过长编码 (历史上被用来夹带 '/') */
|
||||
"a\xed\xa0\x80"
|
||||
"b", /* UTF-16 代理区 */
|
||||
"a\xf5\x80\x80\x80"
|
||||
"b", /* 超出 U+10FFFF */
|
||||
"\xff\xfe", /* 二进制垃圾 */
|
||||
"\xe4\xb8\xad\x80\xe6", /* 合法中文里夹一个坏字节 */
|
||||
};
|
||||
for (size_t k = 0; k < sizeof bad / sizeof bad[0]; k++) {
|
||||
JsonValue *o = json_new_object();
|
||||
json_object_set_string(o, "content", bad[k]);
|
||||
char *d = json_dump(o);
|
||||
CHECK(utf8_all_valid(d), "第 %zu 个坏输入序列化后仍含非法 UTF-8: %s", k, d);
|
||||
CHECK(utf8_all_valid(d), "第 %zu 个坏输入序列化后仍含非法 UTF-8: %s", k,
|
||||
d);
|
||||
/* 而且我们的解析器 (和服务端一样严格)必须收得下 */
|
||||
char err[256];
|
||||
JsonValue *back = json_parse(d, err, sizeof err);
|
||||
@@ -294,14 +318,14 @@ static void test_dump_utf8_safety(void)
|
||||
json_object_set_string(o, "content", "中文 😀 tail");
|
||||
char *d = json_dump(o);
|
||||
CHECK(strstr(d, "中文") != NULL, "合法中文不该被改动: %s", d);
|
||||
CHECK(strstr(d, "\xf0\x9f\x98\x80") != NULL, "合法 emoji 不该被改动: %s", d);
|
||||
CHECK(strstr(d, "\xf0\x9f\x98\x80") != NULL, "合法 emoji 不该被改动: %s",
|
||||
d);
|
||||
CHECK(strstr(d, "\xef\xbf\xbd") == NULL, "合法输入不该出现替换字符: %s", d);
|
||||
free(d);
|
||||
json_free(o);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int main(void) {
|
||||
test_basic();
|
||||
test_escapes();
|
||||
test_numbers();
|
||||
|
||||
Reference in new issue
Block a user