/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include "cj5.h" #include #include #include /* vs2008 does not have INFINITY and NAN defined */ #ifndef INFINITY # define INFINITY ((double)(DBL_MAX+DBL_MAX)) #endif #ifndef NAN # define NAN ((double)(INFINITY-INFINITY)) #endif #if defined(_MSC_VER) # pragma warning(disable: 4056) # pragma warning(disable: 4756) #endif START_TEST(parseObject) { const char *json = "{'a':1.0, 'b':2, 'c':'abcde'}"; cj5_token tokens[32]; cj5_result r = cj5_parse(json, (unsigned int)strlen(json), tokens, 32, NULL); ck_assert(r.error == CJ5_ERROR_NONE); double d = 0.0; cj5_error_code err = cj5_get_float(&r, 2, &d); ck_assert(err == CJ5_ERROR_NONE); ck_assert(d == 1.0); ck_assert_uint_eq(tokens[6].size, 5); } END_TEST START_TEST(parseUTF8) { const char *json = "{'a':\"Lindestra\\u00dfe\"}"; cj5_token tokens[32]; cj5_result r = cj5_parse(json, (unsigned int)strlen(json), tokens, 32, NULL); ck_assert(r.error == CJ5_ERROR_NONE); char buf[32]; cj5_error_code err = cj5_get_str(&r, 2, buf, NULL); ck_assert(err == CJ5_ERROR_NONE); ck_assert_uint_eq(tokens[2].size, 16); } END_TEST START_TEST(parseNestedObject) { const char *json = "{'a':{}, 'b':{'c':3}, 'd':true, 'e':false, 'f':null, 'g':[]}"; cj5_token tokens[32]; cj5_result r = cj5_parse(json, (unsigned int)strlen(json), tokens, 32, NULL); ck_assert(r.error == CJ5_ERROR_NONE); /* 12 elements directly under the root object */ ck_assert_uint_eq(tokens[0].size, 12); /* Test the cj5_find method for value lookup in objects */ unsigned int idx = 0; cj5_error_code err = cj5_find(&r, &idx, "b"); ck_assert_int_eq(err, CJ5_ERROR_NONE); ck_assert_uint_eq(idx, 4); err = cj5_find(&r, &idx, "c"); ck_assert(err == CJ5_ERROR_NONE); ck_assert(idx == 6); int64_t val = 0; cj5_get_int(&r, idx, &val); ck_assert(val == 3); idx = 4; err = cj5_find(&r, &idx, "d"); ck_assert(err == CJ5_ERROR_NOTFOUND); idx = 0; err = cj5_find(&r, &idx, "d"); ck_assert_int_eq(err, CJ5_ERROR_NONE); bool bval = 0; cj5_get_bool(&r, idx, &bval); ck_assert(bval == true); idx = 0; err = cj5_find(&r, &idx, "e"); ck_assert_int_eq(err, CJ5_ERROR_NONE); cj5_get_bool(&r, idx, &bval); ck_assert(bval == false); idx = 0; err = cj5_find(&r, &idx, "f"); ck_assert_int_eq(err, CJ5_ERROR_NONE); ck_assert(tokens[idx].type == CJ5_TOKEN_NULL); } END_TEST START_TEST(parseObjectUnquoted) { const char *json = "{'a':1, b:true}"; cj5_token tokens[32]; cj5_result r = cj5_parse(json, (unsigned int)strlen(json), tokens, 32, NULL); ck_assert(r.error == CJ5_ERROR_NONE); } END_TEST START_TEST(parseObjectWrongBracket) { const char *json = "{'a':1, 'b':2]"; cj5_token tokens[32]; cj5_result r = cj5_parse(json, (unsigned int)strlen(json), tokens, 32, NULL); ck_assert(r.error == CJ5_ERROR_INVALID); } END_TEST START_TEST(parseObjectWrongBracket2) { const char *json = "{{'a':1, 'b':2]}"; cj5_token tokens[32]; cj5_result r = cj5_parse(json, (unsigned int)strlen(json), tokens, 32, NULL); ck_assert(r.error == CJ5_ERROR_INVALID); } END_TEST START_TEST(parseObjectIncomplete) { const char *json = "{'a':1, 'b':2"; cj5_token tokens[32]; cj5_result r = cj5_parse(json, (unsigned int)strlen(json), tokens, 32, NULL); ck_assert(r.error == CJ5_ERROR_INCOMPLETE); } END_TEST START_TEST(parseObjectNoRoot) { const char *json = "'a':1, 'b':2"; cj5_token tokens[32]; cj5_result r = cj5_parse(json, (unsigned int)strlen(json), tokens, 32, NULL); ck_assert(r.error == CJ5_ERROR_NONE); } END_TEST START_TEST(parseObjectStopEarly) { cj5_options opt; opt.stop_early = true; const char *json = "{'a':1}, x"; cj5_token tokens[32]; cj5_result r = cj5_parse(json, (unsigned int)strlen(json), tokens, 32, &opt); ck_assert(r.error == CJ5_ERROR_NONE); ck_assert_uint_eq(r.tokens[0].end, 6); } END_TEST START_TEST(parseObjectNoRootUnquoted) { const char *json = "a:1, 'b':2"; cj5_token tokens[32]; cj5_result r = cj5_parse(json, (unsigned int)strlen(json), tokens, 32, NULL); ck_assert(r.error == CJ5_ERROR_NONE); } END_TEST START_TEST(parseObjectCloseNoRoot) { const char *json = "'a':1, 'b':2}"; cj5_token tokens[32]; cj5_result r = cj5_parse(json, (unsigned int)strlen(json), tokens, 32, NULL); ck_assert(r.error == CJ5_ERROR_INVALID); } END_TEST START_TEST(parseArray) { const char *json = "[1.23456,2,3,null]"; cj5_token tokens[32]; cj5_result r = cj5_parse(json, (unsigned int)strlen(json), tokens, 32, NULL); ck_assert(r.error == CJ5_ERROR_NONE); double val = 0; cj5_get_float(&r, 1, &val); ck_assert(fabs(val - 1.23456) < 0.00001); } END_TEST START_TEST(parseArrayStopEarly) { cj5_options opt; opt.stop_early = true; const char *json = "[1] }"; cj5_token tokens[32]; cj5_result r = cj5_parse(json, (unsigned int)strlen(json), tokens, 32, &opt); ck_assert(r.error == CJ5_ERROR_NONE); ck_assert_uint_eq(r.tokens[0].end, 2); } END_TEST START_TEST(parseValue) { const char *json = "null"; cj5_token tokens[32]; cj5_result r = cj5_parse(json, (unsigned int)strlen(json), tokens, 32, NULL); ck_assert(r.error == CJ5_ERROR_NONE); } END_TEST START_TEST(parseValueStopEarly) { cj5_options opt; opt.stop_early = true; const char *json = "1.0{"; cj5_token tokens[32]; cj5_result r = cj5_parse(json, (unsigned int)strlen(json), tokens, 32, &opt); ck_assert(r.error == CJ5_ERROR_NONE); ck_assert_uint_eq(r.tokens[0].end, 2); } END_TEST START_TEST(parseInf) { const char *json = "Infinity"; cj5_token tokens[32]; cj5_result r = cj5_parse(json, (unsigned int)strlen(json), tokens, 32, NULL); ck_assert(r.error == CJ5_ERROR_NONE); double val = 0; cj5_get_float(&r, 0, &val); ck_assert_msg(val == INFINITY, "val: %f", val); } END_TEST START_TEST(parseNegInf) { const char *json = "-Infinity"; cj5_token tokens[32]; cj5_result r = cj5_parse(json, (unsigned int)strlen(json), tokens, 32, NULL); ck_assert(r.error == CJ5_ERROR_NONE); double val = 0; cj5_get_float(&r, 0, &val); ck_assert_msg(val == -INFINITY, "val: %f", val); } END_TEST static Suite *testSuite_builtin_json(void) { TCase *tc_parse= tcase_create("cj5_parse"); tcase_add_test(tc_parse, parseObject); tcase_add_test(tc_parse, parseUTF8); tcase_add_test(tc_parse, parseNestedObject); tcase_add_test(tc_parse, parseObjectUnquoted); tcase_add_test(tc_parse, parseObjectWrongBracket); tcase_add_test(tc_parse, parseObjectWrongBracket2); tcase_add_test(tc_parse, parseObjectIncomplete); tcase_add_test(tc_parse, parseObjectNoRoot); tcase_add_test(tc_parse, parseObjectNoRootUnquoted); tcase_add_test(tc_parse, parseObjectCloseNoRoot); tcase_add_test(tc_parse, parseObjectStopEarly); tcase_add_test(tc_parse, parseArray); tcase_add_test(tc_parse, parseArrayStopEarly); tcase_add_test(tc_parse, parseValue); tcase_add_test(tc_parse, parseValueStopEarly); tcase_add_test(tc_parse, parseInf); tcase_add_test(tc_parse, parseNegInf); Suite *s = suite_create("Test JSON decoding with the cj5 library"); suite_add_tcase(s, tc_parse); return s; } int main(void) { int number_failed = 0; Suite *s = testSuite_builtin_json(); SRunner *sr = srunner_create(s); srunner_set_fork_status(sr, CK_NOFORK); srunner_run_all(sr, CK_NORMAL); number_failed += srunner_ntests_failed(sr); srunner_free(sr); return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; }