jsmn_test.c revision 275970
1275970Scy#include <stdio.h> 2275970Scy#include <stdlib.h> 3275970Scy#include <string.h> 4275970Scy 5275970Scy#include "jsmn.c" 6275970Scy 7275970Scystatic int test_passed = 0; 8275970Scystatic int test_failed = 0; 9275970Scy 10275970Scy/* Terminate current test with error */ 11275970Scy#define fail() return __LINE__ 12275970Scy 13275970Scy/* Successfull end of the test case */ 14275970Scy#define done() return 0 15275970Scy 16275970Scy/* Check single condition */ 17275970Scy#define check(cond) do { if (!(cond)) fail(); } while (0) 18275970Scy 19275970Scy/* Test runner */ 20275970Scystatic void test(int (*func)(void), const char *name) { 21275970Scy int r = func(); 22275970Scy if (r == 0) { 23275970Scy test_passed++; 24275970Scy } else { 25275970Scy test_failed++; 26275970Scy printf("FAILED: %s (at line %d)\n", name, r); 27275970Scy } 28275970Scy} 29275970Scy 30275970Scy#define TOKEN_EQ(t, tok_start, tok_end, tok_type) \ 31275970Scy ((t).start == tok_start \ 32275970Scy && (t).end == tok_end \ 33275970Scy && (t).type == (tok_type)) 34275970Scy 35275970Scy#define TOKEN_STRING(js, t, s) \ 36275970Scy (strncmp(js+(t).start, s, (t).end - (t).start) == 0 \ 37275970Scy && strlen(s) == (t).end - (t).start) 38275970Scy 39275970Scy#define TOKEN_PRINT(t) \ 40275970Scy printf("start: %d, end: %d, type: %d, size: %d\n", \ 41275970Scy (t).start, (t).end, (t).type, (t).size) 42275970Scy 43275970Scyint test_empty() { 44275970Scy const char *js; 45275970Scy int r; 46275970Scy jsmn_parser p; 47275970Scy jsmntok_t t[10]; 48275970Scy 49275970Scy js = "{}"; 50275970Scy jsmn_init(&p); 51275970Scy r = jsmn_parse(&p, js, t, 10); 52275970Scy check(r == JSMN_SUCCESS); 53275970Scy check(t[0].type == JSMN_OBJECT); 54275970Scy check(t[0].start == 0 && t[0].end == 2); 55275970Scy 56275970Scy js = "[]"; 57275970Scy jsmn_init(&p); 58275970Scy r = jsmn_parse(&p, js, t, 10); 59275970Scy check(r == JSMN_SUCCESS); 60275970Scy check(t[0].type == JSMN_ARRAY); 61275970Scy check(t[0].start == 0 && t[0].end == 2); 62275970Scy 63275970Scy js = "{\"a\":[]}"; 64275970Scy jsmn_init(&p); 65275970Scy r = jsmn_parse(&p, js, t, 10); 66275970Scy check(r == JSMN_SUCCESS); 67275970Scy check(t[0].type == JSMN_OBJECT && t[0].start == 0 && t[0].end == 8); 68275970Scy check(t[1].type == JSMN_STRING && t[1].start == 2 && t[1].end == 3); 69275970Scy check(t[2].type == JSMN_ARRAY && t[2].start == 5 && t[2].end == 7); 70275970Scy 71275970Scy js = "[{},{}]"; 72275970Scy jsmn_init(&p); 73275970Scy r = jsmn_parse(&p, js, t, 10); 74275970Scy check(r == JSMN_SUCCESS); 75275970Scy check(t[0].type == JSMN_ARRAY && t[0].start == 0 && t[0].end == 7); 76275970Scy check(t[1].type == JSMN_OBJECT && t[1].start == 1 && t[1].end == 3); 77275970Scy check(t[2].type == JSMN_OBJECT && t[2].start == 4 && t[2].end == 6); 78275970Scy return 0; 79275970Scy} 80275970Scy 81275970Scyint test_simple() { 82275970Scy const char *js; 83275970Scy int r; 84275970Scy jsmn_parser p; 85275970Scy jsmntok_t tokens[10]; 86275970Scy 87275970Scy js = "{\"a\": 0}"; 88275970Scy 89275970Scy jsmn_init(&p); 90275970Scy r = jsmn_parse(&p, js, tokens, 10); 91275970Scy check(r == JSMN_SUCCESS); 92275970Scy check(TOKEN_EQ(tokens[0], 0, 8, JSMN_OBJECT)); 93275970Scy check(TOKEN_EQ(tokens[1], 2, 3, JSMN_STRING)); 94275970Scy check(TOKEN_EQ(tokens[2], 6, 7, JSMN_PRIMITIVE)); 95275970Scy 96275970Scy check(TOKEN_STRING(js, tokens[0], js)); 97275970Scy check(TOKEN_STRING(js, tokens[1], "a")); 98275970Scy check(TOKEN_STRING(js, tokens[2], "0")); 99275970Scy 100275970Scy jsmn_init(&p); 101275970Scy js = "[\"a\":{},\"b\":{}]"; 102275970Scy r = jsmn_parse(&p, js, tokens, 10); 103275970Scy check(r == JSMN_SUCCESS); 104275970Scy 105275970Scy jsmn_init(&p); 106275970Scy js = "{\n \"Day\": 26,\n \"Month\": 9,\n \"Year\": 12\n }"; 107275970Scy r = jsmn_parse(&p, js, tokens, 10); 108275970Scy check(r == JSMN_SUCCESS); 109275970Scy 110275970Scy return 0; 111275970Scy} 112275970Scy 113275970Scyint test_primitive() { 114275970Scy int r; 115275970Scy jsmn_parser p; 116275970Scy jsmntok_t tok[10]; 117275970Scy const char *js; 118275970Scy#ifndef JSMN_STRICT 119275970Scy js = "\"boolVar\" : true"; 120275970Scy jsmn_init(&p); 121275970Scy r = jsmn_parse(&p, js, tok, 10); 122275970Scy check(r == JSMN_SUCCESS && tok[0].type == JSMN_STRING 123275970Scy && tok[1].type == JSMN_PRIMITIVE); 124275970Scy check(TOKEN_STRING(js, tok[0], "boolVar")); 125275970Scy check(TOKEN_STRING(js, tok[1], "true")); 126275970Scy 127275970Scy js = "\"boolVar\" : false"; 128275970Scy jsmn_init(&p); 129275970Scy r = jsmn_parse(&p, js, tok, 10); 130275970Scy check(r == JSMN_SUCCESS && tok[0].type == JSMN_STRING 131275970Scy && tok[1].type == JSMN_PRIMITIVE); 132275970Scy check(TOKEN_STRING(js, tok[0], "boolVar")); 133275970Scy check(TOKEN_STRING(js, tok[1], "false")); 134275970Scy 135275970Scy js = "\"intVar\" : 12345"; 136275970Scy jsmn_init(&p); 137275970Scy r = jsmn_parse(&p, js, tok, 10); 138275970Scy check(r == JSMN_SUCCESS && tok[0].type == JSMN_STRING 139275970Scy && tok[1].type == JSMN_PRIMITIVE); 140275970Scy check(TOKEN_STRING(js, tok[0], "intVar")); 141275970Scy check(TOKEN_STRING(js, tok[1], "12345")); 142275970Scy 143275970Scy js = "\"floatVar\" : 12.345"; 144275970Scy jsmn_init(&p); 145275970Scy r = jsmn_parse(&p, js, tok, 10); 146275970Scy check(r == JSMN_SUCCESS && tok[0].type == JSMN_STRING 147275970Scy && tok[1].type == JSMN_PRIMITIVE); 148275970Scy check(TOKEN_STRING(js, tok[0], "floatVar")); 149275970Scy check(TOKEN_STRING(js, tok[1], "12.345")); 150275970Scy 151275970Scy js = "\"nullVar\" : null"; 152275970Scy jsmn_init(&p); 153275970Scy r = jsmn_parse(&p, js, tok, 10); 154275970Scy check(r == JSMN_SUCCESS && tok[0].type == JSMN_STRING 155275970Scy && tok[1].type == JSMN_PRIMITIVE); 156275970Scy check(TOKEN_STRING(js, tok[0], "nullVar")); 157275970Scy check(TOKEN_STRING(js, tok[1], "null")); 158275970Scy#endif 159275970Scy return 0; 160275970Scy} 161275970Scy 162275970Scyint test_string() { 163275970Scy int r; 164275970Scy jsmn_parser p; 165275970Scy jsmntok_t tok[10]; 166275970Scy const char *js; 167275970Scy 168275970Scy js = "\"strVar\" : \"hello world\""; 169275970Scy jsmn_init(&p); 170275970Scy r = jsmn_parse(&p, js, tok, 10); 171275970Scy check(r == JSMN_SUCCESS && tok[0].type == JSMN_STRING 172275970Scy && tok[1].type == JSMN_STRING); 173275970Scy check(TOKEN_STRING(js, tok[0], "strVar")); 174275970Scy check(TOKEN_STRING(js, tok[1], "hello world")); 175275970Scy 176275970Scy js = "\"strVar\" : \"escapes: \\/\\r\\n\\t\\b\\f\\\"\\\\\""; 177275970Scy jsmn_init(&p); 178275970Scy r = jsmn_parse(&p, js, tok, 10); 179275970Scy check(r == JSMN_SUCCESS && tok[0].type == JSMN_STRING 180275970Scy && tok[1].type == JSMN_STRING); 181275970Scy check(TOKEN_STRING(js, tok[0], "strVar")); 182275970Scy check(TOKEN_STRING(js, tok[1], "escapes: \\/\\r\\n\\t\\b\\f\\\"\\\\")); 183275970Scy 184275970Scy js = "\"strVar\" : \"\""; 185275970Scy jsmn_init(&p); 186275970Scy r = jsmn_parse(&p, js, tok, 10); 187275970Scy check(r == JSMN_SUCCESS && tok[0].type == JSMN_STRING 188275970Scy && tok[1].type == JSMN_STRING); 189275970Scy check(TOKEN_STRING(js, tok[0], "strVar")); 190275970Scy check(TOKEN_STRING(js, tok[1], "")); 191275970Scy 192275970Scy return 0; 193275970Scy} 194275970Scy 195275970Scyint test_partial_string() { 196275970Scy int r; 197275970Scy jsmn_parser p; 198275970Scy jsmntok_t tok[10]; 199275970Scy const char *js; 200275970Scy 201275970Scy jsmn_init(&p); 202275970Scy js = "\"x\": \"va"; 203275970Scy r = jsmn_parse(&p, js, tok, 10); 204275970Scy check(r == JSMN_ERROR_PART && tok[0].type == JSMN_STRING); 205275970Scy check(TOKEN_STRING(js, tok[0], "x")); 206275970Scy check(p.toknext == 1); 207275970Scy 208275970Scy js = "\"x\": \"valu"; 209275970Scy r = jsmn_parse(&p, js, tok, 10); 210275970Scy check(r == JSMN_ERROR_PART && tok[0].type == JSMN_STRING); 211275970Scy check(TOKEN_STRING(js, tok[0], "x")); 212275970Scy check(p.toknext == 1); 213275970Scy 214275970Scy js = "\"x\": \"value\""; 215275970Scy r = jsmn_parse(&p, js, tok, 10); 216275970Scy check(r == JSMN_SUCCESS && tok[0].type == JSMN_STRING 217275970Scy && tok[1].type == JSMN_STRING); 218275970Scy check(TOKEN_STRING(js, tok[0], "x")); 219275970Scy check(TOKEN_STRING(js, tok[1], "value")); 220275970Scy 221275970Scy js = "\"x\": \"value\", \"y\": \"value y\""; 222275970Scy r = jsmn_parse(&p, js, tok, 10); 223275970Scy check(r == JSMN_SUCCESS && tok[0].type == JSMN_STRING 224275970Scy && tok[1].type == JSMN_STRING && tok[2].type == JSMN_STRING 225275970Scy && tok[3].type == JSMN_STRING); 226275970Scy check(TOKEN_STRING(js, tok[0], "x")); 227275970Scy check(TOKEN_STRING(js, tok[1], "value")); 228275970Scy check(TOKEN_STRING(js, tok[2], "y")); 229275970Scy check(TOKEN_STRING(js, tok[3], "value y")); 230275970Scy 231275970Scy return 0; 232275970Scy} 233275970Scy 234275970Scyint test_unquoted_keys() { 235275970Scy#ifndef JSMN_STRICT 236275970Scy int r; 237275970Scy jsmn_parser p; 238275970Scy jsmntok_t tok[10]; 239275970Scy const char *js; 240275970Scy 241275970Scy jsmn_init(&p); 242275970Scy js = "key1: \"value\"\nkey2 : 123"; 243275970Scy 244275970Scy r = jsmn_parse(&p, js, tok, 10); 245275970Scy check(r == JSMN_SUCCESS && tok[0].type == JSMN_PRIMITIVE 246275970Scy && tok[1].type == JSMN_STRING && tok[2].type == JSMN_PRIMITIVE 247275970Scy && tok[3].type == JSMN_PRIMITIVE); 248275970Scy check(TOKEN_STRING(js, tok[0], "key1")); 249275970Scy check(TOKEN_STRING(js, tok[1], "value")); 250275970Scy check(TOKEN_STRING(js, tok[2], "key2")); 251275970Scy check(TOKEN_STRING(js, tok[3], "123")); 252275970Scy#endif 253275970Scy return 0; 254275970Scy} 255275970Scy 256275970Scyint test_partial_array() { 257275970Scy int r; 258275970Scy jsmn_parser p; 259275970Scy jsmntok_t tok[10]; 260275970Scy const char *js; 261275970Scy 262275970Scy jsmn_init(&p); 263275970Scy js = " [ 1, true, "; 264275970Scy r = jsmn_parse(&p, js, tok, 10); 265275970Scy check(r == JSMN_ERROR_PART && tok[0].type == JSMN_ARRAY 266275970Scy && tok[1].type == JSMN_PRIMITIVE && tok[2].type == JSMN_PRIMITIVE); 267275970Scy 268275970Scy js = " [ 1, true, [123, \"hello"; 269275970Scy r = jsmn_parse(&p, js, tok, 10); 270275970Scy check(r == JSMN_ERROR_PART && tok[0].type == JSMN_ARRAY 271275970Scy && tok[1].type == JSMN_PRIMITIVE && tok[2].type == JSMN_PRIMITIVE 272275970Scy && tok[3].type == JSMN_ARRAY && tok[4].type == JSMN_PRIMITIVE); 273275970Scy 274275970Scy js = " [ 1, true, [123, \"hello\"]"; 275275970Scy r = jsmn_parse(&p, js, tok, 10); 276275970Scy check(r == JSMN_ERROR_PART && tok[0].type == JSMN_ARRAY 277275970Scy && tok[1].type == JSMN_PRIMITIVE && tok[2].type == JSMN_PRIMITIVE 278275970Scy && tok[3].type == JSMN_ARRAY && tok[4].type == JSMN_PRIMITIVE 279275970Scy && tok[5].type == JSMN_STRING); 280275970Scy /* check child nodes of the 2nd array */ 281275970Scy check(tok[3].size == 2); 282275970Scy 283275970Scy js = " [ 1, true, [123, \"hello\"]]"; 284275970Scy r = jsmn_parse(&p, js, tok, 10); 285275970Scy check(r == JSMN_SUCCESS && tok[0].type == JSMN_ARRAY 286275970Scy && tok[1].type == JSMN_PRIMITIVE && tok[2].type == JSMN_PRIMITIVE 287275970Scy && tok[3].type == JSMN_ARRAY && tok[4].type == JSMN_PRIMITIVE 288275970Scy && tok[5].type == JSMN_STRING); 289275970Scy check(tok[3].size == 2); 290275970Scy check(tok[0].size == 3); 291275970Scy return 0; 292275970Scy} 293275970Scy 294275970Scyint test_array_nomem() { 295275970Scy int i; 296275970Scy int r; 297275970Scy jsmn_parser p; 298275970Scy jsmntok_t toksmall[10], toklarge[10]; 299275970Scy const char *js; 300275970Scy 301275970Scy js = " [ 1, true, [123, \"hello\"]]"; 302275970Scy 303275970Scy for (i = 0; i < 6; i++) { 304275970Scy jsmn_init(&p); 305275970Scy memset(toksmall, 0, sizeof(toksmall)); 306275970Scy memset(toklarge, 0, sizeof(toklarge)); 307275970Scy r = jsmn_parse(&p, js, toksmall, i); 308275970Scy check(r == JSMN_ERROR_NOMEM); 309275970Scy 310275970Scy memcpy(toklarge, toksmall, sizeof(toksmall)); 311275970Scy 312275970Scy r = jsmn_parse(&p, js, toklarge, 10); 313275970Scy check(r == JSMN_SUCCESS); 314275970Scy 315275970Scy check(toklarge[0].type == JSMN_ARRAY && toklarge[0].size == 3); 316275970Scy check(toklarge[3].type == JSMN_ARRAY && toklarge[3].size == 2); 317275970Scy } 318275970Scy return 0; 319275970Scy} 320275970Scy 321275970Scyint test_objects_arrays() { 322275970Scy int i; 323275970Scy int r; 324275970Scy jsmn_parser p; 325275970Scy jsmntok_t tokens[10]; 326275970Scy const char *js; 327275970Scy 328275970Scy js = "[10}"; 329275970Scy jsmn_init(&p); 330275970Scy r = jsmn_parse(&p, js, tokens, 10); 331275970Scy check(r == JSMN_ERROR_INVAL); 332275970Scy 333275970Scy js = "[10]"; 334275970Scy jsmn_init(&p); 335275970Scy r = jsmn_parse(&p, js, tokens, 10); 336275970Scy check(r == JSMN_SUCCESS); 337275970Scy 338275970Scy js = "{\"a\": 1]"; 339275970Scy jsmn_init(&p); 340275970Scy r = jsmn_parse(&p, js, tokens, 10); 341275970Scy check(r == JSMN_ERROR_INVAL); 342275970Scy 343275970Scy js = "{\"a\": 1}"; 344275970Scy jsmn_init(&p); 345275970Scy r = jsmn_parse(&p, js, tokens, 10); 346275970Scy check(r == JSMN_SUCCESS); 347275970Scy 348275970Scy return 0; 349275970Scy} 350275970Scy 351275970Scyint test_unicode_characters() { 352275970Scy jsmn_parser p; 353275970Scy jsmntok_t tokens[10]; 354275970Scy const char *js; 355275970Scy 356275970Scy int r; 357275970Scy js = "{\"a\":\"\\uAbcD\"}"; 358275970Scy jsmn_init(&p); 359275970Scy r = jsmn_parse(&p, js, tokens, 10); 360275970Scy check(r == JSMN_SUCCESS); 361275970Scy 362275970Scy js = "{\"a\":\"str\\u0000\"}"; 363275970Scy jsmn_init(&p); 364275970Scy r = jsmn_parse(&p, js, tokens, 10); 365275970Scy check(r == JSMN_SUCCESS); 366275970Scy 367275970Scy js = "{\"a\":\"\\uFFFFstr\"}"; 368275970Scy jsmn_init(&p); 369275970Scy r = jsmn_parse(&p, js, tokens, 10); 370275970Scy check(r == JSMN_SUCCESS); 371275970Scy 372275970Scy js = "{\"a\":\"str\\uFFGFstr\"}"; 373275970Scy jsmn_init(&p); 374275970Scy r = jsmn_parse(&p, js, tokens, 10); 375275970Scy check(r == JSMN_ERROR_INVAL); 376275970Scy 377275970Scy js = "{\"a\":\"str\\u@FfF\"}"; 378275970Scy jsmn_init(&p); 379275970Scy r = jsmn_parse(&p, js, tokens, 10); 380275970Scy check(r == JSMN_ERROR_INVAL); 381275970Scy 382275970Scy js = "{\"a\":[\"\\u028\"]}"; 383275970Scy jsmn_init(&p); 384275970Scy r = jsmn_parse(&p, js, tokens, 10); 385275970Scy check(r == JSMN_ERROR_INVAL); 386275970Scy 387275970Scy js = "{\"a\":[\"\\u0280\"]}"; 388275970Scy jsmn_init(&p); 389275970Scy r = jsmn_parse(&p, js, tokens, 10); 390275970Scy check(r == JSMN_SUCCESS); 391275970Scy 392275970Scy return 0; 393275970Scy} 394275970Scy 395275970Scyint main() { 396275970Scy test(test_empty, "general test for a empty JSON objects/arrays"); 397275970Scy test(test_simple, "general test for a simple JSON string"); 398275970Scy test(test_primitive, "test primitive JSON data types"); 399275970Scy test(test_string, "test string JSON data types"); 400275970Scy test(test_partial_string, "test partial JSON string parsing"); 401275970Scy test(test_partial_array, "test partial array reading"); 402275970Scy test(test_array_nomem, "test array reading with a smaller number of tokens"); 403275970Scy test(test_unquoted_keys, "test unquoted keys (like in JavaScript)"); 404275970Scy test(test_objects_arrays, "test objects and arrays"); 405275970Scy test(test_unicode_characters, "test unicode characters"); 406275970Scy printf("\nPASSED: %d\nFAILED: %d\n", test_passed, test_failed); 407275970Scy return 0; 408275970Scy} 409275970Scy 410