| /* |
| * Copyright (c) 2017 Intel Corporation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| #include <string.h> |
| #include <stdint.h> |
| #include <stdbool.h> |
| #include <ztest.h> |
| #include <json.h> |
| |
| struct test_nested { |
| int nested_int; |
| bool nested_bool; |
| const char *nested_string; |
| }; |
| |
| struct test_struct { |
| const char *some_string; |
| int some_int; |
| bool some_bool; |
| struct test_nested some_nested_struct; |
| int some_array[16]; |
| size_t some_array_len; |
| }; |
| |
| #define FIELD(struct_, member_, type_) { \ |
| .field_name = #member_, \ |
| .field_name_len = sizeof(#member_) - 1, \ |
| .offset = offsetof(struct_, member_), \ |
| .type = type_ \ |
| } |
| static const struct json_obj_descr nested_descr[] = { |
| FIELD(struct test_nested, nested_int, JSON_TOK_NUMBER), |
| FIELD(struct test_nested, nested_bool, JSON_TOK_TRUE), |
| FIELD(struct test_nested, nested_string, JSON_TOK_STRING), |
| }; |
| |
| static const struct json_obj_descr test_descr[] = { |
| FIELD(struct test_struct, some_string, JSON_TOK_STRING), |
| FIELD(struct test_struct, some_int, JSON_TOK_NUMBER), |
| FIELD(struct test_struct, some_bool, JSON_TOK_TRUE), |
| JSON_OBJ_DESCR_OBJECT(struct test_struct, some_nested_struct, |
| nested_descr), |
| JSON_OBJ_DESCR_ARRAY(struct test_struct, some_array, |
| 16, some_array_len, JSON_TOK_NUMBER), |
| }; |
| #undef FIELD |
| |
| static void test_json_encoding(void) |
| { |
| struct test_struct ts = { |
| .some_string = "zephyr 123", |
| .some_int = 42, |
| .some_bool = true, |
| .some_nested_struct = { |
| .nested_int = -1234, |
| .nested_bool = false, |
| .nested_string = "this should be escaped: \t" |
| }, |
| .some_array[0] = 1, |
| .some_array[1] = 4, |
| .some_array[2] = 8, |
| .some_array[3] = 16, |
| .some_array[4] = 32, |
| .some_array_len = 5 |
| }; |
| char encoded[] = "{\"some_string\":\"zephyr 123\"," |
| "\"some_int\":42,\"some_bool\":true," |
| "\"some_nested_struct\":{\"nested_int\":-1234," |
| "\"nested_bool\":false,\"nested_string\":" |
| "\"this should be escaped: \\t\"}," |
| "\"some_array\":[1,4,8,16,32]}"; |
| char buffer[sizeof(encoded)]; |
| int ret; |
| |
| ret = json_obj_encode_buf(test_descr, ARRAY_SIZE(test_descr), |
| &ts, buffer, sizeof(buffer)); |
| assert_equal(ret, 0, "Encoding function returned no errors"); |
| |
| ret = strncmp(buffer, encoded, sizeof(encoded) - 1); |
| assert_equal(ret, 0, "Encoded contents consistent"); |
| } |
| |
| static void test_json_decoding(void) |
| { |
| struct test_struct ts; |
| char encoded[] = "{\"some_string\":\"zephyr 123\"," |
| "\"some_int\":\t42\n," |
| "\"some_bool\":true \t " |
| "\n" |
| "\r ," |
| "\"some_nested_struct\":{ " |
| "\"nested_int\":-1234,\n\n" |
| "\"nested_bool\":false,\t" |
| "\"nested_string\":\"this should be escaped: \\t\"}," |
| "\"some_array\":[11,22, 33,\t45,\n299]" |
| "}"; |
| const int expected_array[] = { 11, 22, 33, 45, 299 }; |
| int ret; |
| |
| ret = json_obj_parse(encoded, sizeof(encoded) - 1, test_descr, |
| ARRAY_SIZE(test_descr), &ts); |
| |
| assert_equal(ret, (1 << ARRAY_SIZE(test_descr)) - 1, |
| "All fields decoded correctly"); |
| |
| assert_true(!strcmp(ts.some_string, "zephyr 123"), |
| "String decoded correctly"); |
| assert_equal(ts.some_int, 42, "Positive integer decoded correctly"); |
| assert_equal(ts.some_bool, true, "Boolean decoded correctly"); |
| assert_equal(ts.some_nested_struct.nested_int, -1234, |
| "Nested negative integer decoded correctly"); |
| assert_equal(ts.some_nested_struct.nested_bool, false, |
| "Nested boolean value decoded correctly"); |
| assert_true(!strcmp(ts.some_nested_struct.nested_string, |
| "this should be escaped: \\t"), |
| "Nested string decoded correctly"); |
| assert_equal(ts.some_array_len, 5, "Array has correct number of items"); |
| assert_true(!memcmp(ts.some_array, expected_array, |
| sizeof(expected_array)), |
| "Array decoded with unexpected values"); |
| } |
| |
| static void test_json_invalid_unicode(void) |
| { |
| struct test_struct ts; |
| char encoded[] = "{\"some_string\":\"\\uABC@\"}"; |
| int ret; |
| |
| ret = json_obj_parse(encoded, sizeof(encoded) - 1, test_descr, |
| ARRAY_SIZE(test_descr), &ts); |
| assert_equal(ret, -EINVAL, "Decoding has to fail"); |
| } |
| |
| static void test_json_missing_quote(void) |
| { |
| struct test_struct ts; |
| char encoded[] = "{\"some_string"; |
| int ret; |
| |
| ret = json_obj_parse(encoded, sizeof(encoded) - 1, test_descr, |
| ARRAY_SIZE(test_descr), &ts); |
| assert_equal(ret, -EINVAL, "Decoding has to fail"); |
| } |
| |
| static void test_json_wrong_token(void) |
| { |
| struct test_struct ts; |
| char encoded[] = "{\"some_string\",}"; |
| int ret; |
| |
| ret = json_obj_parse(encoded, sizeof(encoded) - 1, test_descr, |
| ARRAY_SIZE(test_descr), &ts); |
| assert_equal(ret, -EINVAL, "Decoding has to fail"); |
| } |
| |
| static void test_json_item_wrong_type(void) |
| { |
| struct test_struct ts; |
| char encoded[] = "{\"some_string\":false}"; |
| int ret; |
| |
| ret = json_obj_parse(encoded, sizeof(encoded) - 1, test_descr, |
| ARRAY_SIZE(test_descr), &ts); |
| assert_equal(ret, -EINVAL, "Decoding has to fail"); |
| } |
| |
| static void test_json_key_not_in_descr(void) |
| { |
| struct test_struct ts; |
| char encoded[] = "{\"key_not_in_descr\":123456}"; |
| int ret; |
| |
| ret = json_obj_parse(encoded, sizeof(encoded) - 1, test_descr, |
| ARRAY_SIZE(test_descr), &ts); |
| assert_equal(ret, 0, "No items should be decoded"); |
| } |
| |
| void test_main(void) |
| { |
| ztest_test_suite(lib_json_test, |
| ztest_unit_test(test_json_encoding), |
| ztest_unit_test(test_json_decoding), |
| ztest_unit_test(test_json_invalid_unicode), |
| ztest_unit_test(test_json_missing_quote), |
| ztest_unit_test(test_json_wrong_token), |
| ztest_unit_test(test_json_item_wrong_type), |
| ztest_unit_test(test_json_key_not_in_descr) |
| ); |
| |
| ztest_run_test_suite(lib_json_test); |
| } |