Seregon/sJson

sJson (also known as Secure JSON) is a thread-safe, dynamic-allocation-free, cross-compilable JSON parser based on a PAL (Platform Abstraction Layer) architecture writed in c99

C/251 B/No license
src/test_json.c
sJson / src / test_json.c
1#define JSON_IMPLEMENTATION
2#include "json_pal.h"
3#include <stdio.h>
4#include <string.h>
5 
6#define T(name) printf("[TEST] %-52s", name)
7#define PASS() printf("PASS\n")
8#define FAIL(m) do { printf("FAIL: %s\n", m); return 1; } while(0)
9 
10static int test_primitives(void) {
11 JsonArena* a = json_arena_create(NULL, 4096);
12 JsonError err; JsonValue* v;
13 bool b; int64_t i; double f; const char* s; uint32_t sl;
14 
15 T("null"); v=json_parse_cstr(a,"null",&err); if(!v||v->type!=JSON_NULL) FAIL("null"); PASS();
16 T("true/false"); v=json_parse_cstr(a,"true",&err); json_get_bool(v,&b); if(!b) FAIL("true");
17 v=json_parse_cstr(a,"false",&err); json_get_bool(v,&b); if(b) FAIL("false"); PASS();
18 T("integer"); v=json_parse_cstr(a,"-9223372036854775807",&err);
19 json_get_int(v,&i); if(i!=-9223372036854775807LL) FAIL("int"); PASS();
20 T("float"); v=json_parse_cstr(a,"3.14159265358979",&err);
21 json_get_float(v,&f); if(f<3.14||f>3.15) FAIL("float"); PASS();
22 T("string escapes");v=json_parse_cstr(a,"\"hello\\nworld\\t!\"",&err);
23 json_get_string(v,&s,&sl);
24 if(sl!=13||memcmp(s,"hello\nworld\t!",13)) FAIL("escape content"); PASS();
25 
26 /* Bug #2 regression: \u00e9 must be 2 bytes (C3 A9), not 3 */
27 T("\\u00e9 exact 2 bytes");
28 v=json_parse_cstr(a,"\"\\u00e9\"",&err);
29 json_get_string(v,&s,&sl);
30 if(sl!=2) FAIL("u00e9 len wrong"); PASS();
31 
32 /* \u00e9 (2 bytes) + \u4e2d (3 bytes) = 5 bytes total */
33 T("\\u00e9\\u4e2d exact 5 bytes");
34 v=json_parse_cstr(a,"\"\\u00e9\\u4e2d\"",&err);
35 json_get_string(v,&s,&sl);
36 if(sl!=5) FAIL("combined uXXXX len wrong"); PASS();
37 
38 json_arena_destroy(a);
39 return 0;
40}
41 
42static int test_objects(void) {
43 JsonArena* a = json_arena_create(NULL, 8192);
44 JsonError err; JsonValue *v, *item; int64_t iv; uint32_t len;
45 
46 /* Bug #1 regression */
47 T("simple object {\"a\":1,\"b\":2}");
48 v=json_parse_cstr(a,"{\"a\":1,\"b\":2}",&err);
49 if(!v||err!=JSON_OK) FAIL("parse failed");
50 json_obj_finalize(a,v);
51 json_obj_get(v,"a",&item); json_get_int(item,&iv); if(iv!=1) FAIL("a!=1");
52 json_obj_get(v,"b",&item); json_get_int(item,&iv); if(iv!=2) FAIL("b!=2");
53 PASS();
54 
55 T("empty object {}");
56 v=json_parse_cstr(a,"{}",&err);
57 if(!v||v->type!=JSON_OBJECT) FAIL("{}"); PASS();
58 
59 T("nested {\"users\":[{\"name\":\"Alice\"}]}");
60 v=json_parse_cstr(a,"{\"users\":[{\"name\":\"Alice\",\"age\":30}]}",&err);
61 if(!v||err!=JSON_OK) FAIL("nested parse");
62 json_obj_finalize(a,v);
63 JsonValue *users, *user0, *name_v;
64 json_obj_get(v,"users",&users);
65 json_arr_get(users,0,&user0);
66 json_obj_finalize(a,user0);
67 json_obj_get(user0,"name",&name_v);
68 const char* nm; uint32_t nl;
69 json_get_string(name_v,&nm,&nl);
70 if(nl!=5||memcmp(nm,"Alice",5)) FAIL("nested name"); PASS();
71 
72 T("array [1,2,3]"); v=json_parse_cstr(a,"[1,2,3]",&err);
73 json_get_arr_len(v,&len); if(len!=3) FAIL("arr len");
74 json_arr_get(v,2,&item); json_get_int(item,&iv); if(iv!=3) FAIL("arr[2]"); PASS();
75 
76 json_arena_destroy(a);
77 return 0;
78}
79 
80static int test_path(void) {
81 JsonArena* a = json_arena_create(NULL, 8192);
82 JsonError err; JsonValue *root, *v; int64_t iv;
83 
84 root=json_parse_cstr(a,"{\"config\":{\"host\":\"localhost\",\"port\":8080},\"data\":[10,20,30]}",&err);
85 if(!root){printf("[TEST] path query setup FAIL: parse\n"); return 1;}
86 json_obj_finalize(a,root);
87 JsonValue* cfg; json_obj_get(root,"config",&cfg); json_obj_finalize(a,cfg);
88 
89 T("path data[2]"); v=json_path(root,"data[2]",&err);
90 json_get_int(v,&iv); if(iv!=30) FAIL("data[2]"); PASS();
91 T("path config.port");v=json_path(root,"config.port",&err);
92 json_get_int(v,&iv); if(iv!=8080) FAIL("port"); PASS();
93 T("path config[\"host\"]");
94 v=json_path(root,"config[\"host\"]",&err);
95 const char* s; uint32_t sl;
96 json_get_string(v,&s,&sl);
97 if(sl!=9||memcmp(s,"localhost",9)) FAIL("host"); PASS();
98 
99 json_arena_destroy(a);
100 return 0;
101}
102 
103static int test_serialize(void) {
104 JsonArena* a = json_arena_create(NULL, 8192);
105 JsonError err; JsonValue* root; char buf[1024];
106 
107 T("round-trip {x,y,z}");
108 root=json_parse_cstr(a,"{\"x\":42,\"y\":[1,2,3],\"z\":true}",&err);
109 if(!root||err!=JSON_OK) FAIL("rt parse");
110 json_obj_finalize(a,root);
111 size_t written;
112 err=json_write(root,buf,sizeof(buf),&written,NULL);
113 if(err!=JSON_OK) FAIL("serialize");
114 JsonArena* a2=json_arena_create(NULL,4096);
115 JsonValue* r2=json_parse_cstr(a2,buf,&err);
116 if(!r2||err!=JSON_OK) FAIL("re-parse");
117 json_arena_destroy(a2); PASS();
118 
119 T("buffer too small returns correct error");
120 root=json_parse_cstr(a,"{\"key\":\"value\"}",&err);
121 if(!root) FAIL("parse for buf-small test");
122 char tiny[5];
123 JsonError e2=json_write(root,tiny,sizeof(tiny),NULL,NULL);
124 if(e2!=JSON_ERR_BUFFER_TOO_SMALL) FAIL("wrong error code"); PASS();
125 
126 T("pretty print"); {
127 JsonWriteOpts opts={0}; opts.pretty=true; opts.indent=2;
128 err=json_write(root,buf,sizeof(buf),&written,&opts);
129 if(err!=JSON_OK||written<5) FAIL("pretty"); } PASS();
130 
131 T("measure == write len");
132 { size_t sz=0; json_measure(root,&sz,NULL);
133 err=json_write(root,buf,sz+2,&written,NULL);
134 if(err!=JSON_OK||written!=sz) FAIL("measure"); } PASS();
135 
136 json_arena_destroy(a);
137 return 0;
138}
139 
140static int test_construction(void) {
141 JsonArena* a = json_arena_create(NULL, 16384);
142 JsonValue* arr=json_make_array(a);
143 JsonValue* obj=json_make_object(a);
144 int i; uint32_t len;
145 
146 T("build 100-element array");
147 for(i=0;i<100;i++) json_arr_push(arr,a,json_make_int(a,i));
148 json_get_arr_len(arr,&len); if(len!=100) FAIL("arr len"); PASS();
149 
150 T("build object + finalize");
151 json_obj_setz(obj,a,"pi",json_make_float(a,3.14159));
152 json_obj_setz(obj,a,"name",json_make_stringz(a,"test"));
153 json_obj_setz(obj,a,"ok",json_make_bool(a,true));
154 json_obj_finalize(a,obj);
155 JsonValue* v; if(json_obj_get(obj,"pi",&v)!=JSON_OK) FAIL("pi"); PASS();
156 
157 T("deep clone == original");
158 JsonArena* a2=json_arena_create(NULL,8192);
159 JsonValue* cl=json_clone(a2,obj);
160 if(!cl||!json_equal(obj,cl)) FAIL("clone");
161 json_arena_destroy(a2); PASS();
162 
163 json_arena_destroy(a);
164 return 0;
165}
166 
167static int test_errors(void) {
168 JsonArena* a=json_arena_create(NULL,4096);
169 JsonError err; JsonValue* v;
170 
171 T("reject {bad}"); v=json_parse_cstr(a,"{bad}",&err); if(v) FAIL("accepted bad"); PASS();
172 T("reject [01]"); v=json_parse_cstr(a,"[01]",&err); if(v) FAIL("leading zero"); PASS();
173 T("reject \\q"); v=json_parse_cstr(a,"\"\\q\"",&err); if(v) FAIL("bad escape"); PASS();
174 T("reject trailing");v=json_parse_cstr(a,"42 garbage",&err); if(v) FAIL("trailing"); PASS();
175 T("reject \\uD800");v=json_parse_cstr(a,"\"\\uD800\"",&err); if(v) FAIL("lone surr"); PASS();
176 T("type mismatch"); v=json_parse_cstr(a,"42",&err);
177 bool b; if(json_get_bool(v,&b)!=JSON_ERR_TYPE_MISMATCH) FAIL("mismatch"); PASS();
178 
179 json_arena_destroy(a);
180 return 0;
181}
182 
183static int test_introsort(void) {
184 JsonArena* a=json_arena_create(NULL,512*1024);
185 JsonValue* obj=json_make_object(a);
186 char kb[32]; int n=200, i;
187 
188 T("introsort 200 keys + binary search");
189 for(i=0;i<n;i++){
190 snprintf(kb,sizeof(kb),"key_%04d",i);
191 json_obj_setz(obj,a,kb,json_make_int(a,(int64_t)i));
192 }
193 json_obj_finalize(a,obj);
194 JsonValue* v; int64_t iv;
195 snprintf(kb,sizeof(kb),"key_%04d",99);
196 if(json_obj_get(obj,kb,&v)!=JSON_OK) FAIL("lookup 99");
197 json_get_int(v,&iv); if(iv!=99) FAIL("value 99");
198 snprintf(kb,sizeof(kb),"key_%04d",0);
199 if(json_obj_get(obj,kb,&v)!=JSON_OK) FAIL("lookup 0");
200 snprintf(kb,sizeof(kb),"key_%04d",n-1);
201 if(json_obj_get(obj,kb,&v)!=JSON_OK) FAIL("lookup last"); PASS();
202 
203 json_arena_destroy(a);
204 return 0;
205}
206 
207static int test_arena_reset(void) {
208 JsonArena* a=json_arena_create(NULL,4096);
209 JsonError err; int i;
210 
211 T("arena reset x5 reuse");
212 for(i=0;i<5;i++){
213 json_arena_reset(a);
214 JsonValue* v=json_parse_cstr(a,"[1,2,3,{\"ok\":true}]",&err);
215 if(!v||err!=JSON_OK) FAIL("reset round");
216 } PASS();
217 
218 json_arena_destroy(a);
219 return 0;
220}
221 
222int main(void) {
223 int f=0;
224 printf("=== json_pal.h v1.1 — regression suite ===\n\n");
225 f+=test_primitives();
226 f+=test_objects();
227 f+=test_path();
228 f+=test_serialize();
229 f+=test_construction();
230 f+=test_errors();
231 f+=test_introsort();
232 f+=test_arena_reset();
233 printf("\n%s — %d failure(s)\n", f?"TESTS FAILED":"ALL TESTS PASSED", f);
234 return f?1:0;
235}
236