| 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| 26 * POSSIBILITY OF SUCH DAMAGE. |
26 * POSSIBILITY OF SUCH DAMAGE. |
| 27 */ |
27 */ |
| 28 |
28 |
| |
29 #include "util_allocator.h" |
| 29 #include "cx/test.h" |
30 #include "cx/test.h" |
| 30 |
31 |
| 31 #include "cx/json.h" |
32 #include "cx/json.h" |
| 32 #include "cx/mempool.h" |
33 #include "cx/mempool.h" |
| 33 |
34 |
| 34 CX_TEST(test_json_init_default) { |
35 CX_TEST(test_json_init_default) { |
| 35 CxJson json; |
36 CxJson json; |
| 36 CX_TEST_DO { |
37 CX_TEST_DO { |
| 37 cxJsonInit(NULL, &json); |
38 cxJsonInit(&json, NULL); |
| 38 CX_TEST_ASSERT(json.states == json.states_internal); |
39 CX_TEST_ASSERT(json.states == json.states_internal); |
| 39 CX_TEST_ASSERT(json.nstates == 0); |
40 CX_TEST_ASSERT(json.states_size == 1); |
| 40 CX_TEST_ASSERT(json.states_alloc == 8); |
41 CX_TEST_ASSERT(json.states_capacity >= 8); |
| 41 CX_TEST_ASSERT(json.reader_array_alloc == 8); |
42 CX_TEST_ASSERT(json.vbuf == json.vbuf_internal); |
| |
43 CX_TEST_ASSERT(json.vbuf_size == 0); |
| |
44 CX_TEST_ASSERT(json.vbuf_capacity >= 8); |
| 42 } |
45 } |
| 43 } |
46 } |
| 44 |
47 |
| 45 CX_TEST(test_json_simple_object) { |
48 CX_TEST(test_json_simple_object) { |
| 46 cxstring text = cx_str( |
49 cxstring text = cx_str( |
| 189 int result; |
192 int result; |
| 190 CxJson json; |
193 CxJson json; |
| 191 CxJsonValue *obj = NULL; |
194 CxJsonValue *obj = NULL; |
| 192 |
195 |
| 193 for(int i=0;i<5;i++) { |
196 for(int i=0;i<5;i++) { |
| 194 cxJsonInit(NULL, &json); |
197 cxJsonInit(&json, NULL); |
| 195 cxJsonFill(&json, tests[i]); |
198 cxJsonFill(&json, tests[i]); |
| 196 result = cxJsonNext(&json, &obj); |
199 result = cxJsonNext(&json, &obj); |
| 197 |
200 |
| 198 CX_TEST_ASSERT(result == -1); |
201 CX_TEST_ASSERT(result == -1); |
| 199 CX_TEST_ASSERT(obj == NULL); |
202 CX_TEST_ASSERT(obj != NULL && obj->type == CX_JSON_NOTHING); |
| 200 cxJsonDestroy(&json); |
203 cxJsonDestroy(&json); |
| 201 } |
204 } |
| 202 } |
205 } |
| 203 } |
206 } |
| 204 |
207 |
| 205 CX_TEST(test_json_large_nesting_depth) { |
208 CX_TEST(test_json_large_nesting_depth) { |
| 206 CxJson json; |
209 CxJson json; |
| 207 CxJsonValue *d1; |
210 CxJsonValue *d1; |
| 208 cxstring text = cx_str("{\"test\": [{},{\"foo\": [[{\"bar\":[4, 2, [null, {\"key\": 47}]]}]]}]}"); |
211 cxstring text = cx_str("{\"test\": [{},{\"foo\": [[{\"bar\":[4, 2, [null, {\"key\": 47}]]}]]}]}"); |
| 209 CX_TEST_DO { |
212 CX_TEST_DO { |
| 210 cxJsonInit(NULL, &json); |
213 cxJsonInit(&json, NULL); |
| 211 cxJsonFill(&json, text); |
214 cxJsonFill(&json, text); |
| 212 cxJsonNext(&json, &d1); |
215 cxJsonNext(&json, &d1); |
| 213 |
216 |
| 214 CX_TEST_ASSERT(d1 != NULL); |
217 CX_TEST_ASSERT(d1 != NULL); |
| 215 CX_TEST_ASSERT(cxJsonIsObject(d1)); |
218 CX_TEST_ASSERT(cxJsonIsObject(d1)); |
| 239 CxJsonValue *d10 = cxJsonObjGet(d9b, "key"); |
242 CxJsonValue *d10 = cxJsonObjGet(d9b, "key"); |
| 240 CX_TEST_ASSERT(cxJsonIsInteger(d10)); |
243 CX_TEST_ASSERT(cxJsonIsInteger(d10)); |
| 241 CX_TEST_ASSERT(cxJsonAsInteger(d10) == 47); |
244 CX_TEST_ASSERT(cxJsonAsInteger(d10) == 47); |
| 242 |
245 |
| 243 CX_TEST_ASSERT(json.states != json.states_internal); |
246 CX_TEST_ASSERT(json.states != json.states_internal); |
| 244 CX_TEST_ASSERT(json.states_alloc > cx_nmemb(json.states_internal)); |
247 CX_TEST_ASSERT(json.states_capacity > cx_nmemb(json.states_internal)); |
| 245 |
248 |
| 246 cxJsonValueFree(d1); |
249 cxJsonValueFree(d1); |
| 247 cxJsonDestroy(&json); |
250 cxJsonDestroy(&json); |
| 248 } |
251 } |
| 249 } |
252 } |
| 250 |
253 |
| 251 CX_TEST(test_json_number) { |
254 CX_TEST(test_json_number) { |
| 252 CxJson json; |
255 CxJson json; |
| 253 cxJsonInit(NULL, &json); |
256 cxJsonInit(&json, NULL); |
| 254 CX_TEST_DO { |
257 CX_TEST_DO { |
| 255 // TODO: find a better way to terminate values that are not arrays/objects |
258 // TODO: find a better way to terminate values that are not arrays/objects |
| 256 CxJsonValue *v; |
259 CxJsonValue *v; |
| 257 int result; |
260 int result; |
| 258 cxJsonFill(&json, "3.1415 "); |
261 cxJsonFill(&json, "3.1415 "); |
| 332 } |
335 } |
| 333 cxJsonDestroy(&json); |
336 cxJsonDestroy(&json); |
| 334 } |
337 } |
| 335 |
338 |
| 336 CX_TEST(test_json_allocator) { |
339 CX_TEST(test_json_allocator) { |
| 337 CxMempool *mp = cxMempoolCreate(64, NULL); |
340 CxTestingAllocator talloc; |
| 338 CxJson json; |
341 cx_testing_allocator_init(&talloc); |
| 339 cxJsonInit(mp->allocator, &json); |
342 CxAllocator *allocator = &talloc.base; |
| 340 |
343 |
| 341 cxstring text = cx_str( |
344 cxstring text = cx_str( |
| 342 "{\n" |
345 "{\n" |
| 343 "\t\"message\":\"success\",\n" |
346 "\t\"message\":\"success\",\n" |
| 344 "\t\"data\":[\"value1\",{\"x\":123, \"y\":523 }]\n" |
347 "\t\"data\":[\"value1\",{\"x\":123, \"y\":523 }]\n" |
| 345 "}" |
348 "}" |
| 346 ); |
349 ); |
| 347 |
350 |
| 348 CX_TEST_DO { |
351 CX_TEST_DO { |
| 349 int result; |
|
| 350 |
|
| 351 CxJson json; |
352 CxJson json; |
| 352 cxJsonInit(mp->allocator, &json); |
353 cxJsonInit(&json, allocator); |
| 353 cxJsonFill(&json, text); |
354 cxJsonFill(&json, text); |
| 354 |
355 |
| 355 CxJsonValue *obj; |
356 CxJsonValue *obj; |
| 356 result = cxJsonNext(&json, &obj); |
357 int result = cxJsonNext(&json, &obj); |
| 357 CX_TEST_ASSERT(result == 1); |
358 CX_TEST_ASSERT(result == 1); |
| 358 CX_TEST_ASSERT(obj->allocator == mp->allocator); |
359 CX_TEST_ASSERT(obj->allocator == allocator); |
| 359 |
360 |
| 360 // this recursively frees everything |
361 // this recursively frees everything |
| 361 cxJsonValueFree(obj); |
362 cxJsonValueFree(obj); |
| 362 cxJsonDestroy(&json); |
363 cxJsonDestroy(&json); |
| 363 cxMempoolFree(mp); |
364 |
| 364 } |
365 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc)); |
| |
366 } |
| |
367 cx_testing_allocator_destroy(&talloc); |
| |
368 } |
| |
369 |
| |
370 CX_TEST(test_json_allocator_parse_error) { |
| |
371 CxTestingAllocator talloc; |
| |
372 cx_testing_allocator_init(&talloc); |
| |
373 CxAllocator *allocator = &talloc.base; |
| |
374 |
| |
375 cxstring text = cx_str( |
| |
376 "{\n" |
| |
377 "\t\"message\":\"success\"\n" // <-- missing comma |
| |
378 "\t\"data\":[\"value1\",{\"x\":123, \"y\":523 }]\n" |
| |
379 "}" |
| |
380 ); |
| |
381 |
| |
382 CX_TEST_DO { |
| |
383 CxJson json; |
| |
384 cxJsonInit(&json, allocator); |
| |
385 cxJsonFill(&json, text); |
| |
386 |
| |
387 CxJsonValue *obj = NULL; |
| |
388 int result = cxJsonNext(&json, &obj); |
| |
389 CX_TEST_ASSERT(result == -1); |
| |
390 CX_TEST_ASSERT(obj != NULL && obj->type == CX_JSON_NOTHING); |
| |
391 |
| |
392 // clean-up any left-over memory |
| |
393 cxJsonDestroy(&json); |
| |
394 |
| |
395 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc)); |
| |
396 } |
| |
397 cx_testing_allocator_destroy(&talloc); |
| 365 } |
398 } |
| 366 |
399 |
| 367 CxTestSuite *cx_test_suite_json(void) { |
400 CxTestSuite *cx_test_suite_json(void) { |
| 368 CxTestSuite *suite = cx_test_suite_new("json"); |
401 CxTestSuite *suite = cx_test_suite_new("json"); |
| 369 |
402 |
| 373 cx_test_register(suite, test_json_object_error); |
406 cx_test_register(suite, test_json_object_error); |
| 374 cx_test_register(suite, test_json_large_nesting_depth); |
407 cx_test_register(suite, test_json_large_nesting_depth); |
| 375 cx_test_register(suite, test_json_number); |
408 cx_test_register(suite, test_json_number); |
| 376 cx_test_register(suite, test_json_multiple_values); |
409 cx_test_register(suite, test_json_multiple_values); |
| 377 cx_test_register(suite, test_json_allocator); |
410 cx_test_register(suite, test_json_allocator); |
| |
411 cx_test_register(suite, test_json_allocator_parse_error); |
| 378 |
412 |
| 379 return suite; |
413 return suite; |
| 380 } |
414 } |
| 381 |
415 |