diff options
Diffstat (limited to 'tests/utests/data/test_parser_json.c')
-rw-r--r-- | tests/utests/data/test_parser_json.c | 172 |
1 files changed, 159 insertions, 13 deletions
diff --git a/tests/utests/data/test_parser_json.c b/tests/utests/data/test_parser_json.c index d341e31..8feed9c 100644 --- a/tests/utests/data/test_parser_json.c +++ b/tests/utests/data/test_parser_json.c @@ -1,9 +1,10 @@ -/* +/** * @file test_parser_json.c - * @author: Radek Krejci <rkrejci@cesnet.cz> - * @brief unit tests for functions from parser_xml.c + * @author Radek Krejci <rkrejci@cesnet.cz> + * @author Michal Vasko <mvasko@cesnet.cz> + * @brief unit tests for JSON parser * - * Copyright (c) 2019 CESNET, z.s.p.o. + * Copyright (c) 2019 - 2023 CESNET, z.s.p.o. * * This source code is licensed under BSD 3-Clause License (the "License"). * You may not use this file except in compliance with the License. @@ -44,7 +45,10 @@ setup(void **state) "leaf-list ll1 { type uint8; }" "leaf foo2 { type string; default \"default-val\"; }" "leaf foo3 { type uint32; }" - "notification n2;}"; + "leaf foo4 { type uint64; }" + "rpc r1 {input {leaf l1 {type string;} leaf l2 {type string;}}}" + "notification n2;" + "}"; UTEST_SETUP; @@ -160,6 +164,7 @@ test_leaf(void **state) /* reverse solidus in JSON object member name */ data = "{\"@a:foo\":{\"a:hi\\nt\":1},\"a:foo\":\"xxx\"}"; assert_int_equal(LY_EINVAL, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree)); + CHECK_LOG_CTX("Annotation definition for attribute \"a:hi\nt\" not found.", "Path \"/@a:foo/@a:hi\nt\", line number 1."); } static void @@ -427,12 +432,10 @@ test_list(void **state) assert_non_null(leaf = (struct lyd_node_term *)leaf->next); CHECK_LYSC_NODE(leaf->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "d", 1, LYS_LEAF, 1, 0, NULL, 0); CHECK_LOG_CTX(NULL, NULL); - CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, "{\"a:l1\":[{\"a\":\"a\",\"b\":\"b\",\"c\":1,\"d\":\"d\"}]}"); lyd_free_all(tree); - /* */ CHECK_PARSE_LYD("{\"a:l1\":[{\"c\":1,\"b\":\"b\",\"a\":\"a\"}]}", LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, tree); CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_ORDBY_SYSTEM, 1, "l1", 1, LYS_LIST, 0, 0, NULL, 0); @@ -447,11 +450,16 @@ test_list(void **state) CHECK_LYSC_NODE(leaf->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_KEY, 1, "c", 1, LYS_LEAF, 1, 0, NULL, 0); CHECK_LOG_CTX(NULL, NULL); - CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, "{\"a:l1\":[{\"a\":\"a\",\"b\":\"b\",\"c\":1}]}"); lyd_free_all(tree); + /* skip unknown nested nodes */ + data = "{\"a:l1\":[{\"a\":\"val_a\",\"b\":\"val_b\",\"c\":3,\"counters\":{\"count1\":\"c1\",\"count2\":\"c2\"}}]}"; + CHECK_PARSE_LYD(data, LYD_PARSE_ONLY, 0, tree); + CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, "{\"a:l1\":[{\"a\":\"val_a\",\"b\":\"val_b\",\"c\":3}]}"); + lyd_free_all(tree); + data = "{\"a:cp\":{\"@\":{\"a:hint\":1}}}"; CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree); assert_non_null(tree); @@ -460,7 +468,6 @@ test_list(void **state) 1, LYS_CONTAINER, 0, 0, NULL, 0); CHECK_LYD_META(tree->meta, 1, "hint", 0, 1, INT8, "1", 1); assert_null(tree->meta->next); - CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data); lyd_free_all(tree); } @@ -516,6 +523,25 @@ test_opaq(void **state) CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data); lyd_free_all(tree); + /* special chars */ + data = "{\"a:foo3\":\"ab\\\"\\\\\\r\\t\"}"; + CHECK_PARSE_LYD(data, LYD_PARSE_OPAQ | LYD_PARSE_ONLY, 0, tree); + CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data); + lyd_free_all(tree); + + /* wrong encoding */ + data = "{\"a:foo3\":\"25\"}"; + CHECK_PARSE_LYD(data, LYD_PARSE_OPAQ | LYD_PARSE_ONLY, 0, tree); + CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 0, 0, LY_VALUE_JSON, "foo3", 0, 0, NULL, 0, "25"); + CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data); + lyd_free_all(tree); + + data = "{\"a:foo4\":25}"; + CHECK_PARSE_LYD(data, LYD_PARSE_OPAQ | LYD_PARSE_ONLY, 0, tree); + CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 0, 0, LY_VALUE_JSON, "foo4", 0, 0, NULL, 0, "25"); + CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data); + lyd_free_all(tree); + /* missing key, no flags */ data = "{\"a:l1\":[{\"a\":\"val_a\",\"b\":\"val_b\",\"d\":\"val_d\"}]}"; PARSER_CHECK_ERROR(data, 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID, @@ -555,11 +581,12 @@ test_opaq(void **state) /* invalid metadata */ data = "{\"@a:foo\":\"str\",\"@a:foo3\":1,\"a:foo3\":2}"; PARSER_CHECK_ERROR(data, 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID, - "Unknown module of node \"@a:foo\".", "Data location \"/@a:foo\"."); + "Unknown module of node \"@a:foo\".", "Path \"/\"."); + CHECK_LOG_CTX("Missing JSON data instance to be coupled with @a:foo metadata.", "Data location \"/@a:foo\", line number 1."); /* empty name */ PARSER_CHECK_ERROR("{\"@a:foo\":{\"\":0}}", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID, - "A JSON object member name cannot be a zero-length string.", "Line number 1."); + "JSON object member name cannot be a zero-length string.", "Data location \"/@a:foo\", line number 1."); /* opaque data tree format print */ data = @@ -626,6 +653,7 @@ static void test_rpc(void **state) { const char *data; + char *str; struct ly_in *in; struct lyd_node *tree, *op; const struct lyd_node *node; @@ -675,8 +703,16 @@ test_rpc(void **state) CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data); lyd_free_all(tree); - /* wrong namespace, element name, whatever... */ - /* TODO */ + /* append to parent */ + assert_int_equal(LY_SUCCESS, lyd_new_path(NULL, UTEST_LYCTX, "/a:r1", NULL, 0, &op)); + assert_int_equal(LY_SUCCESS, ly_in_new_memory("{\"l1\": \"some str\", \"l2\": \"some other str\"}", &in)); + assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, op, in, LYD_JSON, LYD_TYPE_RPC_YANG, &tree, NULL)); + ly_in_free(in, 0); + + assert_int_equal(LY_SUCCESS, lyd_print_mem(&str, op, LYD_JSON, LYD_PRINT_WITHSIBLINGS | LYD_PRINT_SHRINK)); + lyd_free_tree(op); + assert_string_equal(str, "{\"a:r1\":{\"l1\":\"some str\",\"l2\":\"some other str\"}}"); + free(str); } static void @@ -772,6 +808,112 @@ test_reply(void **state) /* TODO */ } +static void +test_restconf_rpc(void **state) +{ + const char *data; + struct ly_in *in; + struct lyd_node *tree, *envp; + + assert_non_null((ly_ctx_load_module(UTEST_LYCTX, "ietf-netconf-nmda", "2019-01-07", NULL))); + + assert_int_equal(LY_SUCCESS, lyd_new_path(NULL, UTEST_LYCTX, "/ietf-netconf-nmda:edit-data", NULL, 0, &tree)); + + data = "{\"ietf-netconf-nmda:input\":{" + "\"datastore\":\"ietf-datastores:running\"," + "\"config\":{\"a:cp\":{\"z\":[null],\"@z\":{\"ietf-netconf:operation\":\"replace\"}}," + "\"a:l1\":[{\"@\":{\"ietf-netconf:operation\":\"replace\"},\"a\":\"val_a\",\"b\":\"val_b\",\"c\":\"val_c\"}]}" + "}}"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in)); + assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, tree, in, LYD_JSON, LYD_TYPE_RPC_RESTCONF, &envp, NULL)); + ly_in_free(in, 0); + + /* the same just connected to the edit-data RPC */ + data = "{\"ietf-netconf-nmda:edit-data\":{" + "\"datastore\":\"ietf-datastores:running\"," + "\"config\":{\"a:cp\":{\"z\":[null],\"@z\":{\"ietf-netconf:operation\":\"replace\"}}," + "\"a:l1\":[{\"@\":{\"ietf-netconf:operation\":\"replace\"},\"a\":\"val_a\",\"b\":\"val_b\",\"c\":\"val_c\"}]}" + "}}"; + CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data); + lyd_free_all(tree); + lyd_free_all(envp); +} + +static void +test_restconf_notification(void **state) +{ + const char *data; + struct ly_in *in; + struct lyd_node *tree, *ntf; + + data = "{\"ietf-restconf:notification\":{\"eventTime\":\"2013-12-21T00:01:00Z\",\"a:c\":{\"n1\":{\"nl\":\"value\"}}}}"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in)); + assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_JSON, LYD_TYPE_NOTIF_RESTCONF, &tree, &ntf)); + ly_in_free(in, 0); + + /* envelopes separately */ + data = "{\"ietf-restconf:notification\":{\"eventTime\":\"2013-12-21T00:01:00Z\"}}"; + CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data); + + /* notification with the parent node */ + data = "{\"a:c\":{\"n1\":{\"nl\":\"value\"}}}"; + CHECK_LYD_STRING(lyd_parent(ntf), LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data); + + lyd_free_all(tree); + lyd_free_all(ntf); + + /* wrong order */ + data = "{\"ietf-restconf:notification\":{\"a:n2\":{},\"eventTime\":\"2013-12-21T00:01:00Z\"}}"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in)); + assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_JSON, LYD_TYPE_NOTIF_RESTCONF, &tree, &ntf)); + ly_in_free(in, 0); + + lyd_free_all(tree); + lyd_free_all(ntf); + + /* unknown notification */ + data = "{\"ietf-restconf:notification\":{\"eventTime\":\"2013-12-21T00:01:00Z\",\"invalid:n2\":{}}}"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in)); + assert_int_equal(LY_EVALID, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_JSON, LYD_TYPE_NOTIF_RESTCONF, &tree, &ntf)); + UTEST_LOG_CTX_CLEAN; + ly_in_free(in, 0); + lyd_free_all(tree); +} + +static void +test_restconf_reply(void **state) +{ + const char *data; + struct ly_in *in; + struct lyd_node *tree, *envp; + + assert_int_equal(LY_SUCCESS, lyd_new_path(NULL, UTEST_LYCTX, "/a:c/act", NULL, 0, &tree)); + + data = "{\"a:output\":{\"al\":25}}"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in)); + assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, lyd_child(tree), in, LYD_JSON, LYD_TYPE_REPLY_RESTCONF, &envp, NULL)); + ly_in_free(in, 0); + + /* connected to the RPC with the parent */ + data = "{\"a:c\":{\"act\":{\"al\":25}}}"; + CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data); + lyd_free_all(tree); + lyd_free_all(envp); +} + +static void +test_metadata(void **state) +{ + const char *data; + struct lyd_node *tree; + + /* invalid metadata value */ + data = "{\"a:c\":{\"x\":\"xval\",\"@x\":{\"a:hint\":\"value\"}}}"; + assert_int_equal(LY_EVALID, lyd_parse_data_mem(_UC->ctx, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree)); + assert_null(tree); + CHECK_LOG_CTX("Invalid non-number-encoded int8 value \"value\".", "Path \"/a:c/x/@a:hint\", line number 1."); +} + int main(void) { @@ -787,6 +929,10 @@ main(void) UTEST(test_action, setup), UTEST(test_notification, setup), UTEST(test_reply, setup), + UTEST(test_restconf_rpc, setup), + UTEST(test_restconf_notification, setup), + UTEST(test_restconf_reply, setup), + UTEST(test_metadata, setup), }; return cmocka_run_group_tests(tests, NULL, NULL); |