1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 5 #include "jsmn.c" 6 7 static int test_passed = 0; 8 static int test_failed = 0; 9 10 /* Terminate current test with error */ 11 #define fail() return __LINE__ 12 13 /* Successfull end of the test case */ 14 #define done() return 0 15 16 /* Check single condition */ 17 #define check(cond) do { if (!(cond)) fail(); } while (0) 18 19 /* Test runner */ 20 static void test(int (*func)(void), const char *name) { 21 int r = func(); 22 if (r == 0) { 23 test_passed++; 24 } else { 25 test_failed++; 26 printf("FAILED: %s (at line %d)\n", name, r); 27 } 28 } 29 30 #define TOKEN_EQ(t, tok_start, tok_end, tok_type) \ 31 ((t).start == tok_start \ 32 && (t).end == tok_end \ 33 && (t).type == (tok_type)) 34 35 #define TOKEN_STRING(js, t, s) \ 36 (strncmp(js+(t).start, s, (t).end - (t).start) == 0 \ 37 && strlen(s) == (t).end - (t).start) 38 39 #define TOKEN_PRINT(t) \ 40 printf("start: %d, end: %d, type: %d, size: %d\n", \ 41 (t).start, (t).end, (t).type, (t).size) 42 43 int test_empty() { 44 const char *js; 45 int r; 46 jsmn_parser p; 47 jsmntok_t t[10]; 48 49 js = "{}"; 50 jsmn_init(&p); 51 r = jsmn_parse(&p, js, t, 10); 52 check(r == JSMN_SUCCESS); 53 check(t[0].type == JSMN_OBJECT); 54 check(t[0].start == 0 && t[0].end == 2); 55 56 js = "[]"; 57 jsmn_init(&p); 58 r = jsmn_parse(&p, js, t, 10); 59 check(r == JSMN_SUCCESS); 60 check(t[0].type == JSMN_ARRAY); 61 check(t[0].start == 0 && t[0].end == 2); 62 63 js = "{\"a\":[]}"; 64 jsmn_init(&p); 65 r = jsmn_parse(&p, js, t, 10); 66 check(r == JSMN_SUCCESS); 67 check(t[0].type == JSMN_OBJECT && t[0].start == 0 && t[0].end == 8); 68 check(t[1].type == JSMN_STRING && t[1].start == 2 && t[1].end == 3); 69 check(t[2].type == JSMN_ARRAY && t[2].start == 5 && t[2].end == 7); 70 71 js = "[{},{}]"; 72 jsmn_init(&p); 73 r = jsmn_parse(&p, js, t, 10); 74 check(r == JSMN_SUCCESS); 75 check(t[0].type == JSMN_ARRAY && t[0].start == 0 && t[0].end == 7); 76 check(t[1].type == JSMN_OBJECT && t[1].start == 1 && t[1].end == 3); 77 check(t[2].type == JSMN_OBJECT && t[2].start == 4 && t[2].end == 6); 78 return 0; 79 } 80 81 int test_simple() { 82 const char *js; 83 int r; 84 jsmn_parser p; 85 jsmntok_t tokens[10]; 86 87 js = "{\"a\": 0}"; 88 89 jsmn_init(&p); 90 r = jsmn_parse(&p, js, tokens, 10); 91 check(r == JSMN_SUCCESS); 92 check(TOKEN_EQ(tokens[0], 0, 8, JSMN_OBJECT)); 93 check(TOKEN_EQ(tokens[1], 2, 3, JSMN_STRING)); 94 check(TOKEN_EQ(tokens[2], 6, 7, JSMN_PRIMITIVE)); 95 96 check(TOKEN_STRING(js, tokens[0], js)); 97 check(TOKEN_STRING(js, tokens[1], "a")); 98 check(TOKEN_STRING(js, tokens[2], "0")); 99 100 jsmn_init(&p); 101 js = "[\"a\":{},\"b\":{}]"; 102 r = jsmn_parse(&p, js, tokens, 10); 103 check(r == JSMN_SUCCESS); 104 105 jsmn_init(&p); 106 js = "{\n \"Day\": 26,\n \"Month\": 9,\n \"Year\": 12\n }"; 107 r = jsmn_parse(&p, js, tokens, 10); 108 check(r == JSMN_SUCCESS); 109 110 return 0; 111 } 112 113 int test_primitive() { 114 int r; 115 jsmn_parser p; 116 jsmntok_t tok[10]; 117 const char *js; 118 #ifndef JSMN_STRICT 119 js = "\"boolVar\" : true"; 120 jsmn_init(&p); 121 r = jsmn_parse(&p, js, tok, 10); 122 check(r == JSMN_SUCCESS && tok[0].type == JSMN_STRING 123 && tok[1].type == JSMN_PRIMITIVE); 124 check(TOKEN_STRING(js, tok[0], "boolVar")); 125 check(TOKEN_STRING(js, tok[1], "true")); 126 127 js = "\"boolVar\" : false"; 128 jsmn_init(&p); 129 r = jsmn_parse(&p, js, tok, 10); 130 check(r == JSMN_SUCCESS && tok[0].type == JSMN_STRING 131 && tok[1].type == JSMN_PRIMITIVE); 132 check(TOKEN_STRING(js, tok[0], "boolVar")); 133 check(TOKEN_STRING(js, tok[1], "false")); 134 135 js = "\"intVar\" : 12345"; 136 jsmn_init(&p); 137 r = jsmn_parse(&p, js, tok, 10); 138 check(r == JSMN_SUCCESS && tok[0].type == JSMN_STRING 139 && tok[1].type == JSMN_PRIMITIVE); 140 check(TOKEN_STRING(js, tok[0], "intVar")); 141 check(TOKEN_STRING(js, tok[1], "12345")); 142 143 js = "\"floatVar\" : 12.345"; 144 jsmn_init(&p); 145 r = jsmn_parse(&p, js, tok, 10); 146 check(r == JSMN_SUCCESS && tok[0].type == JSMN_STRING 147 && tok[1].type == JSMN_PRIMITIVE); 148 check(TOKEN_STRING(js, tok[0], "floatVar")); 149 check(TOKEN_STRING(js, tok[1], "12.345")); 150 151 js = "\"nullVar\" : null"; 152 jsmn_init(&p); 153 r = jsmn_parse(&p, js, tok, 10); 154 check(r == JSMN_SUCCESS && tok[0].type == JSMN_STRING 155 && tok[1].type == JSMN_PRIMITIVE); 156 check(TOKEN_STRING(js, tok[0], "nullVar")); 157 check(TOKEN_STRING(js, tok[1], "null")); 158 #endif 159 return 0; 160 } 161 162 int test_string() { 163 int r; 164 jsmn_parser p; 165 jsmntok_t tok[10]; 166 const char *js; 167 168 js = "\"strVar\" : \"hello world\""; 169 jsmn_init(&p); 170 r = jsmn_parse(&p, js, tok, 10); 171 check(r == JSMN_SUCCESS && tok[0].type == JSMN_STRING 172 && tok[1].type == JSMN_STRING); 173 check(TOKEN_STRING(js, tok[0], "strVar")); 174 check(TOKEN_STRING(js, tok[1], "hello world")); 175 176 js = "\"strVar\" : \"escapes: \\/\\r\\n\\t\\b\\f\\\"\\\\\""; 177 jsmn_init(&p); 178 r = jsmn_parse(&p, js, tok, 10); 179 check(r == JSMN_SUCCESS && tok[0].type == JSMN_STRING 180 && tok[1].type == JSMN_STRING); 181 check(TOKEN_STRING(js, tok[0], "strVar")); 182 check(TOKEN_STRING(js, tok[1], "escapes: \\/\\r\\n\\t\\b\\f\\\"\\\\")); 183 184 js = "\"strVar\" : \"\""; 185 jsmn_init(&p); 186 r = jsmn_parse(&p, js, tok, 10); 187 check(r == JSMN_SUCCESS && tok[0].type == JSMN_STRING 188 && tok[1].type == JSMN_STRING); 189 check(TOKEN_STRING(js, tok[0], "strVar")); 190 check(TOKEN_STRING(js, tok[1], "")); 191 192 return 0; 193 } 194 195 int test_partial_string() { 196 int r; 197 jsmn_parser p; 198 jsmntok_t tok[10]; 199 const char *js; 200 201 jsmn_init(&p); 202 js = "\"x\": \"va"; 203 r = jsmn_parse(&p, js, tok, 10); 204 check(r == JSMN_ERROR_PART && tok[0].type == JSMN_STRING); 205 check(TOKEN_STRING(js, tok[0], "x")); 206 check(p.toknext == 1); 207 208 js = "\"x\": \"valu"; 209 r = jsmn_parse(&p, js, tok, 10); 210 check(r == JSMN_ERROR_PART && tok[0].type == JSMN_STRING); 211 check(TOKEN_STRING(js, tok[0], "x")); 212 check(p.toknext == 1); 213 214 js = "\"x\": \"value\""; 215 r = jsmn_parse(&p, js, tok, 10); 216 check(r == JSMN_SUCCESS && tok[0].type == JSMN_STRING 217 && tok[1].type == JSMN_STRING); 218 check(TOKEN_STRING(js, tok[0], "x")); 219 check(TOKEN_STRING(js, tok[1], "value")); 220 221 js = "\"x\": \"value\", \"y\": \"value y\""; 222 r = jsmn_parse(&p, js, tok, 10); 223 check(r == JSMN_SUCCESS && tok[0].type == JSMN_STRING 224 && tok[1].type == JSMN_STRING && tok[2].type == JSMN_STRING 225 && tok[3].type == JSMN_STRING); 226 check(TOKEN_STRING(js, tok[0], "x")); 227 check(TOKEN_STRING(js, tok[1], "value")); 228 check(TOKEN_STRING(js, tok[2], "y")); 229 check(TOKEN_STRING(js, tok[3], "value y")); 230 231 return 0; 232 } 233 234 int test_unquoted_keys() { 235 #ifndef JSMN_STRICT 236 int r; 237 jsmn_parser p; 238 jsmntok_t tok[10]; 239 const char *js; 240 241 jsmn_init(&p); 242 js = "key1: \"value\"\nkey2 : 123"; 243 244 r = jsmn_parse(&p, js, tok, 10); 245 check(r == JSMN_SUCCESS && tok[0].type == JSMN_PRIMITIVE 246 && tok[1].type == JSMN_STRING && tok[2].type == JSMN_PRIMITIVE 247 && tok[3].type == JSMN_PRIMITIVE); 248 check(TOKEN_STRING(js, tok[0], "key1")); 249 check(TOKEN_STRING(js, tok[1], "value")); 250 check(TOKEN_STRING(js, tok[2], "key2")); 251 check(TOKEN_STRING(js, tok[3], "123")); 252 #endif 253 return 0; 254 } 255 256 int test_partial_array() { 257 int r; 258 jsmn_parser p; 259 jsmntok_t tok[10]; 260 const char *js; 261 262 jsmn_init(&p); 263 js = " [ 1, true, "; 264 r = jsmn_parse(&p, js, tok, 10); 265 check(r == JSMN_ERROR_PART && tok[0].type == JSMN_ARRAY 266 && tok[1].type == JSMN_PRIMITIVE && tok[2].type == JSMN_PRIMITIVE); 267 268 js = " [ 1, true, [123, \"hello"; 269 r = jsmn_parse(&p, js, tok, 10); 270 check(r == JSMN_ERROR_PART && tok[0].type == JSMN_ARRAY 271 && tok[1].type == JSMN_PRIMITIVE && tok[2].type == JSMN_PRIMITIVE 272 && tok[3].type == JSMN_ARRAY && tok[4].type == JSMN_PRIMITIVE); 273 274 js = " [ 1, true, [123, \"hello\"]"; 275 r = jsmn_parse(&p, js, tok, 10); 276 check(r == JSMN_ERROR_PART && tok[0].type == JSMN_ARRAY 277 && tok[1].type == JSMN_PRIMITIVE && tok[2].type == JSMN_PRIMITIVE 278 && tok[3].type == JSMN_ARRAY && tok[4].type == JSMN_PRIMITIVE 279 && tok[5].type == JSMN_STRING); 280 /* check child nodes of the 2nd array */ 281 check(tok[3].size == 2); 282 283 js = " [ 1, true, [123, \"hello\"]]"; 284 r = jsmn_parse(&p, js, tok, 10); 285 check(r == JSMN_SUCCESS && tok[0].type == JSMN_ARRAY 286 && tok[1].type == JSMN_PRIMITIVE && tok[2].type == JSMN_PRIMITIVE 287 && tok[3].type == JSMN_ARRAY && tok[4].type == JSMN_PRIMITIVE 288 && tok[5].type == JSMN_STRING); 289 check(tok[3].size == 2); 290 check(tok[0].size == 3); 291 return 0; 292 } 293 294 int test_array_nomem() { 295 int i; 296 int r; 297 jsmn_parser p; 298 jsmntok_t toksmall[10], toklarge[10]; 299 const char *js; 300 301 js = " [ 1, true, [123, \"hello\"]]"; 302 303 for (i = 0; i < 6; i++) { 304 jsmn_init(&p); 305 memset(toksmall, 0, sizeof(toksmall)); 306 memset(toklarge, 0, sizeof(toklarge)); 307 r = jsmn_parse(&p, js, toksmall, i); 308 check(r == JSMN_ERROR_NOMEM); 309 310 memcpy(toklarge, toksmall, sizeof(toksmall)); 311 312 r = jsmn_parse(&p, js, toklarge, 10); 313 check(r == JSMN_SUCCESS); 314 315 check(toklarge[0].type == JSMN_ARRAY && toklarge[0].size == 3); 316 check(toklarge[3].type == JSMN_ARRAY && toklarge[3].size == 2); 317 } 318 return 0; 319 } 320 321 int test_objects_arrays() { 322 int i; 323 int r; 324 jsmn_parser p; 325 jsmntok_t tokens[10]; 326 const char *js; 327 328 js = "[10}"; 329 jsmn_init(&p); 330 r = jsmn_parse(&p, js, tokens, 10); 331 check(r == JSMN_ERROR_INVAL); 332 333 js = "[10]"; 334 jsmn_init(&p); 335 r = jsmn_parse(&p, js, tokens, 10); 336 check(r == JSMN_SUCCESS); 337 338 js = "{\"a\": 1]"; 339 jsmn_init(&p); 340 r = jsmn_parse(&p, js, tokens, 10); 341 check(r == JSMN_ERROR_INVAL); 342 343 js = "{\"a\": 1}"; 344 jsmn_init(&p); 345 r = jsmn_parse(&p, js, tokens, 10); 346 check(r == JSMN_SUCCESS); 347 348 return 0; 349 } 350 351 int test_unicode_characters() { 352 jsmn_parser p; 353 jsmntok_t tokens[10]; 354 const char *js; 355 356 int r; 357 js = "{\"a\":\"\\uAbcD\"}"; 358 jsmn_init(&p); 359 r = jsmn_parse(&p, js, tokens, 10); 360 check(r == JSMN_SUCCESS); 361 362 js = "{\"a\":\"str\\u0000\"}"; 363 jsmn_init(&p); 364 r = jsmn_parse(&p, js, tokens, 10); 365 check(r == JSMN_SUCCESS); 366 367 js = "{\"a\":\"\\uFFFFstr\"}"; 368 jsmn_init(&p); 369 r = jsmn_parse(&p, js, tokens, 10); 370 check(r == JSMN_SUCCESS); 371 372 js = "{\"a\":\"str\\uFFGFstr\"}"; 373 jsmn_init(&p); 374 r = jsmn_parse(&p, js, tokens, 10); 375 check(r == JSMN_ERROR_INVAL); 376 377 js = "{\"a\":\"str\\u@FfF\"}"; 378 jsmn_init(&p); 379 r = jsmn_parse(&p, js, tokens, 10); 380 check(r == JSMN_ERROR_INVAL); 381 382 js = "{\"a\":[\"\\u028\"]}"; 383 jsmn_init(&p); 384 r = jsmn_parse(&p, js, tokens, 10); 385 check(r == JSMN_ERROR_INVAL); 386 387 js = "{\"a\":[\"\\u0280\"]}"; 388 jsmn_init(&p); 389 r = jsmn_parse(&p, js, tokens, 10); 390 check(r == JSMN_SUCCESS); 391 392 return 0; 393 } 394 395 int main() { 396 test(test_empty, "general test for a empty JSON objects/arrays"); 397 test(test_simple, "general test for a simple JSON string"); 398 test(test_primitive, "test primitive JSON data types"); 399 test(test_string, "test string JSON data types"); 400 test(test_partial_string, "test partial JSON string parsing"); 401 test(test_partial_array, "test partial array reading"); 402 test(test_array_nomem, "test array reading with a smaller number of tokens"); 403 test(test_unquoted_keys, "test unquoted keys (like in JavaScript)"); 404 test(test_objects_arrays, "test objects and arrays"); 405 test(test_unicode_characters, "test unicode characters"); 406 printf("\nPASSED: %d\nFAILED: %d\n", test_passed, test_failed); 407 return 0; 408 } 409 410