summaryrefslogtreecommitdiffstats
path: root/tests/utests/data
diff options
context:
space:
mode:
Diffstat (limited to 'tests/utests/data')
-rw-r--r--tests/utests/data/test_diff.c258
-rw-r--r--tests/utests/data/test_new.c63
-rw-r--r--tests/utests/data/test_parser_json.c172
-rw-r--r--tests/utests/data/test_parser_xml.c226
-rw-r--r--tests/utests/data/test_printer_xml.c3
-rw-r--r--tests/utests/data/test_tree_data.c35
-rw-r--r--tests/utests/data/test_validation.c93
7 files changed, 804 insertions, 46 deletions
diff --git a/tests/utests/data/test_diff.c b/tests/utests/data/test_diff.c
index 1b7592a..4400b5d 100644
--- a/tests/utests/data/test_diff.c
+++ b/tests/utests/data/test_diff.c
@@ -4,7 +4,7 @@
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief tests for lyd_diff()
*
- * Copyright (c) 2020 CESNET, z.s.p.o.
+ * Copyright (c) 2020 - 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.
@@ -17,15 +17,15 @@
#include "libyang.h"
-#define CHECK_PARSE_LYD(INPUT, MODEL) \
- CHECK_PARSE_LYD_PARAM(INPUT, LYD_XML, LYD_PARSE_ONLY, 0, LY_SUCCESS, MODEL)
+#define CHECK_PARSE_LYD(INPUT, OUTPUT) \
+ CHECK_PARSE_LYD_PARAM(INPUT, LYD_XML, LYD_PARSE_ONLY, 0, LY_SUCCESS, OUTPUT)
-#define CHECK_LYD_STRING(IN_MODEL, TEXT) \
- CHECK_LYD_STRING_PARAM(IN_MODEL, TEXT, LYD_XML, LYD_PRINT_WITHSIBLINGS)
+#define CHECK_LYD_STRING(INPUT, TEXT) \
+ CHECK_LYD_STRING_PARAM(INPUT, TEXT, LYD_XML, LYD_PRINT_WITHSIBLINGS)
-#define CHECK_PARSE_LYD_DIFF(INPUT_1, INPUT_2, OUT_MODEL) \
- assert_int_equal(LY_SUCCESS, lyd_diff_siblings(INPUT_1, INPUT_2, 0, &OUT_MODEL));\
- assert_non_null(OUT_MODEL)
+#define CHECK_PARSE_LYD_DIFF(INPUT_1, INPUT_2, OUT_DIFF) \
+ assert_int_equal(LY_SUCCESS, lyd_diff_siblings(INPUT_1, INPUT_2, 0, &OUT_DIFF));\
+ assert_non_null(OUT_DIFF)
#define TEST_DIFF_3(XML1, XML2, XML3, DIFF1, DIFF2, MERGE) \
{ \
@@ -117,6 +117,12 @@ const char *schema1 =
" leaf l2 {\n"
" type int32;\n"
" }\n"
+ ""
+ " container cont {\n"
+ " leaf l3 {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
" }\n"
""
" leaf-list dllist {\n"
@@ -312,6 +318,8 @@ test_invalid(void **state)
struct lyd_node *diff = NULL;
assert_int_equal(lyd_diff_siblings(model_1, lyd_child(model_1), 0, &diff), LY_EINVAL);
+ CHECK_LOG_CTX("Invalid arguments - cannot create diff for unrelated data (lyd_diff()).", NULL);
+
assert_int_equal(lyd_diff_siblings(NULL, NULL, 0, NULL), LY_EINVAL);
lyd_free_all(model_1);
@@ -637,6 +645,126 @@ test_list(void **state)
}
static void
+test_nested_list(void **state)
+{
+ struct lyd_node *data1, *data2, *diff;
+ const char *xml1, *xml2;
+
+ (void) state;
+
+ xml1 =
+ "<df xmlns=\"urn:libyang:tests:defaults\">"
+ " <list>"
+ " <name>n1</name>"
+ " <value>25</value>"
+ " <list2>"
+ " <name2>n22</name2>"
+ " <value2>26</value2>"
+ " </list2>"
+ " </list>"
+ " <list>"
+ " <name>n2</name>"
+ " <value>25</value>"
+ " <list2>"
+ " <name2>n22</name2>"
+ " <value2>26</value2>"
+ " </list2>"
+ " </list>"
+ " <list>"
+ " <name>n3</name>"
+ " <value>25</value>"
+ " <list2>"
+ " <name2>n22</name2>"
+ " <value2>26</value2>"
+ " </list2>"
+ " </list>"
+ " <list>"
+ " <name>n4</name>"
+ " <value>25</value>"
+ " <list2>"
+ " <name2>n22</name2>"
+ " <value2>26</value2>"
+ " </list2>"
+ " </list>"
+ " <list>"
+ " <name>n0</name>"
+ " <value>26</value>"
+ " <list2>"
+ " <name2>n22</name2>"
+ " <value2>26</value2>"
+ " </list2>"
+ " <list2>"
+ " <name2>n23</name2>"
+ " <value2>26</value2>"
+ " </list2>"
+ " </list>"
+ "</df>";
+ xml2 =
+ "<df xmlns=\"urn:libyang:tests:defaults\">"
+ " <list>"
+ " <name>n0</name>"
+ " <value>30</value>"
+ " <list2>"
+ " <name2>n23</name2>"
+ " <value2>26</value2>"
+ " </list2>"
+ " </list>"
+ "</df>";
+
+ CHECK_PARSE_LYD(xml1, data1);
+ CHECK_PARSE_LYD(xml2, data2);
+ CHECK_PARSE_LYD_DIFF(data1, data2, diff);
+
+ CHECK_LYD_STRING(diff,
+ "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">\n"
+ " <list yang:operation=\"delete\">\n"
+ " <name>n1</name>\n"
+ " <value>25</value>\n"
+ " <list2>\n"
+ " <name2>n22</name2>\n"
+ " <value2>26</value2>\n"
+ " </list2>\n"
+ " </list>\n"
+ " <list yang:operation=\"delete\">\n"
+ " <name>n2</name>\n"
+ " <value>25</value>\n"
+ " <list2>\n"
+ " <name2>n22</name2>\n"
+ " <value2>26</value2>\n"
+ " </list2>\n"
+ " </list>\n"
+ " <list yang:operation=\"delete\">\n"
+ " <name>n3</name>\n"
+ " <value>25</value>\n"
+ " <list2>\n"
+ " <name2>n22</name2>\n"
+ " <value2>26</value2>\n"
+ " </list2>\n"
+ " </list>\n"
+ " <list yang:operation=\"delete\">\n"
+ " <name>n4</name>\n"
+ " <value>25</value>\n"
+ " <list2>\n"
+ " <name2>n22</name2>\n"
+ " <value2>26</value2>\n"
+ " </list2>\n"
+ " </list>\n"
+ " <list yang:operation=\"none\">\n"
+ " <name>n0</name>\n"
+ " <value yang:operation=\"replace\" yang:orig-default=\"false\" yang:orig-value=\"26\">30</value>\n"
+ " <list2 yang:operation=\"delete\">\n"
+ " <name2>n22</name2>\n"
+ " <value2>26</value2>\n"
+ " </list2>\n"
+ " </list>\n"
+ "</df>\n");
+
+ lyd_free_all(data1);
+ lyd_free_all(data2);
+ lyd_free_all(diff);
+}
+
+static void
test_userord_llist(void **state)
{
(void) state;
@@ -940,6 +1068,118 @@ test_userord_list2(void **state)
}
static void
+test_userord_list3(void **state)
+{
+ (void) state;
+ const char *xml1 =
+ "<df xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <ul>\n"
+ " <l1>a</l1>\n"
+ " <l2>1</l2>\n"
+ " </ul>\n"
+ " <ul>\n"
+ " <l1>b</l1>\n"
+ " <l2>2</l2>\n"
+ " </ul>\n"
+ " <ul>\n"
+ " <l1>c</l1>\n"
+ " <cont>\n"
+ " <l3>val1</l3>\n"
+ " </cont>\n"
+ " </ul>\n"
+ " <ul>\n"
+ " <l1>d</l1>\n"
+ " <l2>4</l2>\n"
+ " </ul>\n"
+ "</df>\n";
+ const char *xml2 =
+ "<df xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <ul>\n"
+ " <l1>c</l1>\n"
+ " <l2>3</l2>\n"
+ " <cont>\n"
+ " <l3>val2</l3>\n"
+ " </cont>\n"
+ " </ul>\n"
+ " <ul>\n"
+ " <l1>a</l1>\n"
+ " <l2>1</l2>\n"
+ " </ul>\n"
+ " <ul>\n"
+ " <l1>d</l1>\n"
+ " <l2>44</l2>\n"
+ " </ul>\n"
+ " <ul>\n"
+ " <l1>b</l1>\n"
+ " <l2>2</l2>\n"
+ " </ul>\n"
+ "</df>\n";
+ const char *xml3 =
+ "<df xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <ul>\n"
+ " <l1>a</l1>\n"
+ " </ul>\n"
+ " <ul>\n"
+ " <l1>c</l1>\n"
+ " <l2>3</l2>\n"
+ " <cont>\n"
+ " <l3>val2</l3>\n"
+ " </cont>\n"
+ " </ul>\n"
+ " <ul>\n"
+ " <l1>d</l1>\n"
+ " <l2>44</l2>\n"
+ " </ul>\n"
+ " <ul>\n"
+ " <l1>b</l1>\n"
+ " <l2>2</l2>\n"
+ " </ul>\n"
+ "</df>\n";
+
+ const char *out_diff_1 =
+ "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">\n"
+ " <ul yang:operation=\"replace\" yang:key=\"\" yang:orig-key=\"[l1='b']\">\n"
+ " <l1>c</l1>\n"
+ " <l2 yang:operation=\"create\">3</l2>\n"
+ " <cont yang:operation=\"none\">\n"
+ " <l3 yang:operation=\"replace\" yang:orig-default=\"false\" yang:orig-value=\"val1\">val2</l3>\n"
+ " </cont>\n"
+ " </ul>\n"
+ " <ul yang:operation=\"replace\" yang:key=\"[l1='a']\" yang:orig-key=\"[l1='b']\">\n"
+ " <l1>d</l1>\n"
+ " <l2 yang:operation=\"replace\" yang:orig-default=\"false\" yang:orig-value=\"4\">44</l2>\n"
+ " </ul>\n"
+ "</df>\n";
+ const char *out_diff_2 =
+ "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">\n"
+ " <ul yang:operation=\"replace\" yang:key=\"\" yang:orig-key=\"[l1='c']\">\n"
+ " <l1>a</l1>\n"
+ " <l2 yang:operation=\"delete\">1</l2>\n"
+ " </ul>\n"
+ "</df>\n";
+ const char *out_merge =
+ "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">\n"
+ " <ul yang:operation=\"replace\" yang:key=\"\" yang:orig-key=\"[l1='b']\">\n"
+ " <l1>c</l1>\n"
+ " <l2 yang:operation=\"create\">3</l2>\n"
+ " <cont yang:operation=\"none\">\n"
+ " <l3 yang:operation=\"replace\" yang:orig-default=\"false\" yang:orig-value=\"val1\">val2</l3>\n"
+ " </cont>\n"
+ " </ul>\n"
+ " <ul yang:operation=\"replace\" yang:key=\"[l1='a']\" yang:orig-key=\"[l1='b']\">\n"
+ " <l1>d</l1>\n"
+ " <l2 yang:operation=\"replace\" yang:orig-default=\"false\" yang:orig-value=\"4\">44</l2>\n"
+ " </ul>\n"
+ " <ul yang:key=\"\" yang:orig-key=\"[l1='c']\" yang:operation=\"replace\">\n"
+ " <l1>a</l1>\n"
+ " <l2 yang:operation=\"delete\">1</l2>\n"
+ " </ul>\n"
+ "</df>\n";
+
+ TEST_DIFF_3(xml1, xml2, xml3, out_diff_1, out_diff_2, out_merge);
+}
+
+static void
test_keyless_list(void **state)
{
(void) state;
@@ -1207,11 +1447,13 @@ main(void)
UTEST(test_delete_merge, setup),
UTEST(test_leaf, setup),
UTEST(test_list, setup),
+ UTEST(test_nested_list, setup),
UTEST(test_userord_llist, setup),
UTEST(test_userord_llist2, setup),
UTEST(test_userord_mix, setup),
UTEST(test_userord_list, setup),
UTEST(test_userord_list2, setup),
+ UTEST(test_userord_list3, setup),
UTEST(test_keyless_list, setup),
UTEST(test_state_llist, setup),
UTEST(test_wd, setup),
diff --git a/tests/utests/data/test_new.c b/tests/utests/data/test_new.c
index 7642960..5cee903 100644
--- a/tests/utests/data/test_new.c
+++ b/tests/utests/data/test_new.c
@@ -55,6 +55,7 @@ const char *schema_a = "module a {\n"
" anydata any {\n"
" config false;\n"
" }\n"
+ " anyxml anyx;\n"
" leaf-list ll2 {\n"
" config false;\n"
" type string;\n"
@@ -128,6 +129,16 @@ test_top_level(void **state)
assert_int_equal(lyd_new_list2(NULL, mod, "l1", "[a= 'a']\n[b =\t'b']", 0, &node), LY_SUCCESS);
lyd_free_tree(node);
+ const char *key_vals[] = {"a", "b"};
+
+ assert_int_equal(lyd_new_list3(NULL, mod, "l1", key_vals, NULL, 0, &node), LY_SUCCESS);
+ lyd_free_tree(node);
+
+ uint32_t val_lens[] = {1, 1};
+
+ assert_int_equal(lyd_new_list3_bin(NULL, mod, "l1", (const void **)key_vals, val_lens, 0, &node), LY_SUCCESS);
+ lyd_free_tree(node);
+
/* leaf */
assert_int_equal(lyd_new_term(NULL, mod, "foo", "[a='a'][b='b'][c='c']", 0, &node), LY_EVALID);
CHECK_LOG_CTX("Invalid type uint16 value \"[a='a'][b='b'][c='c']\".", "Schema location \"/a:foo\".");
@@ -290,6 +301,7 @@ test_path(void **state)
ret = lyd_new_path2(root, NULL, "/a:c2/l3[1]", NULL, 0, 0, 0, NULL, &node);
assert_int_equal(ret, LY_EEXIST);
+ CHECK_LOG_CTX("Path \"/a:c2/l3[1]\" already exists.", "Data location \"/a:c2/l3[1]\".");
ret = lyd_new_path2(root, NULL, "/a:c2/l3[2]/x", "val2", 0, 0, 0, NULL, &node);
assert_int_equal(ret, LY_SUCCESS);
@@ -348,6 +360,7 @@ test_path(void **state)
ret = lyd_new_path2(root, NULL, "/a:ll2[1]", "", 0, 0, 0, NULL, &node);
assert_int_equal(ret, LY_EEXIST);
+ CHECK_LOG_CTX("Path \"/a:ll2[1]\" already exists.", "Data location \"/a:ll2[1]\".");
ret = lyd_new_path2(root, NULL, "/a:ll2[2]", "val2", 0, 0, 0, NULL, &node);
assert_int_equal(ret, LY_SUCCESS);
@@ -362,6 +375,7 @@ test_path(void **state)
ret = lyd_new_path2(root, NULL, "/a:ll2[3][.='val3']", NULL, 0, 0, 0, NULL, &node);
assert_int_equal(ret, LY_EVALID);
+ CHECK_LOG_CTX("Unparsed characters \"[.='val3']\" left at the end of path.", NULL);
lyd_print_mem(&str, root, LYD_XML, LYD_PRINT_WITHSIBLINGS);
assert_string_equal(str,
@@ -391,6 +405,55 @@ test_path(void **state)
"}\n");
free(str);
lyd_free_siblings(root);
+
+ /* anyxml */
+ ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:anyx", "<a/><b/><c/>", 0, LYD_ANYDATA_XML, 0, &root, NULL);
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_non_null(root);
+
+ lyd_print_mem(&str, root, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+ assert_string_equal(str,
+ "<anyx xmlns=\"urn:tests:a\">\n"
+ " <a/>\n"
+ " <b/>\n"
+ " <c/>\n"
+ "</anyx>\n");
+ free(str);
+ lyd_print_mem(&str, root, LYD_JSON, LYD_PRINT_WITHSIBLINGS);
+ assert_string_equal(str,
+ "{\n"
+ " \"a:anyx\": {\n"
+ " \"a\": [null],\n"
+ " \"b\": [null],\n"
+ " \"c\": [null]\n"
+ " }\n"
+ "}\n");
+ free(str);
+ lyd_free_siblings(root);
+
+ ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:anyx", "{\"a\":[null],\"b\":[null],\"c\":[null]}", 0, LYD_ANYDATA_JSON, 0, &root, NULL);
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_non_null(root);
+
+ lyd_print_mem(&str, root, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+ assert_string_equal(str,
+ "<anyx xmlns=\"urn:tests:a\">\n"
+ " <a/>\n"
+ " <b/>\n"
+ " <c/>\n"
+ "</anyx>\n");
+ free(str);
+ lyd_print_mem(&str, root, LYD_JSON, LYD_PRINT_WITHSIBLINGS);
+ assert_string_equal(str,
+ "{\n"
+ " \"a:anyx\": {\n"
+ " \"a\": [null],\n"
+ " \"b\": [null],\n"
+ " \"c\": [null]\n"
+ " }\n"
+ "}\n");
+ free(str);
+ lyd_free_siblings(root);
}
static void
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);
diff --git a/tests/utests/data/test_parser_xml.c b/tests/utests/data/test_parser_xml.c
index 7defd9c..4f33f00 100644
--- a/tests/utests/data/test_parser_xml.c
+++ b/tests/utests/data/test_parser_xml.c
@@ -31,6 +31,7 @@ setup(void **state)
" namespace urn:tests:a;\n"
" prefix a;\n"
" yang-version 1.1;\n"
+ " import ietf-yang-metadata {prefix md;}"
" list l1 { key \"a b c\"; leaf a {type string;} leaf b {type string;} leaf c {type int16;}"
" leaf d {type string;}"
" container cont {leaf e {type boolean;}}"
@@ -42,9 +43,12 @@ setup(void **state)
" notification n1 { leaf nl {type string;}}}\n"
" container cp {presence \"container switch\"; leaf y {type string;} leaf z {type int8;}}\n"
" anydata any {config false;}\n"
+ " anyxml anyx;\n"
" leaf foo2 { type string; default \"default-val\"; }\n"
" leaf foo3 { type uint32; }\n"
- " notification n2;}";
+ " notification n2;"
+ " md:annotation attr {type enumeration {enum val;}}"
+ "}";
UTEST_SETUP;
@@ -122,6 +126,7 @@ static void
test_anydata(void **state)
{
const char *data;
+ char *str;
struct lyd_node *tree;
data = "<any xmlns=\"urn:tests:a\">\n"
@@ -145,6 +150,49 @@ test_anydata(void **state)
"</any>\n";
CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data_expected);
+
+ assert_int_equal(LY_SUCCESS, lyd_any_value_str(tree, &str));
+ lyd_free_all(tree);
+
+ assert_int_equal(LY_SUCCESS, lyd_new_path2(NULL, UTEST_LYCTX, "/a:any", str, strlen(str), LYD_ANYDATA_XML, 0, &tree, NULL));
+ free(str);
+ CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data_expected);
+ lyd_free_all(tree);
+}
+
+static void
+test_anyxml(void **state)
+{
+ const char *data;
+ char *str;
+ struct lyd_node *tree;
+
+ data = "<anyx xmlns=\"urn:tests:a\">\n"
+ " <element1>\n"
+ " <element2 x:attr2=\"test\" xmlns:x=\"urn:x\">data</element2>\n"
+ " </element1>\n"
+ " <element1a/>\n"
+ "</anyx>\n";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ assert_non_null(tree);
+ tree = tree->next;
+
+ const char *data_expected =
+ "<anyx xmlns=\"urn:tests:a\">\n"
+ " <element1>\n"
+ " <element2 xmlns:x=\"urn:x\" x:attr2=\"test\">data</element2>\n"
+ " </element1>\n"
+ " <element1a/>\n"
+ "</anyx>\n";
+
+ CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data_expected);
+
+ assert_int_equal(LY_SUCCESS, lyd_any_value_str(tree, &str));
+ lyd_free_all(tree);
+
+ assert_int_equal(LY_SUCCESS, lyd_new_path2(NULL, UTEST_LYCTX, "/a:anyx", str, strlen(str), LYD_ANYDATA_XML, 0, &tree, NULL));
+ free(str);
+ CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data_expected);
lyd_free_all(tree);
}
@@ -170,17 +218,21 @@ test_list(void **state)
/* missing keys */
PARSER_CHECK_ERROR("<l1 xmlns=\"urn:tests:a\"><c>1</c><b>b</b></l1>", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"List instance is missing its key \"a\".", "Data location \"/a:l1[b='b'][c='1']\", line number 1.");
+ CHECK_LOG_CTX("Invalid position of the key \"b\" in a list.", NULL);
PARSER_CHECK_ERROR("<l1 xmlns=\"urn:tests:a\"><a>a</a></l1>", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"List instance is missing its key \"b\".", "Data location \"/a:l1[a='a']\", line number 1.");
PARSER_CHECK_ERROR("<l1 xmlns=\"urn:tests:a\"><b>b</b><a>a</a></l1>", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"List instance is missing its key \"c\".", "Data location \"/a:l1[a='a'][b='b']\", line number 1.");
+ CHECK_LOG_CTX("Invalid position of the key \"a\" in a list.", NULL);
/* key duplicate */
PARSER_CHECK_ERROR("<l1 xmlns=\"urn:tests:a\"><c>1</c><b>b</b><a>a</a><c>1</c></l1>", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"Duplicate instance of \"c\".",
"Data location \"/a:l1[a='a'][b='b'][c='1'][c='1']/c\", line number 1.");
+ CHECK_LOG_CTX("Invalid position of the key \"a\" in a list.", NULL);
+ CHECK_LOG_CTX("Invalid position of the key \"b\" in a list.", NULL);
/* keys order */
CHECK_PARSE_LYD("<l1 xmlns=\"urn:tests:a\"><d>d</d><a>a</a><c>1</c><b>b</b></l1>", 0, LYD_VALIDATE_PRESENT, tree);
@@ -209,6 +261,7 @@ 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 | LYS_KEY, 1, "c", 1, LYS_LEAF, 1, 0, NULL, 0);
CHECK_LOG_CTX("Invalid position of the key \"a\" in a list.", NULL);
+ CHECK_LOG_CTX("Invalid position of the key \"b\" in a list.", NULL);
lyd_free_all(tree);
PARSER_CHECK_ERROR(data, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
@@ -250,14 +303,14 @@ test_opaq(void **state)
/* opaq flag */
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_XML, "foo3", 0, 0, NULL, 0, "");
+ CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 0, 0, LY_VALUE_XML, "foo3", 0, 0, NULL, 1, "");
CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, "<foo3 xmlns=\"urn:tests:a\"/>\n");
lyd_free_all(tree);
/* list, opaq flag */
data = "<l1 xmlns=\"urn:tests:a\"/>";
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_XML, "l1", 0, 0, NULL, 0, "");
+ CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 0, 0, LY_VALUE_XML, "l1", 0, 0, NULL, 1, "");
CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, "<l1 xmlns=\"urn:tests:a\"/>\n");
lyd_free_all(tree);
@@ -273,7 +326,7 @@ test_opaq(void **state)
/* opaq flag */
CHECK_PARSE_LYD(data, LYD_PARSE_OPAQ | LYD_PARSE_ONLY, 0, tree);
- CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 0, 0x1, LY_VALUE_XML, "l1", 0, 0, NULL, 0, "");
+ CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 0, 0x1, LY_VALUE_XML, "l1", 0, 0, NULL, 1, "");
CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
@@ -289,7 +342,7 @@ test_opaq(void **state)
/* opaq flag */
CHECK_PARSE_LYD(data, LYD_PARSE_OPAQ | LYD_PARSE_ONLY, 0, tree);
- CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 0, 0x1, LY_VALUE_XML, "l1", 0, 0, NULL, 0, "");
+ CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 0, 0x1, LY_VALUE_XML, "l1", 0, 0, NULL, 1, "");
CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
@@ -300,7 +353,7 @@ test_opaq(void **state)
" <c xmld:id=\"D\">1</c>\n"
"</a>\n",
LYD_XML, LYD_PARSE_OPAQ, LYD_VALIDATE_PRESENT, &tree));
- CHECK_LOG_CTX("Unknown XML prefix \"xmld\".", "Line number 3.");
+ CHECK_LOG_CTX("Unknown XML prefix \"xmld\".", "Data location \"/a\", line number 3.");
}
static void
@@ -358,10 +411,10 @@ test_rpc(void **state)
node = lyd_child(node);
/* z has no value */
- CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)node, 0x1, 0, LY_VALUE_XML, "z", 0, 0, NULL, 0, "");
+ CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)node, 0x1, 0, LY_VALUE_XML, "z", 0, 0, NULL, 1, "");
node = node->parent->next;
/* l1 key c has invalid value so it is at the end */
- CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)node, 0x1, 0x1, LY_VALUE_XML, "l1", 0, 0, NULL, 0, "");
+ CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)node, 0x1, 0x1, LY_VALUE_XML, "l1", 0, 0, NULL, 1, "");
CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS,
"<edit-config xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
@@ -554,10 +607,10 @@ test_netconf_rpc(void **state)
node = lyd_child(node);
/* z has no value */
- CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)node, 0x1, 0, LY_VALUE_XML, "z", 0, 0, NULL, 0, "");
+ CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)node, 0x1, 0, LY_VALUE_XML, "z", 0, 0, NULL, 1, "");
node = node->parent->next;
/* l1 key c has invalid value so it is at the end */
- CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)node, 0x1, 0x1, LY_VALUE_XML, "l1", 0, 0, NULL, 0, "");
+ CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)node, 0x1, 0x1, LY_VALUE_XML, "l1", 0, 0, NULL, 1, "");
CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS,
"<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" message-id=\"25\"/>\n");
@@ -581,8 +634,33 @@ test_netconf_rpc(void **state)
lyd_free_all(tree);
lyd_free_all(op);
- /* wrong namespace, element name, whatever... */
- /* TODO */
+ /* invalid anyxml nested metadata value */
+ data = "<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" message-id=\"1\" pid=\"4114692032\">\n"
+ " <copy-config>\n"
+ " <target>\n"
+ " <running/>\n"
+ " </target>\n"
+ " <source>\n"
+ " <config>\n"
+ " <l1 xmlns=\"urn:tests:a\" xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
+ " <a>val_a</a>\n"
+ " <b>val_b</b>\n"
+ " <c>5</c>\n"
+ " <cont nc:operation=\"merge\">\n"
+ " <e nc:operation=\"merge2\">false</e>\n"
+ " </cont>\n"
+ " </l1>\n"
+ " </config>\n"
+ " </source>\n"
+ " </copy-config>\n"
+ "</rpc>\n";
+ assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
+ assert_int_equal(LY_EVALID, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_XML, LYD_TYPE_RPC_NETCONF, &tree, &op));
+ ly_in_free(in, 0);
+ CHECK_LOG_CTX("Invalid enumeration value \"merge2\".",
+ "Path \"/ietf-netconf:copy-config/source/config/a:l1[a='val_a'][b='val_b'][c='5']/cont/e/@ietf-netconf:operation\", line number 13.");
+ lyd_free_all(tree);
+ assert_null(op);
}
static void
@@ -678,6 +756,22 @@ test_netconf_reply_or_notification(void **state)
lyd_free_all(tree);
lyd_free_all(op2);
+ /* notification with a different order */
+ data = "<notification xmlns=\"urn:ietf:params:xml:ns:netconf:notification:1.0\">\n"
+ "<c xmlns=\"urn:tests:a\">\n"
+ " <n1>\n"
+ " <nl>value</nl>\n"
+ " </n1>\n"
+ "</c>\n"
+ "<eventTime>2010-12-06T08:00:01Z</eventTime>\n"
+ "</notification>\n";
+ assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
+ assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_XML, LYD_TYPE_NOTIF_NETCONF, &tree, &op2));
+ ly_in_free(in, 0);
+
+ lyd_free_all(tree);
+ lyd_free_all(op2);
+
/* parse a data reply */
data = "<rpc-reply message-id=\"55\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
" <al xmlns=\"urn:tests:a\">25</al>\n"
@@ -739,6 +833,64 @@ test_netconf_reply_or_notification(void **state)
}
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 = "<input xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-nmda\">"
+ "<datastore xmlns:ds=\"urn:ietf:params:xml:ns:yang:ietf-datastores\">ds:running</datastore>"
+ "<config>"
+ "<cp xmlns=\"urn:tests:a\"><z xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\" nc:operation=\"replace\"/></cp>"
+ "<l1 xmlns=\"urn:tests:a\" xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\" nc:operation=\"replace\">"
+ "<a>val_a</a><b>val_b</b><c>val_c</c>"
+ "</l1>"
+ "</config></input>";
+ assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
+ assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, tree, in, LYD_XML, LYD_TYPE_RPC_RESTCONF, &envp, NULL));
+ ly_in_free(in, 0);
+
+ /* the same just connected to the edit-data RPC */
+ data = "<edit-data xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-nmda\">"
+ "<datastore xmlns:ds=\"urn:ietf:params:xml:ns:yang:ietf-datastores\">ds:running</datastore>"
+ "<config>"
+ "<cp xmlns=\"urn:tests:a\"><z xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\" nc:operation=\"replace\"/></cp>"
+ "<l1 xmlns=\"urn:tests:a\" xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\" nc:operation=\"replace\">"
+ "<a>val_a</a><b>val_b</b><c>val_c</c>"
+ "</l1>"
+ "</config></edit-data>";
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+ lyd_free_all(envp);
+}
+
+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 = "<output xmlns=\"urn:tests:a\"><al>25</al></output>";
+ 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_XML, LYD_TYPE_REPLY_RESTCONF, &envp, NULL));
+ ly_in_free(in, 0);
+
+ /* connected to the RPC with the parent */
+ data = "<c xmlns=\"urn:tests:a\"><act><al>25</al></act></c>";
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+ lyd_free_all(envp);
+}
+
+static void
test_filter_attributes(void **state)
{
const char *data;
@@ -812,12 +964,58 @@ test_data_skip(void **state)
lyd_free_all(tree);
}
+static void
+test_metadata(void **state)
+{
+ const char *data;
+ struct lyd_node *tree;
+
+ /* invalid metadata value */
+ data = "<c xmlns=\"urn:tests:a\" xmlns:a=\"urn:tests:a\"><x a:attr=\"value\">xval</x></c>";
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(_UC->ctx, data, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
+ assert_null(tree);
+ CHECK_LOG_CTX("Invalid enumeration value \"value\".", "Path \"/a:c/x/@a:attr\", line number 1.");
+}
+
+static void
+test_subtree(void **state)
+{
+ const char *data;
+ struct ly_in *in;
+ struct lyd_node *tree;
+
+ /* prepare data with the parent */
+ data = "<l1 xmlns=\"urn:tests:a\">\n"
+ " <a>val_a</a>\n"
+ " <b>val_b</b>\n"
+ " <c>1</c>\n"
+ "</l1>\n";
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
+
+ /* parse a subtree of it */
+ data = "<cont xmlns=\"urn:tests:a\">\n"
+ " <e>true</e>\n"
+ "</cont>\n";
+ assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
+ assert_int_equal(LY_SUCCESS, lyd_parse_data(UTEST_LYCTX, tree, in, LYD_XML, 0, LYD_VALIDATE_PRESENT, NULL));
+ ly_in_free(in, 0);
+
+ /* parse another container, fails */
+ assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
+ assert_int_equal(LY_EVALID, lyd_parse_data(UTEST_LYCTX, tree, in, LYD_XML, 0, LYD_VALIDATE_PRESENT, NULL));
+ ly_in_free(in, 0);
+ CHECK_LOG_CTX("Duplicate instance of \"cont\".", "Data location \"/a:l1[a='val_a'][b='val_b'][c='1']/cont\".");
+
+ lyd_free_all(tree);
+}
+
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_leaf, setup),
UTEST(test_anydata, setup),
+ UTEST(test_anyxml, setup),
UTEST(test_list, setup),
UTEST(test_container, setup),
UTEST(test_opaq, setup),
@@ -828,8 +1026,12 @@ main(void)
UTEST(test_netconf_rpc, setup),
UTEST(test_netconf_action, setup),
UTEST(test_netconf_reply_or_notification, setup),
+ UTEST(test_restconf_rpc, setup),
+ UTEST(test_restconf_reply, setup),
UTEST(test_filter_attributes, setup),
UTEST(test_data_skip, setup),
+ UTEST(test_metadata, setup),
+ UTEST(test_subtree, setup),
};
return cmocka_run_group_tests(tests, NULL, NULL);
diff --git a/tests/utests/data/test_printer_xml.c b/tests/utests/data/test_printer_xml.c
index d533c41..6213a37 100644
--- a/tests/utests/data/test_printer_xml.c
+++ b/tests/utests/data/test_printer_xml.c
@@ -145,7 +145,8 @@ test_anydata(void **state)
" <cont>\n"
" <elem1 xmlns=\"urn:tests:defs\">\n"
" <elem2 xmlns=\"urn:tests:types\" xmlns:defs=\"urn:tests:defs\" xmlns:defaults=\"urn:defaults\" "
- "defs:attr1=\"defaults:val\" attr2=\"/defaults:node/defs:node2\"/>\n"
+ "defs:attr1=\"defaults:val\" attr2=\"/defaults:node/defs:node2\">\n"
+ " </elem2>\n"
" </elem1>\n"
" </cont>\n"
"</any>\n";
diff --git a/tests/utests/data/test_tree_data.c b/tests/utests/data/test_tree_data.c
index 27dba42..494fdf3 100644
--- a/tests/utests/data/test_tree_data.c
+++ b/tests/utests/data/test_tree_data.c
@@ -1,9 +1,9 @@
/**
* @file test_tree_data.c
- * @author: Radek Krejci <rkrejci@cesnet.cz>
- * @brief unit tests for functions from tress_data.c
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief unit tests for functions from tree_data.c
*
- * Copyright (c) 2018-2019 CESNET, z.s.p.o.
+ * Copyright (c) 2018-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.
@@ -100,7 +100,7 @@ test_compare(void **state)
data2 = "<l2 xmlns=\"urn:tests:a\"><c><x>b</x></c></l2>";
CHECK_PARSE_LYD(data1, 0, LYD_VALIDATE_PRESENT, tree1);
CHECK_PARSE_LYD(data2, 0, LYD_VALIDATE_PRESENT, tree2);
- assert_int_equal(LY_ENOT, lyd_compare_single(tree1->next, tree2->next, 0));
+ assert_int_equal(LY_ENOT, lyd_compare_single(tree1->next, tree2->next, LYD_COMPARE_FULL_RECURSION));
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1->next->next, tree2->next, 0));
lyd_free_all(tree1);
lyd_free_all(tree2);
@@ -145,6 +145,14 @@ test_compare(void **state)
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, 0));
lyd_free_all(tree1);
lyd_free_all(tree2);
+
+ data1 = "<c xmlns=\"urn:tests:a\"><x>c</x><x>a</x><x>b</x></c>";
+ data2 = "<c xmlns=\"urn:tests:a\"><x>a</x><x>b</x><x>c</x></c>";
+ CHECK_PARSE_LYD(data1, 0, LYD_VALIDATE_PRESENT, tree1);
+ CHECK_PARSE_LYD(data2, 0, LYD_VALIDATE_PRESENT, tree2);
+ assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, LYD_COMPARE_FULL_RECURSION));
+ lyd_free_all(tree1);
+ lyd_free_all(tree2);
}
static void
@@ -196,7 +204,7 @@ test_compare_diff_ctx(void **state)
data2 = "<l2 xmlns=\"urn:tests:b\"><c><x>b</x></c></l2>";
CHECK_PARSE_LYD_PARAM_CTX(UTEST_LYCTX, data1, 0, tree1);
CHECK_PARSE_LYD_PARAM_CTX(ctx2, data2, 0, tree2);
- assert_int_equal(LY_ENOT, lyd_compare_single(tree1, tree2, 0));
+ assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, 0));
lyd_free_all(tree1);
lyd_free_all(tree2);
@@ -210,7 +218,7 @@ test_compare_diff_ctx(void **state)
data2 = "<l2 xmlns=\"urn:tests:b\"><c><x>b</x></c></l2>";
CHECK_PARSE_LYD_PARAM_CTX(UTEST_LYCTX, data1, 0, tree1);
CHECK_PARSE_LYD_PARAM_CTX(ctx2, data2, 0, tree2);
- assert_int_equal(LY_ENOT, lyd_compare_single(tree1, tree2, 0));
+ assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, 0));
lyd_free_all(tree1);
lyd_free_all(tree2);
@@ -329,8 +337,7 @@ test_dup(void **state)
data = "<l2 xmlns=\"urn:tests:a\"><c><x>b</x></c></l2>";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree1);
- assert_int_equal(LY_SUCCESS, lyd_dup_single(((struct lyd_node_inner *)((struct lyd_node_inner *)tree1->next)->child)->child, NULL,
- LYD_DUP_WITH_PARENTS, &tree2));
+ assert_int_equal(LY_SUCCESS, lyd_dup_single(lyd_child(lyd_child(tree1->next)), NULL, LYD_DUP_WITH_PARENTS, &tree2));
int unsigned flag = LYS_CONFIG_R | LYS_SET_ENUM;
CHECK_LYSC_NODE(tree2->schema, NULL, 0, flag, 1, "x", 1, LYS_LEAF, 1, 0, NULL, 0);
@@ -352,8 +359,8 @@ test_dup(void **state)
data = "<l2 xmlns=\"urn:tests:a\"><c><x>b</x></c></l2>";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree1);
assert_int_equal(LY_SUCCESS, lyd_dup_single(tree1->next, NULL, 0, &tree2));
- assert_int_equal(LY_SUCCESS, lyd_dup_single(((struct lyd_node_inner *)((struct lyd_node_inner *)tree1->next)->child)->child,
- (struct lyd_node_inner *)tree2, LYD_DUP_WITH_PARENTS, NULL));
+ assert_int_equal(LY_SUCCESS, lyd_dup_single(lyd_child(lyd_child(tree1->next)), (struct lyd_node_inner *)tree2,
+ LYD_DUP_WITH_PARENTS, NULL));
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1->next, tree2, LYD_COMPARE_FULL_RECURSION));
lyd_free_all(tree1);
lyd_free_all(tree2);
@@ -363,6 +370,8 @@ test_dup(void **state)
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree1);
assert_int_equal(LY_EINVAL, lyd_dup_single(((struct lyd_node_inner *)tree1)->child->prev,
(struct lyd_node_inner *)tree1->next, LYD_DUP_WITH_PARENTS, NULL));
+ CHECK_LOG_CTX("None of the duplicated node \"c\" schema parents match the provided parent \"c\".",
+ NULL);
lyd_free_all(tree1);
}
@@ -488,6 +497,11 @@ test_find_path(void **state)
assert_int_equal(LY_SUCCESS, lyd_find_path(root, "/c:cont/nexthop[gateway='10.0.0.1']", 0, NULL));
assert_int_equal(LY_SUCCESS, lyd_find_path(root, "/c:cont/nexthop[gateway='2100::1']", 0, NULL));
assert_int_equal(LY_SUCCESS, lyd_find_path(root, "/c:cont/pref[.='fc00::/64']", 0, NULL));
+
+ assert_int_equal(LY_EVALID, lyd_find_path(root, "/cont", 0, NULL));
+ CHECK_LOG_CTX("Prefix missing for \"cont\" in path.", "Schema location \"/c:cont\".");
+ assert_int_equal(LY_SUCCESS, lyd_find_path(root, "nexthop[gateway='2100::1']", 0, NULL));
+
lyd_free_all(root);
}
@@ -525,6 +539,7 @@ test_data_hash(void **state)
/* The run must not crash due to the assert that checks the hash. */
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
+ CHECK_LOG_CTX("Duplicate instance of \"ll\".", "Data location \"/test-data-hash:c/ll[.='']\", line number 1.");
lyd_free_all(tree);
}
diff --git a/tests/utests/data/test_validation.c b/tests/utests/data/test_validation.c
index 415e16a..d0dcae5 100644
--- a/tests/utests/data/test_validation.c
+++ b/tests/utests/data/test_validation.c
@@ -1154,6 +1154,92 @@ test_must(void **state)
CHECK_LOG_CTX_APPTAG("l leaf is not left", "Data location \"/i:cont/l3\".", "not-left");
}
+static void
+test_multi_error(void **state)
+{
+ struct lyd_node *tree;
+ const char *schema =
+ "module ii {\n"
+ " namespace urn:tests:ii;\n"
+ " prefix ii;\n"
+ " yang-version 1.1;\n"
+ "\n"
+ " container cont {\n"
+ " leaf l {\n"
+ " type string;\n"
+ " }\n"
+ " leaf l2 {\n"
+ " must \"../l = 'right'\";\n"
+ " type string;\n"
+ " }\n"
+ " leaf l3 {\n"
+ " must \"../l = 'left'\" {\n"
+ " error-app-tag \"not-left\";\n"
+ " error-message \"l leaf is not left\";\n"
+ " }\n"
+ " type string;\n"
+ " }\n"
+ " leaf-list ll {\n"
+ " type uint32;\n"
+ " min-elements 2;\n"
+ " }\n"
+ " }\n"
+ "}";
+ const char *data;
+
+ UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
+
+ /* xml */
+ data =
+ "<cont xmlns=\"urn:tests:ii\">\n"
+ " <l>wrong</l>\n"
+ " <l>wrong2</l>\n"
+ " <l2>val</l2>\n"
+ " <l3>val</l3>\n"
+ " <ll>ahoy</ll>\n"
+ "</cont>\n";
+ CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT | LYD_VALIDATE_MULTI_ERROR, LY_EVALID, tree);
+ CHECK_LOG_CTX_APPTAG("Too few \"ll\" instances.", "Schema location \"/ii:cont/ll\".", "too-few-elements");
+ CHECK_LOG_CTX_APPTAG("l leaf is not left", "Data location \"/ii:cont/l3\".", "not-left");
+ CHECK_LOG_CTX_APPTAG("Must condition \"../l = 'right'\" not satisfied.", "Data location \"/ii:cont/l2\".", "must-violation");
+ CHECK_LOG_CTX_APPTAG("Invalid type uint32 value \"ahoy\".", "Data location \"/ii:cont/ll\", line number 6.", NULL);
+
+ /* json */
+ data = "{\n"
+ " \"ii:cont\": {\n"
+ " \"l\": \"wrong\",\n"
+ " \"l\": \"wrong2\",\n"
+ " \"l2\": \"val\",\n"
+ " \"l3\": \"val\",\n"
+ " \"ll\": [\"ahoy\"]\n"
+ " }\n"
+ "}\n";
+ CHECK_PARSE_LYD_PARAM(data, LYD_JSON, 0, LYD_VALIDATE_PRESENT | LYD_VALIDATE_MULTI_ERROR, LY_EVALID, tree);
+ CHECK_LOG_CTX_APPTAG("Too few \"ll\" instances.", "Schema location \"/ii:cont/ll\".", "too-few-elements");
+ CHECK_LOG_CTX_APPTAG("l leaf is not left", "Data location \"/ii:cont/l3\".", "not-left");
+ CHECK_LOG_CTX_APPTAG("Must condition \"../l = 'right'\" not satisfied.", "Data location \"/ii:cont/l2\".", "must-violation");
+ CHECK_LOG_CTX_APPTAG("Invalid non-number-encoded uint32 value \"ahoy\".", "Data location \"/ii:cont/ll\", line number 7.", NULL);
+
+ /* validation */
+ data = "{\n"
+ " \"ii:cont\": {\n"
+ " \"l\": \"wrong\",\n"
+ " \"l\": \"wrong2\",\n"
+ " \"l2\": \"val\",\n"
+ " \"l3\": \"val\",\n"
+ " \"ll\": [25]\n"
+ " }\n"
+ "}\n";
+ CHECK_PARSE_LYD_PARAM(data, LYD_JSON, LYD_PARSE_ONLY, 0, LY_SUCCESS, tree);
+ assert_int_equal(LY_EVALID, lyd_validate_all(&tree, NULL, LYD_VALIDATE_PRESENT | LYD_VALIDATE_MULTI_ERROR, NULL));
+ lyd_free_tree(tree);
+ CHECK_LOG_CTX_APPTAG("Too few \"ll\" instances.", "Schema location \"/ii:cont/ll\".", "too-few-elements");
+ CHECK_LOG_CTX_APPTAG("l leaf is not left", "Data location \"/ii:cont/l3\".", "not-left");
+ CHECK_LOG_CTX_APPTAG("Must condition \"../l = 'right'\" not satisfied.", "Data location \"/ii:cont/l2\".", "must-violation");
+ CHECK_LOG_CTX_APPTAG("Duplicate instance of \"l\".", "Data location \"/ii:cont/l\".", NULL);
+ CHECK_LOG_CTX_APPTAG("Duplicate instance of \"l\".", "Data location \"/ii:cont/l\".", NULL);
+}
+
const char *schema_j =
"module j {\n"
" namespace urn:tests:j;\n"
@@ -1212,6 +1298,7 @@ test_action(void **state)
struct lyd_node *tree, *op_tree;
UTEST_ADD_MODULE(schema_j, LYS_IN_YANG, feats_j, NULL);
+ UTEST_LOG_CTX_CLEAN;
assert_int_equal(LY_SUCCESS, ly_in_new_memory(
"<cont xmlns=\"urn:tests:j\">\n"
@@ -1304,6 +1391,7 @@ test_reply(void **state)
struct lyd_node *tree, *op_tree;
UTEST_ADD_MODULE(schema_j, LYS_IN_YANG, feats_j, NULL);
+ UTEST_LOG_CTX_CLEAN;
assert_int_equal(LY_SUCCESS, ly_in_new_memory(
"<cont xmlns=\"urn:tests:j\">\n"
@@ -1422,7 +1510,7 @@ test_case(void **state)
" }\n"
"}\n", LYD_JSON, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
CHECK_LOG_CTX("Data for both cases \"v0\" and \"v2\" exist.",
- "Data location \"/k:ch\", line number 5.");
+ "Data location \"/k:ch\", line number 6.");
CHECK_PARSE_LYD_PARAM(
"{\n"
@@ -1432,7 +1520,7 @@ test_case(void **state)
" }\n"
"}\n", LYD_JSON, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
CHECK_LOG_CTX("Data for both cases \"v0\" and \"v2\" exist.",
- "Data location \"/k:ch\", line number 5.");
+ "Data location \"/k:ch\", line number 6.");
}
int
@@ -1450,6 +1538,7 @@ main(void)
UTEST(test_defaults),
UTEST(test_state),
UTEST(test_must),
+ UTEST(test_multi_error),
UTEST(test_action),
UTEST(test_rpc),
UTEST(test_reply),