1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
|
#include "assert.h"
#include "test.h"
#include "dged/json.h"
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
struct parsed_json {
struct json_result result;
uint8_t *buf;
};
static struct parsed_json json_parse_error(const char *msg) {
return (struct parsed_json){
.result =
(struct json_result){
.ok = false,
.result.error = msg,
},
.buf = NULL,
};
}
static struct parsed_json parse_json_file(const char *path) {
struct stat sb;
if (stat(path, &sb) != 0) {
return json_parse_error("file not found");
}
FILE *file = fopen(path, "r");
if (fseek(file, 0, SEEK_END) != 0) {
return json_parse_error("fseek to end failed");
}
long sz = ftell(file);
if (sz == -1) {
return json_parse_error("ftell failed");
}
rewind(file);
uint8_t *buff = malloc(sz);
int bytes = fread(buff, 1, sz, file);
if (bytes != sz) {
return json_parse_error("did not read whole file");
}
return (struct parsed_json){
.result = json_parse(buff, sz),
.buf = buff,
};
}
static void test_empty_parse(void) {
struct json_result res = json_parse((uint8_t *)"", 0);
ASSERT(res.ok, "Expected empty parse to work");
json_destroy(&res.result.document);
}
static void test_empty_array(void) {
struct json_result res = json_parse((uint8_t *)"[]", 2);
ASSERT(res.ok, "Expected parse of empty array to work");
struct json_value root = res.result.document;
ASSERT(root.type == Json_Array, "Expected doc root to be array");
ASSERT(json_array_len(root.value.array) == 0, "Expected array to be empty");
json_destroy(&root);
}
static void test_array(void) {
struct json_result res = json_parse((uint8_t *)"[ 1, 2, 4 ]", 11);
ASSERT(res.ok, "Expected parse of number array to work");
struct json_value root = res.result.document;
ASSERT(root.type == Json_Array, "Expected doc root to be array");
ASSERT(json_array_len(root.value.array) == 3, "Expected array len to be 3");
json_destroy(&root);
const char *jsn = "[ \"hello\", \"world\", \"\\\"\" ]";
res = json_parse((uint8_t *)jsn, strlen(jsn));
ASSERT(res.ok, "Expected parse of string array to work");
root = res.result.document;
ASSERT(root.type == Json_Array, "Expected doc root to be array");
struct json_value *second = json_array_get(root.value.array, 1);
ASSERT(second->type == Json_String, "Expected second element to be a string");
ASSERT(s8cmp(second->value.string, s8("world")) == 0,
"Expected second string to be \"world\"");
json_destroy(&root);
}
static void test_object(void) {
struct json_result res = json_parse((uint8_t *)"{ }", 3);
ASSERT(res.ok, "Expected parse of empty object to work");
struct json_value root = res.result.document;
ASSERT(root.type == Json_Object, "Expected doc root to be object");
ASSERT(json_len(root.value.object) == 0, "Expected empty object len to be 0");
json_destroy(&root);
const char *jsn = "{ \"name\": \"Kalle Kula\", \"age\": 33, \"ball\": true, "
"\"square\": false }";
res = json_parse((uint8_t *)jsn, strlen(jsn));
ASSERT(res.ok, "Expected parse of simple object to work");
root = res.result.document;
ASSERT(root.type == Json_Object, "Expected doc root to be object");
ASSERT(json_contains(root.value.object, s8("name")),
"Expected object to contain \"name\"");
struct json_value *age = json_get(root.value.object, s8("age"));
ASSERT(age->type == Json_Number, "Expected age to (just?) be a number");
ASSERT(age->value.number == 33, "Expected age to be 33");
struct json_value *ball = json_get(root.value.object, s8("ball"));
ASSERT(ball->type == Json_Bool, "Expected ball to be a boolean.");
ASSERT(ball->value.boolean, "Expected Kalle Kulla to be a ball.");
json_destroy(&root);
jsn = "{ \"name\": \"Kalle Kula\", \"age\": 33, \"kids\": "
"[ "
"{ \"name\": \"Sune Kula\", \"age\": 10, }, "
"{ \"name\": \"Suna Kula\", \"age\": 7 }, "
"], \"pet_names\": [ \"fido\", \"fado\" ], \"ball\": true }";
res = json_parse((uint8_t *)jsn, strlen(jsn));
ASSERT(res.ok, "Expected parse of nested object to work");
root = res.result.document;
ASSERT(root.type == Json_Object, "Expected doc root to be object");
ASSERT(json_contains(root.value.object, s8("kids")),
"Expected json object to contain array of kids");
struct json_value *kids = json_get(root.value.object, s8("kids"));
ASSERT(kids->type == Json_Array, "Expected kids to be array");
ball = json_get(root.value.object, s8("ball"));
ASSERT(ball->type == Json_Bool, "Expected ball to be a boolean.");
ASSERT(ball->value.boolean, "Expected Kalle Kulla to be a ball.");
json_destroy(&root);
}
#define xstr(s) str(s)
#define str(s) #s
#define test_parse_file(path) \
{ \
struct parsed_json parsed = parse_json_file(xstr(TEST_ROOT) "/" path); \
ASSERT(parsed.result.ok, "Expected parsing of " #path " to work: %s", \
parsed.result.result.error); \
json_destroy(&parsed.result.result.document); \
free(parsed.buf); \
}
static void test_files(void) { test_parse_file("json/diag.json"); }
static void test_brackets_in_strings(void) {
struct parsed_json parsed =
parse_json_file(xstr(TEST_ROOT) "/json/diag2.json");
ASSERT(parsed.result.ok, "Expected parsing of diag2.json to work");
struct json_value *params =
json_get(parsed.result.result.document.value.object, s8("params"));
ASSERT(params != NULL, "Expected JSON object to contain params");
ASSERT(params->type == Json_Object, "Expected params to be a JSON object");
struct json_value *diagnostics =
json_get(params->value.object, s8("diagnostics"));
ASSERT(diagnostics != NULL, "Expected params to contain diagnostics");
ASSERT(diagnostics->type == Json_Array, "Expected params to be a JSON array");
struct json_array *diags = diagnostics->value.array;
ASSERT(json_array_len(diags) == 5,
"Expected diagnostics array to contain five items");
json_destroy(&parsed.result.result.document);
free(parsed.buf);
}
static void test_str_escape(void) {
struct s8 res = unescape_json_string(s8("a\n\\n\r\\rb"));
ASSERT(s8eq(res, s8("a\n\n\r\rb")), "Expected \\n and \\r to not be removed");
s8delete(res);
struct s8 res2 = unescape_json_string(s8(" \\\\\\n"));
ASSERT(s8eq(res2, s8(" \\\n")), "Expected \\ and \\n to not be removed");
s8delete(res2);
}
void run_json_tests(void) {
run_test(test_empty_parse);
run_test(test_empty_array);
run_test(test_array);
run_test(test_object);
run_test(test_files);
run_test(test_brackets_in_strings);
run_test(test_str_escape);
}
|