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.c1221
-rw-r--r--tests/utests/data/test_lyb.c2841
-rw-r--r--tests/utests/data/test_merge.c756
-rw-r--r--tests/utests/data/test_new.c446
-rw-r--r--tests/utests/data/test_parser_json.c793
-rw-r--r--tests/utests/data/test_parser_xml.c836
-rw-r--r--tests/utests/data/test_printer_xml.c343
-rw-r--r--tests/utests/data/test_tree_data.c597
-rw-r--r--tests/utests/data/test_validation.c1460
9 files changed, 9293 insertions, 0 deletions
diff --git a/tests/utests/data/test_diff.c b/tests/utests/data/test_diff.c
new file mode 100644
index 0000000..1b7592a
--- /dev/null
+++ b/tests/utests/data/test_diff.c
@@ -0,0 +1,1221 @@
+/**
+ * @file test_diff.c
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @author Michal Vasko <mvasko@cesnet.cz>
+ * @brief tests for lyd_diff()
+ *
+ * Copyright (c) 2020 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.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ */
+#define _UTEST_MAIN_
+#include "utests.h"
+
+#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_LYD_STRING(IN_MODEL, TEXT) \
+ CHECK_LYD_STRING_PARAM(IN_MODEL, 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 TEST_DIFF_3(XML1, XML2, XML3, DIFF1, DIFF2, MERGE) \
+ { \
+ struct lyd_node *data1;\
+ struct lyd_node *data2;\
+ struct lyd_node *data3;\
+ /*create*/\
+ CHECK_PARSE_LYD(XML1, data1);\
+ CHECK_PARSE_LYD(XML2, data2);\
+ CHECK_PARSE_LYD(XML3, data3);\
+ /* diff1 */ \
+ struct lyd_node *diff1;\
+ CHECK_PARSE_LYD_DIFF(data1, data2, diff1); \
+ CHECK_LYD_STRING(diff1, DIFF1); \
+ assert_int_equal(lyd_diff_apply_all(&data1, diff1), LY_SUCCESS); \
+ CHECK_LYD(data1, data2); \
+ /* diff2 */ \
+ struct lyd_node *diff2;\
+ CHECK_PARSE_LYD_DIFF(data2, data3, diff2); \
+ CHECK_LYD_STRING(diff2, DIFF2); \
+ assert_int_equal(lyd_diff_apply_all(&data2, diff2), LY_SUCCESS);\
+ CHECK_LYD(data2, data3);\
+ /* merge */ \
+ assert_int_equal(lyd_diff_merge_all(&diff1, diff2, 0), LY_SUCCESS);\
+ CHECK_LYD_STRING(diff1, MERGE); \
+ /* cleanup */ \
+ lyd_free_all(data1);\
+ lyd_free_all(data2);\
+ lyd_free_all(data3);\
+ lyd_free_all(diff1);\
+ lyd_free_all(diff2);\
+ }
+
+const char *schema1 =
+ "module defaults {\n"
+ " yang-version 1.1;\n"
+ " namespace \"urn:libyang:tests:defaults\";\n"
+ " prefix df;\n"
+ ""
+ " feature unhide;\n"
+ ""
+ " typedef defint32 {\n"
+ " type int32;\n"
+ " default \"42\";\n"
+ " }\n"
+ ""
+ " leaf hiddenleaf {\n"
+ " if-feature \"unhide\";\n"
+ " type int32;\n"
+ " default \"42\";\n"
+ " }\n"
+ ""
+ " container df {\n"
+ " leaf foo {\n"
+ " type defint32;\n"
+ " }\n"
+ ""
+ " leaf hiddenleaf {\n"
+ " if-feature \"unhide\";\n"
+ " type int32;\n"
+ " default \"42\";\n"
+ " }\n"
+ ""
+ " container bar {\n"
+ " presence \"\";\n"
+ " leaf hi {\n"
+ " type int32;\n"
+ " default \"42\";\n"
+ " }\n"
+ ""
+ " leaf ho {\n"
+ " type int32;\n"
+ " mandatory true;\n"
+ " }\n"
+ " }\n"
+ ""
+ " leaf-list llist {\n"
+ " type defint32;\n"
+ " ordered-by user;\n"
+ " }\n"
+ ""
+ " list ul {\n"
+ " key \"l1\";\n"
+ " ordered-by user;\n"
+ " leaf l1 {\n"
+ " type string;\n"
+ " }\n"
+ ""
+ " leaf l2 {\n"
+ " type int32;\n"
+ " }\n"
+ " }\n"
+ ""
+ " leaf-list dllist {\n"
+ " type uint8;\n"
+ " default \"1\";\n"
+ " default \"2\";\n"
+ " default \"3\";\n"
+ " }\n"
+ ""
+ " list list {\n"
+ " key \"name\";\n"
+ " leaf name {\n"
+ " type string;\n"
+ " }\n"
+ ""
+ " leaf value {\n"
+ " type int32;\n"
+ " default \"42\";\n"
+ " }\n"
+ " list list2 {\n"
+ " key \"name2\";\n"
+ " leaf name2 {\n"
+ " type string;\n"
+ " }\n"
+ " leaf value2 {\n"
+ " type int32;\n"
+ " }\n"
+ " }\n"
+ " }\n";
+const char *schema2 =
+ " choice select {\n"
+ " default \"a\";\n"
+ " case a {\n"
+ " choice a {\n"
+ " leaf a1 {\n"
+ " type int32;\n"
+ " default \"42\";\n"
+ " }\n"
+ ""
+ " leaf a2 {\n"
+ " type int32;\n"
+ " default \"24\";\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ ""
+ " leaf b {\n"
+ " type string;\n"
+ " }\n"
+ ""
+ " container c {\n"
+ " presence \"\";\n"
+ " leaf x {\n"
+ " type int32;\n"
+ " default \"42\";\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ ""
+ " choice select2 {\n"
+ " default \"s2b\";\n"
+ " leaf s2a {\n"
+ " type int32;\n"
+ " default \"42\";\n"
+ " }\n"
+ ""
+ " case s2b {\n"
+ " choice s2b {\n"
+ " default \"b1\";\n"
+ " case b1 {\n"
+ " leaf b1_1 {\n"
+ " type int32;\n"
+ " default \"42\";\n"
+ " }\n"
+ ""
+ " leaf b1_2 {\n"
+ " type string;\n"
+ " }\n"
+ ""
+ " leaf b1_status {\n"
+ " type int32;\n"
+ " default \"42\";\n"
+ " config false;\n"
+ " }\n"
+ " }\n"
+ ""
+ " leaf b2 {\n"
+ " type int32;\n"
+ " default \"42\";\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " list kl {\n"
+ " config \"false\";\n"
+ " leaf l1 {\n"
+ " type string;\n"
+ " }\n"
+ ""
+ " leaf l2 {\n"
+ " type int32;\n"
+ " }\n"
+ " }\n"
+ ""
+ " leaf-list kll {\n"
+ " config \"false\";\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ ""
+ " container hidden {\n"
+ " leaf foo {\n"
+ " type int32;\n"
+ " default \"42\";\n"
+ " }\n"
+ ""
+ " leaf baz {\n"
+ " type int32;\n"
+ " default \"42\";\n"
+ " }\n"
+ ""
+ " leaf papa {\n"
+ " type int32;\n"
+ " default \"42\";\n"
+ " config false;\n"
+ " }\n"
+ " }\n"
+ ""
+ " rpc rpc1 {\n"
+ " input {\n"
+ " leaf inleaf1 {\n"
+ " type string;\n"
+ " }\n"
+ ""
+ " leaf inleaf2 {\n"
+ " type string;\n"
+ " default \"def1\";\n"
+ " }\n"
+ " }\n"
+ ""
+ " output {\n"
+ " leaf outleaf1 {\n"
+ " type string;\n"
+ " default \"def2\";\n"
+ " }\n"
+ ""
+ " leaf outleaf2 {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ ""
+ " notification notif {\n"
+ " leaf ntfleaf1 {\n"
+ " type string;\n"
+ " default \"def3\";\n"
+ " }\n"
+ ""
+ " leaf ntfleaf2 {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ "}\n";
+
+static int
+setup(void **state)
+{
+ char *schema;
+
+ UTEST_SETUP;
+
+ /* create one schema, longer than 4095 chars */
+ schema = malloc(strlen(schema1) + strlen(schema2) + 1);
+ strcpy(schema, schema1);
+ strcat(schema, schema2);
+
+ UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
+ free(schema);
+
+ return 0;
+}
+
+static void
+test_invalid(void **state)
+{
+ (void) state;
+ const char *xml = "<df xmlns=\"urn:libyang:tests:defaults\"><foo>42</foo></df>";
+
+ struct lyd_node *model_1;
+
+ CHECK_PARSE_LYD(xml, model_1);
+
+ struct lyd_node *diff = NULL;
+
+ assert_int_equal(lyd_diff_siblings(model_1, lyd_child(model_1), 0, &diff), LY_EINVAL);
+ assert_int_equal(lyd_diff_siblings(NULL, NULL, 0, NULL), LY_EINVAL);
+
+ lyd_free_all(model_1);
+ lyd_free_all(diff);
+}
+
+static void
+test_same(void **state)
+{
+ (void) state;
+ const char *xml =
+ "<nacm xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-acm\">\n"
+ " <enable-nacm>true</enable-nacm>\n"
+ " <read-default>permit</read-default>\n"
+ " <write-default>deny</write-default>\n"
+ " <exec-default>permit</exec-default>\n"
+ " <enable-external-groups>true</enable-external-groups>\n"
+ "</nacm><df xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <foo>42</foo><b1_1>42</b1_1>\n"
+ "</df><hidden xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <foo>42</foo><baz>42</baz></hidden>\n";
+
+ struct lyd_node *model_1;
+ struct lyd_node *model_2;
+
+ assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_DIR_MODULES_YANG));
+ assert_non_null(ly_ctx_load_module(UTEST_LYCTX, "ietf-netconf-acm", "2018-02-14", NULL));
+
+ CHECK_PARSE_LYD(xml, model_1);
+ CHECK_PARSE_LYD(xml, model_2);
+
+ struct lyd_node *diff = NULL;
+
+ assert_int_equal(lyd_diff_siblings(model_1, model_2, 0, &diff), LY_SUCCESS);
+ assert_null(diff);
+ assert_int_equal(lyd_diff_apply_all(&model_1, diff), LY_SUCCESS);
+ CHECK_LYD(model_1, model_2);
+
+ lyd_free_all(model_1);
+ lyd_free_all(model_2);
+ lyd_free_all(diff);
+}
+
+static void
+test_empty1(void **state)
+{
+ (void) state;
+ const char *xml_in =
+ "<df xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <foo>42</foo>\n"
+ " <b1_1>42</b1_1>\n"
+ "</df>\n"
+ "<hidden xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <foo>42</foo>\n"
+ " <baz>42</baz>\n"
+ "</hidden>\n";
+
+ struct lyd_node *model_1 = NULL;
+ struct lyd_node *model_2;
+
+ CHECK_PARSE_LYD(xml_in, model_2);
+
+ struct lyd_node *diff;
+
+ CHECK_PARSE_LYD_DIFF(model_1, model_2, diff);
+ CHECK_LYD_STRING(diff,
+ "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"create\">\n"
+ " <foo>42</foo>\n"
+ " <b1_1>42</b1_1>\n"
+ "</df>\n"
+ "<hidden xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"create\">\n"
+ " <foo>42</foo>\n"
+ " <baz>42</baz>\n"
+ "</hidden>\n");
+ assert_int_equal(lyd_diff_apply_all(&model_1, diff), LY_SUCCESS);
+ CHECK_LYD(model_1, model_2);
+
+ lyd_free_all(model_1);
+ lyd_free_all(model_2);
+ lyd_free_all(diff);
+}
+
+static void
+test_empty2(void **state)
+{
+ (void) state;
+ const char *xml = "<df xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <foo>42</foo>\n"
+ " <b1_1>42</b1_1>\n"
+ "</df><hidden xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <foo>42</foo>\n"
+ " <baz>42</baz>\n"
+ "</hidden>\n";
+
+ struct lyd_node *model_1;
+
+ CHECK_PARSE_LYD(xml, model_1);
+
+ struct lyd_node *diff;
+
+ CHECK_PARSE_LYD_DIFF(model_1, NULL, diff);
+ CHECK_LYD_STRING(diff,
+ "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"delete\">\n"
+ " <foo>42</foo>\n"
+ " <b1_1>42</b1_1>\n"
+ "</df>\n"
+ "<hidden xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"delete\">\n"
+ " <foo>42</foo>\n"
+ " <baz>42</baz>\n"
+ "</hidden>\n");
+
+ assert_int_equal(lyd_diff_apply_all(&model_1, diff), LY_SUCCESS);
+ assert_ptr_equal(model_1, NULL);
+
+ lyd_free_all(diff);
+ lyd_free_all(model_1);
+}
+
+static void
+test_empty_nested(void **state)
+{
+ (void) state;
+ const char *xml = "<df xmlns=\"urn:libyang:tests:defaults\"><foo>42</foo></df>";
+
+ struct lyd_node *model_1;
+
+ CHECK_PARSE_LYD(xml, model_1);
+
+ struct lyd_node *diff = NULL;
+
+ assert_int_equal(lyd_diff_siblings(NULL, NULL, 0, &diff), LY_SUCCESS);
+ assert_null(diff);
+
+ struct lyd_node *diff1;
+
+ CHECK_PARSE_LYD_DIFF(NULL, lyd_child(model_1), diff1);
+ CHECK_LYD_STRING(diff1,
+ "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">\n"
+ " <foo yang:operation=\"create\">42</foo>\n"
+ "</df>\n");
+
+ struct lyd_node *diff2;
+
+ CHECK_PARSE_LYD_DIFF(lyd_child(model_1), NULL, diff2);
+ CHECK_LYD_STRING(diff2,
+ "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">\n"
+ " <foo yang:operation=\"delete\">42</foo>\n"
+ "</df>\n");
+
+ lyd_free_all(model_1);
+ lyd_free_all(diff1);
+ lyd_free_all(diff2);
+}
+
+static void
+test_delete_merge(void **state)
+{
+ (void) state;
+ struct lyd_node *diff1, *diff2;
+ const char *xml1 =
+ "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">\n"
+ " <list>\n"
+ " <name>a</name>\n"
+ " <list2 yang:operation=\"delete\">\n"
+ " <name2>a</name2>\n"
+ " </list2>\n"
+ " </list>\n"
+ "</df>\n";
+ const char *xml2 =
+ "<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>a</name>\n"
+ " </list>\n"
+ "</df>\n";
+ const char *xml_merge =
+ "<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>a</name>\n"
+ " <list2 yang:operation=\"delete\">\n"
+ " <name2>a</name2>\n"
+ " </list2>\n"
+ " </list>\n"
+ "</df>\n";
+
+ CHECK_PARSE_LYD(xml1, diff1);
+ CHECK_PARSE_LYD(xml2, diff2);
+
+ assert_int_equal(lyd_diff_merge_all(&diff1, diff2, 0), LY_SUCCESS);
+ CHECK_LYD_STRING(diff1, xml_merge);
+
+ lyd_free_all(diff1);
+ lyd_free_all(diff2);
+}
+
+static void
+test_leaf(void **state)
+{
+ (void) state;
+ const char *xml1 =
+ "<df xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <foo>42</foo>\n"
+ "</df>\n"
+ "<hidden xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <foo>42</foo>\n"
+ " <baz>42</baz>\n"
+ "</hidden>\n";
+ const char *xml2 =
+ "<df xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <foo>41</foo>\n"
+ " <b1_1>42</b1_1>\n"
+ "</df>\n";
+ const char *xml3 =
+ "<df xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <foo>40</foo>\n"
+ "</df>\n"
+ "<hidden xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <foo>40</foo>\n"
+ "</hidden>\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"
+ " <foo yang:operation=\"replace\" yang:orig-default=\"false\" yang:orig-value=\"42\">41</foo>\n"
+ " <b1_1 yang:operation=\"create\">42</b1_1>\n"
+ "</df>\n"
+ "<hidden xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"delete\">\n"
+ " <foo>42</foo>\n"
+ " <baz>42</baz>\n"
+ "</hidden>\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"
+ " <foo yang:operation=\"replace\" yang:orig-default=\"false\" yang:orig-value=\"41\">40</foo>\n"
+ " <b1_1 yang:operation=\"delete\">42</b1_1>\n"
+ "</df>\n"
+ "<hidden xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"create\">\n"
+ " <foo>40</foo>\n"
+ "</hidden>\n";
+
+ const char *out_merge =
+ "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">\n"
+ " <foo yang:operation=\"replace\" yang:orig-default=\"false\" yang:orig-value=\"42\">40</foo>\n"
+ "</df>\n"
+ "<hidden xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">\n"
+ " <foo yang:operation=\"replace\" yang:orig-value=\"42\" yang:orig-default=\"false\">40</foo>\n"
+ " <baz yang:operation=\"delete\">42</baz>\n"
+ "</hidden>\n";
+
+ TEST_DIFF_3(xml1, xml2, xml3, out_diff_1, out_diff_2, out_merge);
+}
+
+static void
+test_list(void **state)
+{
+ (void) state;
+ const char *xml1 = "<df xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <list>\n"
+ " <name>a</name>\n"
+ " <value>1</value>\n"
+ " </list>\n"
+ " <list>\n"
+ " <name>b</name>\n"
+ " <value>2</value>\n"
+ " </list>\n"
+ "</df>\n";
+ const char *xml2 = "<df xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <list>\n"
+ " <name>b</name>\n"
+ " <value>-2</value>\n"
+ " </list>\n"
+ " <list>\n"
+ " <name>c</name>\n"
+ " <value>3</value>\n"
+ " </list>\n"
+ "</df>\n";
+ const char *xml3 = "<df xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <list>\n"
+ " <name>b</name>\n"
+ " <value>-2</value>\n"
+ " </list>\n"
+ " <list>\n"
+ " <name>a</name>\n"
+ " <value>2</value>\n"
+ " </list>\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"
+ " <list yang:operation=\"delete\">\n"
+ " <name>a</name>\n"
+ " <value>1</value>\n"
+ " </list>\n"
+ " <list yang:operation=\"none\">\n"
+ " <name>b</name>\n"
+ " <value yang:operation=\"replace\" yang:orig-default=\"false\" yang:orig-value=\"2\">-2</value>\n"
+ " </list>\n"
+ " <list yang:operation=\"create\">\n"
+ " <name>c</name>\n"
+ " <value>3</value>\n"
+ " </list>\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"
+ " <list yang:operation=\"delete\">\n"
+ " <name>c</name>\n"
+ " <value>3</value>\n"
+ " </list>\n"
+ " <list yang:operation=\"create\">\n"
+ " <name>a</name>\n"
+ " <value>2</value>\n"
+ " </list>\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"
+ " <list yang:operation=\"none\">\n"
+ " <name>a</name>\n"
+ " <value yang:operation=\"replace\" yang:orig-value=\"1\" yang:orig-default=\"false\">2</value>\n"
+ " </list>\n"
+ " <list yang:operation=\"none\">\n"
+ " <name>b</name>\n"
+ " <value yang:operation=\"replace\" yang:orig-default=\"false\" yang:orig-value=\"2\">-2</value>\n"
+ " </list>\n"
+ "</df>\n";
+
+ TEST_DIFF_3(xml1, xml2, xml3, out_diff_1, out_diff_2, out_merge);
+}
+
+static void
+test_userord_llist(void **state)
+{
+ (void) state;
+ const char *xml1 =
+ "<df xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <llist>1</llist>\n"
+ " <llist>2</llist>\n"
+ " <llist>3</llist>\n"
+ " <llist>4</llist>\n"
+ " <llist>5</llist>\n"
+ "</df>\n";
+ const char *xml2 =
+ "<df xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <llist>1</llist>\n"
+ " <llist>4</llist>\n"
+ " <llist>3</llist>\n"
+ " <llist>2</llist>\n"
+ " <llist>5</llist>\n"
+ "</df>\n";
+ const char *xml3 =
+ "<df xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <llist>5</llist>\n"
+ " <llist>4</llist>\n"
+ " <llist>3</llist>\n"
+ " <llist>2</llist>\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"
+ " <llist yang:operation=\"replace\" yang:orig-default=\"false\" yang:orig-value=\"3\" yang:value=\"1\">4</llist>\n"
+ " <llist yang:operation=\"replace\" yang:orig-default=\"false\" yang:orig-value=\"2\" yang:value=\"4\">3</llist>\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"
+ " <llist yang:operation=\"delete\" yang:orig-value=\"\">1</llist>\n"
+ " <llist yang:operation=\"replace\" yang:orig-default=\"false\" yang:orig-value=\"2\" yang:value=\"\">5</llist>\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"
+ " <llist yang:operation=\"replace\" yang:orig-default=\"false\" yang:orig-value=\"3\" yang:value=\"1\">4</llist>\n"
+ " <llist yang:operation=\"replace\" yang:orig-default=\"false\" yang:orig-value=\"2\" yang:value=\"4\">3</llist>\n"
+ " <llist yang:orig-value=\"\" yang:operation=\"delete\">1</llist>\n"
+ " <llist yang:orig-default=\"false\" yang:orig-value=\"2\" yang:value=\"\" yang:operation=\"replace\">5</llist>\n"
+ "</df>\n";
+
+ TEST_DIFF_3(xml1, xml2, xml3, out_diff_1, out_diff_2, out_merge);
+}
+
+static void
+test_userord_llist2(void **state)
+{
+ (void) state;
+ const char *xml1 =
+ "<df xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <llist>1</llist>\n"
+ " <list><name>a</name><value>1</value></list>\n"
+ " <llist>2</llist>\n"
+ " <llist>3</llist>\n"
+ " <llist>4</llist>\n"
+ "</df>\n";
+ const char *xml2 =
+ "<df xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <llist>1</llist>\n"
+ " <list><name>a</name><value>1</value></list>\n"
+ " <llist>2</llist>\n"
+ " <llist>4</llist>\n"
+ " <llist>3</llist>\n"
+ "</df>\n";
+ const char *xml3 =
+ "<df xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <llist>4</llist>\n"
+ " <llist>1</llist>\n"
+ " <list><name>a</name><value>1</value></list>\n"
+ " <llist>3</llist>\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"
+ " <llist yang:operation=\"replace\" yang:orig-default=\"false\" yang:orig-value=\"3\" yang:value=\"2\">4</llist>\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"
+ " <llist yang:operation=\"delete\" yang:orig-value=\"1\">2</llist>\n"
+ " <llist yang:operation=\"replace\" yang:orig-default=\"false\" yang:orig-value=\"1\" yang:value=\"\">4</llist>\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"
+ " <llist yang:operation=\"replace\" yang:orig-default=\"false\" yang:orig-value=\"3\" yang:value=\"\">4</llist>\n"
+ " <llist yang:orig-value=\"1\" yang:operation=\"delete\">2</llist>\n"
+ "</df>\n";
+
+ TEST_DIFF_3(xml1, xml2, xml3, out_diff_1, out_diff_2, out_merge);
+}
+
+static void
+test_userord_mix(void **state)
+{
+ (void) state;
+ const char *xml1 =
+ "<df xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <llist>1</llist>\n"
+ " <llist>2</llist>\n"
+ " <llist>3</llist>\n"
+ "</df>\n";
+ const char *xml2 =
+ "<df xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <llist>3</llist>\n"
+ " <llist>1</llist>\n"
+ "</df>\n";
+ const char *xml3 =
+ "<df xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <llist>1</llist>\n"
+ " <llist>4</llist>\n"
+ " <llist>3</llist>\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"
+ " <llist yang:operation=\"delete\" yang:orig-value=\"1\">2</llist>\n"
+ " <llist yang:operation=\"replace\" yang:orig-default=\"false\" yang:orig-value=\"1\" yang:value=\"\">3</llist>\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"
+ " <llist yang:operation=\"replace\" yang:orig-default=\"false\" yang:orig-value=\"3\" yang:value=\"\">1</llist>\n"
+ " <llist yang:operation=\"create\" yang:value=\"1\">4</llist>\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"
+ " <llist yang:operation=\"delete\" yang:orig-value=\"1\">2</llist>\n"
+ " <llist yang:operation=\"replace\" yang:orig-default=\"false\" yang:orig-value=\"1\" yang:value=\"\">3</llist>\n"
+ " <llist yang:orig-default=\"false\" yang:orig-value=\"3\" yang:value=\"\" yang:operation=\"replace\">1</llist>\n"
+ " <llist yang:value=\"1\" yang:operation=\"create\">4</llist>\n"
+ "</df>\n";
+
+ TEST_DIFF_3(xml1, xml2, xml3, out_diff_1, out_diff_2, out_merge);
+}
+
+static void
+test_userord_list(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"
+ " <l2>3</l2>\n"
+ " </ul>\n"
+ "</df>\n";
+ const char *xml2 =
+ "<df xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <ul>\n"
+ " <l1>a</l1>\n"
+ " <l2>11</l2>\n"
+ " </ul>\n"
+ " <ul>\n"
+ " <l1>c</l1>\n"
+ " <l2>3</l2>\n"
+ " </ul>\n"
+ "</df>\n";
+ const char *xml3 =
+ "<df xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <ul>\n"
+ " <l1>c</l1>\n"
+ " <l2>33</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>\n"
+ " <l1>a</l1>\n"
+ " <l2 yang:operation=\"replace\" yang:orig-default=\"false\" yang:orig-value=\"1\">11</l2>\n"
+ " </ul>\n"
+ " <ul yang:operation=\"delete\" yang:orig-key=\"[l1='a']\">\n"
+ " <l1>b</l1>\n"
+ " <l2>2</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=\"delete\" yang:orig-key=\"\">\n"
+ " <l1>a</l1>\n"
+ " <l2>11</l2>\n"
+ " </ul>\n"
+ " <ul yang:operation=\"none\">\n"
+ " <l1>c</l1>\n"
+ " <l2 yang:operation=\"replace\" yang:orig-default=\"false\" yang:orig-value=\"3\">33</l2>\n"
+ " </ul>\n"
+ " <ul yang:operation=\"create\" yang:key=\"[l1='c']\">\n"
+ " <l1>b</l1>\n"
+ " <l2>2</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=\"delete\">\n"
+ " <l1>a</l1>\n"
+ " <l2 yang:operation=\"delete\">1</l2>\n"
+ " </ul>\n"
+ " <ul yang:orig-key=\"[l1='a']\" yang:operation=\"replace\" yang:key=\"[l1='c']\">\n"
+ " <l1>b</l1>\n"
+ " </ul>\n"
+ " <ul yang:operation=\"none\">\n"
+ " <l1>c</l1>\n"
+ " <l2 yang:operation=\"replace\" yang:orig-default=\"false\" yang:orig-value=\"3\">33</l2>\n"
+ " </ul>\n"
+ "</df>\n";
+
+ TEST_DIFF_3(xml1, xml2, xml3, out_diff_1, out_diff_2, out_merge);
+}
+
+static void
+test_userord_list2(void **state)
+{
+ (void) state;
+ const char *xml1 =
+ "<df xmlns=\"urn:libyang:tests:defaults\">\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"
+ " </ul>\n"
+ " <ul>\n"
+ " <l1>d</l1>\n"
+ " <l2>4</l2>\n"
+ " </ul>\n"
+ "</df>\n";
+ const char *xml3 =
+ "<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"
+ " <l2>3</l2>\n"
+ " </ul>\n"
+ " <ul>\n"
+ " <l1>d</l1>\n"
+ " <l2>4</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=\"create\" yang:key=\"\">\n"
+ " <l1>c</l1>\n"
+ " <l2>3</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=\"create\" yang:key=\"\">\n"
+ " <l1>a</l1>\n"
+ " <l2>1</l2>\n"
+ " </ul>\n"
+ " <ul yang:operation=\"create\" yang:key=\"[l1='a']\">\n"
+ " <l1>b</l1>\n"
+ " <l2>2</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=\"create\" yang:key=\"\">\n"
+ " <l1>c</l1>\n"
+ " <l2>3</l2>\n"
+ " </ul>\n"
+ " <ul yang:key=\"\" yang:operation=\"create\">\n"
+ " <l1>a</l1>\n"
+ " <l2>1</l2>\n"
+ " </ul>\n"
+ " <ul yang:key=\"[l1='a']\" yang:operation=\"create\">\n"
+ " <l1>b</l1>\n"
+ " <l2>2</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;
+ const char *xml1 = "<df xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <kl>\n"
+ " <l1>a</l1>\n"
+ " <l2>1</l2>\n"
+ " </kl>\n"
+ " <kl>\n"
+ " <l1>b</l1>\n"
+ " <l2>2</l2>\n"
+ " </kl>\n"
+ " <kl>\n"
+ " <l1>c</l1>\n"
+ " <l2>3</l2>\n"
+ " </kl>\n"
+ "</df>\n";
+ const char *xml2 = "<df xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <kl>\n"
+ " <l1>b</l1>\n"
+ " <l2>2</l2>\n"
+ " </kl>\n"
+ " <kl>\n"
+ " <l1>a</l1>\n"
+ " <l2>1</l2>\n"
+ " </kl>\n"
+ " <kl>\n"
+ " <l1>a</l1>\n"
+ " <l2>1</l2>\n"
+ " </kl>\n"
+ "</df>\n";
+ const char *xml3 = "<df xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <kl>\n"
+ " <l1>c</l1>\n"
+ " </kl>\n"
+ " <kl>\n"
+ " <l2>4</l2>\n"
+ " </kl>\n"
+ " <kl>\n"
+ " <l1>e</l1>\n"
+ " <l2>5</l2>\n"
+ " </kl>\n"
+ " <kl>\n"
+ " <l1>f</l1>\n"
+ " <l2>6</l2>\n"
+ " </kl>\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"
+ " <kl yang:operation=\"delete\" yang:orig-position=\"2\">\n"
+ " <l1>c</l1>\n"
+ " <l2>3</l2>\n"
+ " </kl>\n"
+ " <kl yang:operation=\"replace\" yang:position=\"\" yang:orig-position=\"1\">\n"
+ " <l1>b</l1>\n"
+ " <l2>2</l2>\n"
+ " </kl>\n"
+ " <kl yang:operation=\"create\" yang:position=\"2\">\n"
+ " <l1>a</l1>\n"
+ " <l2>1</l2>\n"
+ " </kl>\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"
+ " <kl yang:operation=\"delete\" yang:orig-position=\"\">\n"
+ " <l1>b</l1>\n"
+ " <l2>2</l2>\n"
+ " </kl>\n"
+ " <kl yang:operation=\"delete\" yang:orig-position=\"\">\n"
+ " <l1>a</l1>\n"
+ " <l2>1</l2>\n"
+ " </kl>\n"
+ " <kl yang:operation=\"delete\" yang:orig-position=\"\">\n"
+ " <l1>a</l1>\n"
+ " <l2>1</l2>\n"
+ " </kl>\n"
+ " <kl yang:operation=\"create\" yang:position=\"\">\n"
+ " <l1>c</l1>\n"
+ " </kl>\n"
+ " <kl yang:operation=\"create\" yang:position=\"1\">\n"
+ " <l2>4</l2>\n"
+ " </kl>\n"
+ " <kl yang:operation=\"create\" yang:position=\"2\">\n"
+ " <l1>e</l1>\n"
+ " <l2>5</l2>\n"
+ " </kl>\n"
+ " <kl yang:operation=\"create\" yang:position=\"3\">\n"
+ " <l1>f</l1>\n"
+ " <l2>6</l2>\n"
+ " </kl>\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"
+ " <kl yang:operation=\"delete\" yang:orig-position=\"2\">\n"
+ " <l1>c</l1>\n"
+ " <l2>3</l2>\n"
+ " </kl>\n"
+ " <kl yang:orig-position=\"1\" yang:operation=\"delete\">\n"
+ " <l1>b</l1>\n"
+ " <l2>2</l2>\n"
+ " </kl>\n"
+ " <kl yang:orig-position=\"\" yang:operation=\"delete\">\n"
+ " <l1>a</l1>\n"
+ " <l2>1</l2>\n"
+ " </kl>\n"
+ " <kl yang:position=\"\" yang:operation=\"create\">\n"
+ " <l1>c</l1>\n"
+ " </kl>\n"
+ " <kl yang:position=\"1\" yang:operation=\"create\">\n"
+ " <l2>4</l2>\n"
+ " </kl>\n"
+ " <kl yang:position=\"2\" yang:operation=\"create\">\n"
+ " <l1>e</l1>\n"
+ " <l2>5</l2>\n"
+ " </kl>\n"
+ " <kl yang:position=\"3\" yang:operation=\"create\">\n"
+ " <l1>f</l1>\n"
+ " <l2>6</l2>\n"
+ " </kl>\n"
+ "</df>\n";
+
+ TEST_DIFF_3(xml1, xml2, xml3, out_diff_1, out_diff_2, out_merge);
+}
+
+static void
+test_state_llist(void **state)
+{
+ (void) state;
+ const char *xml1 = "<df xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <kll>a</kll>\n"
+ " <kll>b</kll>\n"
+ " <kll>c</kll>\n"
+ "</df>\n";
+ const char *xml2 = "<df xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <kll>b</kll>\n"
+ " <kll>c</kll>\n"
+ " <kll>a</kll>\n"
+ " <kll>a</kll>\n"
+ " <kll>a</kll>\n"
+ "</df>\n";
+ const char *xml3 = "<df xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <kll>a</kll>\n"
+ " <kll>d</kll>\n"
+ " <kll>a</kll>\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"
+ " <kll yang:operation=\"replace\" yang:orig-default=\"false\" yang:position=\"\" yang:orig-position=\"1\">b</kll>\n"
+ " <kll yang:operation=\"replace\" yang:orig-default=\"false\" yang:position=\"1\" yang:orig-position=\"2\">c</kll>\n"
+ " <kll yang:operation=\"create\" yang:position=\"3\">a</kll>\n"
+ " <kll yang:operation=\"create\" yang:position=\"4\">a</kll>\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"
+ " <kll yang:operation=\"delete\" yang:orig-position=\"\">b</kll>\n"
+ " <kll yang:operation=\"delete\" yang:orig-position=\"\">c</kll>\n"
+ " <kll yang:operation=\"delete\" yang:orig-position=\"2\">a</kll>\n"
+ " <kll yang:operation=\"create\" yang:position=\"1\">d</kll>\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"
+ " <kll yang:orig-default=\"false\" yang:orig-position=\"1\" yang:operation=\"delete\">b</kll>\n"
+ " <kll yang:orig-default=\"false\" yang:orig-position=\"2\" yang:operation=\"delete\">c</kll>\n"
+ " <kll yang:operation=\"create\" yang:position=\"4\">a</kll>\n"
+ " <kll yang:position=\"1\" yang:operation=\"create\">d</kll>\n"
+ "</df>\n";
+
+ TEST_DIFF_3(xml1, xml2, xml3, out_diff_1, out_diff_2, out_merge);
+}
+
+static void
+test_wd(void **state)
+{
+ (void) state;
+ const struct lys_module *mod;
+ const char *xml2 = "<df xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <foo>41</foo>\n"
+ " <dllist>4</dllist>\n"
+ "</df>\n";
+ const char *xml3 = "<df xmlns=\"urn:libyang:tests:defaults\">\n"
+ " <foo>42</foo>\n"
+ " <dllist>4</dllist>\n"
+ " <dllist>1</dllist>\n"
+ "</df>\n";
+
+ mod = ly_ctx_get_module_implemented(UTEST_LYCTX, "defaults");
+ assert_non_null(mod);
+
+ struct lyd_node *model_1 = NULL;
+
+ assert_int_equal(lyd_validate_module(&model_1, mod, 0, NULL), LY_SUCCESS);
+ assert_ptr_not_equal(model_1, NULL);
+
+ struct lyd_node *model_2;
+ struct lyd_node *model_3;
+
+ CHECK_PARSE_LYD_PARAM(xml2, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, model_2);
+ CHECK_PARSE_LYD_PARAM(xml3, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, model_3);
+
+ /* diff1 */
+ struct lyd_node *diff1 = NULL;
+
+ assert_int_equal(lyd_diff_siblings(model_1, model_2, LYD_DIFF_DEFAULTS, &diff1), LY_SUCCESS);
+ assert_non_null(diff1);
+
+ const char *diff1_out_1 =
+ "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">\n"
+ " <foo yang:operation=\"replace\" yang:orig-default=\"true\" yang:orig-value=\"42\">41</foo>\n"
+ " <dllist yang:operation=\"delete\">1</dllist>\n"
+ " <dllist yang:operation=\"delete\">2</dllist>\n"
+ " <dllist yang:operation=\"delete\">3</dllist>\n"
+ " <dllist yang:operation=\"create\">4</dllist>\n"
+ "</df>\n";
+
+ CHECK_LYD_STRING_PARAM(diff1, diff1_out_1, LYD_XML, LYD_PRINT_WITHSIBLINGS | LYD_PRINT_WD_ALL);
+ assert_int_equal(lyd_diff_apply_all(&model_1, diff1), LY_SUCCESS);
+ CHECK_LYD(model_1, model_2);
+
+ /* diff2 */
+ struct lyd_node *diff2;
+
+ assert_int_equal(lyd_diff_siblings(model_2, model_3, LYD_DIFF_DEFAULTS, &diff2), LY_SUCCESS);
+ assert_non_null(diff2);
+ CHECK_LYD_STRING(diff2,
+ "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">\n"
+ " <foo yang:operation=\"replace\" yang:orig-default=\"false\" yang:orig-value=\"41\">42</foo>\n"
+ " <dllist yang:operation=\"create\">1</dllist>\n"
+ "</df>\n");
+
+ assert_int_equal(lyd_diff_apply_all(&model_2, diff2), LY_SUCCESS);
+ CHECK_LYD(model_2, model_3);
+
+ /* merge */
+ assert_int_equal(lyd_diff_merge_all(&diff1, diff2, 0), LY_SUCCESS);
+
+ const char *diff1_out_2 =
+ "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">\n"
+ " <foo yang:orig-default=\"true\" yang:operation=\"none\">42</foo>\n"
+ " <dllist yang:operation=\"none\" yang:orig-default=\"true\">1</dllist>\n"
+ " <dllist yang:operation=\"delete\">2</dllist>\n"
+ " <dllist yang:operation=\"delete\">3</dllist>\n"
+ " <dllist yang:operation=\"create\">4</dllist>\n"
+ "</df>\n";
+
+ CHECK_LYD_STRING_PARAM(diff1, diff1_out_2, LYD_XML, LYD_PRINT_WITHSIBLINGS | LYD_PRINT_WD_ALL);
+
+ lyd_free_all(model_1);
+ lyd_free_all(model_2);
+ lyd_free_all(model_3);
+ lyd_free_all(diff1);
+ lyd_free_all(diff2);
+}
+
+int
+main(void)
+{
+ const struct CMUnitTest tests[] = {
+ UTEST(test_invalid, setup),
+ UTEST(test_same, setup),
+ UTEST(test_empty1, setup),
+ UTEST(test_empty2, setup),
+ UTEST(test_empty_nested, setup),
+ UTEST(test_delete_merge, setup),
+ UTEST(test_leaf, setup),
+ UTEST(test_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_keyless_list, setup),
+ UTEST(test_state_llist, setup),
+ UTEST(test_wd, setup),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/tests/utests/data/test_lyb.c b/tests/utests/data/test_lyb.c
new file mode 100644
index 0000000..26f3e73
--- /dev/null
+++ b/tests/utests/data/test_lyb.c
@@ -0,0 +1,2841 @@
+/**
+ * @file test_lyb.c
+ * @author Michal Vasko <mvasko@cesnet.cz>
+ * @brief Cmocka tests for LYB binary data format.
+ *
+ * Copyright (c) 2020 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.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ */
+#define _UTEST_MAIN_
+#include "utests.h"
+
+#include "hash_table.h"
+#include "libyang.h"
+
+#define CHECK_PARSE_LYD(INPUT, OUT_NODE) \
+ CHECK_PARSE_LYD_PARAM(INPUT, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, LY_SUCCESS, OUT_NODE)
+
+#define CHECK_LYD_STRING(MODEL, TEXT) \
+ CHECK_LYD_STRING_PARAM(MODEL, TEXT, LYD_XML, LYD_PRINT_WITHSIBLINGS | LYD_PRINT_SHRINK)
+
+static void
+check_print_parse(void **state, const char *data_xml)
+{
+ struct lyd_node *tree_1;
+ struct lyd_node *tree_2;
+ char *lyb_out;
+
+ CHECK_PARSE_LYD(data_xml, tree_1);
+ assert_int_equal(lyd_print_mem(&lyb_out, tree_1, LYD_LYB, LYD_PRINT_WITHSIBLINGS), 0);
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, lyb_out, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT,
+ 0, &tree_2));
+ assert_non_null(tree_2);
+ CHECK_LYD(tree_1, tree_2);
+
+ free(lyb_out);
+ lyd_free_all(tree_1);
+ lyd_free_all(tree_2);
+}
+
+static int
+setup(void **state)
+{
+ UTEST_SETUP;
+ assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_DIR_MODULES_YANG));
+
+ return 0;
+}
+
+static void
+tests_leaflist(void **state)
+{
+ const char *mod;
+ const char *data_xml;
+
+ mod =
+ "module mod { namespace \"urn:test-leaflist\"; prefix m;"
+ " container cont {"
+ " presence \"\";"
+ " leaf-list ll {"
+ " type uint8;"
+ " }"
+ " }"
+ "}";
+ UTEST_ADD_MODULE(mod, LYS_IN_YANG, NULL, NULL);
+
+ data_xml =
+ "<cont xmlns=\"urn:test-leaflist\">\n"
+ "</cont>\n";
+ check_print_parse(state, data_xml);
+
+ data_xml =
+ "<cont xmlns=\"urn:test-leaflist\">\n"
+ " <ll>1</ll>\n"
+ "</cont>\n";
+ check_print_parse(state, data_xml);
+
+ data_xml =
+ "<cont xmlns=\"urn:test-leaflist\">\n"
+ " <ll>1</ll>\n"
+ " <ll>2</ll>\n"
+ "</cont>\n";
+ check_print_parse(state, data_xml);
+}
+
+static void
+tests_list(void **state)
+{
+ const char *mod;
+ const char *data_xml;
+
+ mod =
+ "module mod { namespace \"urn:test-list\"; prefix m;"
+ " container cont {"
+ " presence \"\";"
+ " list lst {"
+ " key \"lf\";"
+ " leaf lf {"
+ " type uint8;"
+ " }"
+ " }"
+ " }"
+ "}";
+ UTEST_ADD_MODULE(mod, LYS_IN_YANG, NULL, NULL);
+
+ data_xml =
+ "<cont xmlns=\"urn:test-list\">\n"
+ " <lst>"
+ " <lf>1</lf>"
+ " </lst>"
+ "</cont>\n";
+ check_print_parse(state, data_xml);
+
+ data_xml =
+ "<cont xmlns=\"urn:test-list\">\n"
+ " <lst>"
+ " <lf>1</lf>"
+ " <lf>2</lf>"
+ " </lst>"
+ "</cont>\n";
+ check_print_parse(state, data_xml);
+}
+
+static void
+tests_any(void **state)
+{
+ const char *mod;
+ const char *data_xml;
+
+ mod =
+ "module mod { namespace \"urn:test-any\"; prefix m;"
+ " container cont {"
+ " presence \"\";"
+ " anyxml anxml;\n"
+ " }"
+ "}";
+ UTEST_ADD_MODULE(mod, LYS_IN_YANG, NULL, NULL);
+
+ data_xml =
+ "<cont xmlns=\"urn:test-any\">\n"
+ "</cont>\n";
+ check_print_parse(state, data_xml);
+
+ data_xml =
+ "<cont xmlns=\"urn:test-any\">\n"
+ " <anxml><node>value</node></anxml>\n"
+ "</cont>\n";
+ check_print_parse(state, data_xml);
+
+ data_xml =
+ "<cont xmlns=\"urn:test-any\">\n"
+ " <anxml><node1>value</node1></anxml>\n"
+ " <anxml><node2>value</node2></anxml>\n"
+ "</cont>\n";
+ check_print_parse(state, data_xml);
+}
+
+static void
+test_ietf_interfaces(void **state)
+{
+ const char *data_xml =
+ "<interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">\n"
+ " <interface>\n"
+ " <name>eth0</name>\n"
+ " <description>Ethernet 0</description>\n"
+ " <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type>\n"
+ " <enabled>true</enabled>\n"
+ " <ipv4 xmlns=\"urn:ietf:params:xml:ns:yang:ietf-ip\">\n"
+ " <enabled>true</enabled>\n"
+ " <mtu>1500</mtu>\n"
+ " <address>\n"
+ " <ip>192.168.2.100</ip>\n"
+ " <prefix-length>24</prefix-length>\n"
+ " </address>\n"
+ " </ipv4>\n"
+ " </interface>\n"
+ " <interface>\n"
+ " <name>eth1</name>\n"
+ " <description>Ethernet 1</description>\n"
+ " <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type>\n"
+ " <enabled>true</enabled>\n"
+ " <ipv4 xmlns=\"urn:ietf:params:xml:ns:yang:ietf-ip\">\n"
+ " <enabled>true</enabled>\n"
+ " <mtu>1500</mtu>\n"
+ " <address>\n"
+ " <ip>10.10.1.5</ip>\n"
+ " <prefix-length>16</prefix-length>\n"
+ " </address>\n"
+ " </ipv4>\n"
+ " </interface>\n"
+ " <interface>\n"
+ " <name>gigaeth0</name>\n"
+ " <description>GigabitEthernet 0</description>\n"
+ " <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type>\n"
+ " <enabled>false</enabled>\n"
+ " </interface>\n"
+ "</interfaces>\n";
+
+ assert_non_null(ly_ctx_load_module(UTEST_LYCTX, "ietf-ip", NULL, NULL));
+ assert_non_null(ly_ctx_load_module(UTEST_LYCTX, "iana-if-type", NULL, NULL));
+
+ check_print_parse(state, data_xml);
+}
+
+static void
+test_origin(void **state)
+{
+ const char *origin_yang =
+ "module test-origin {"
+ " namespace \"urn:test-origin\";"
+ " prefix to;"
+ " import ietf-origin {"
+ " prefix or;"
+ " }"
+ ""
+ " container cont {"
+ " leaf leaf1 {"
+ " type string;"
+ " }"
+ " leaf leaf2 {"
+ " type string;"
+ " }"
+ " leaf leaf3 {"
+ " type uint8;"
+ " }"
+ " }"
+ "}";
+ const char *data_xml =
+ "<cont xmlns=\"urn:test-origin\">\n"
+ " <leaf1 xmlns:or=\"urn:ietf:params:xml:ns:yang:ietf-origin\" or:origin=\"or:default\">value1</leaf1>\n"
+ " <leaf2>value2</leaf2>\n"
+ " <leaf3 xmlns:or=\"urn:ietf:params:xml:ns:yang:ietf-origin\" or:origin=\"or:system\">125</leaf3>\n"
+ "</cont>\n";
+
+ UTEST_ADD_MODULE(origin_yang, LYS_IN_YANG, NULL, NULL);
+ assert_int_equal(LY_SUCCESS, lys_set_implemented(ly_ctx_get_module_latest(UTEST_LYCTX, "ietf-origin"), NULL));
+
+ check_print_parse(state, data_xml);
+}
+
+static void
+test_statements(void **state)
+{
+ const char *links_yang =
+ "module links {\n"
+ " yang-version 1.1;\n"
+ " namespace \"urn:module2\";\n"
+ " prefix mod2;\n"
+ "\n"
+ " identity just-another-identity;\n"
+ "\n"
+ " leaf one-leaf {\n"
+ " type string;\n"
+ " }\n"
+ "\n"
+ " list list-for-augment {\n"
+ " key keyleaf;\n"
+ "\n"
+ " leaf keyleaf {\n"
+ " type string;\n"
+ " }\n"
+ "\n"
+ " leaf just-leaf {\n"
+ " type int32;\n"
+ " }\n"
+ " }\n"
+ "\n"
+ " leaf rleaf {\n"
+ " type string;\n"
+ " }\n"
+ "\n"
+ " leaf-list llist {\n"
+ " type string;\n"
+ " min-elements 0;\n"
+ " max-elements 100;\n"
+ " ordered-by user;\n"
+ " }\n"
+ "\n"
+ " grouping rgroup {\n"
+ " leaf rg1 {\n"
+ " type string;\n"
+ " }\n"
+ "\n"
+ " leaf rg2 {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ "}\n";
+
+ const char *statements_yang =
+ "module statements {\n"
+ " namespace \"urn:module\";\n"
+ " prefix mod;\n"
+ " yang-version 1.1;\n"
+ "\n"
+ " import links {\n"
+ " prefix mod2;\n"
+ " }\n"
+ "\n"
+ " identity random-identity {\n"
+ " base \"mod2:just-another-identity\";\n"
+ " base \"another-identity\";\n"
+ " }\n"
+ "\n"
+ " identity another-identity {\n"
+ " base \"mod2:just-another-identity\";\n"
+ " }\n"
+ "\n"
+ " typedef percent {\n"
+ " type uint8 {\n"
+ " range \"0 .. 100\";\n"
+ " }\n"
+ " units percent;\n"
+ " }\n"
+ "\n"
+ " container ice-cream-shop {\n"
+ " container employees {\n"
+ " list employee {\n"
+ " config true;\n"
+ " key id;\n"
+ " unique name;\n"
+ " min-elements 0;\n"
+ " max-elements 100;\n"
+ "\n"
+ " leaf id {\n"
+ " type uint64;\n"
+ " mandatory true;\n"
+ " }\n"
+ "\n"
+ " leaf name {\n"
+ " type string;\n"
+ " }\n"
+ "\n"
+ " leaf age {\n"
+ " type uint32;\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ "\n"
+ " container random {\n"
+ " choice switch {\n"
+ " case a {\n"
+ " leaf aleaf {\n"
+ " type string;\n"
+ " default aaa;\n"
+ " }\n"
+ " }\n"
+ "\n"
+ " case c {\n"
+ " leaf cleaf {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ "\n"
+ " anyxml xml-data;\n"
+ " anydata any-data;\n"
+ " leaf-list leaflist {\n"
+ " type string;\n"
+ " min-elements 0;\n"
+ " max-elements 20;\n"
+ " ordered-by system;\n"
+ " }\n"
+ "\n"
+ " grouping group {\n"
+ " leaf g1 {\n"
+ " mandatory false;\n"
+ " type percent;\n"
+ " }\n"
+ "\n"
+ " leaf g2 {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ "\n"
+ " uses group;\n"
+ " uses mod2:rgroup;\n"
+ "\n"
+ " leaf lref {\n"
+ " type leafref {\n"
+ " path \"/mod2:one-leaf\";\n"
+ " }\n"
+ " }\n"
+ "\n"
+ " leaf iref {\n"
+ " type identityref {\n"
+ " base \"mod2:just-another-identity\";\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ "\n"
+ " notification notif;\n"
+ "\n"
+ " augment \"/random\" {\n"
+ " leaf aug-leaf {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ "}\n";
+
+ const char *data_xml =
+ "<one-leaf xmlns=\"urn:module2\">reference leaf</one-leaf>\n"
+ "<ice-cream-shop xmlns=\"urn:module\">\n"
+ " <employees>\n"
+ " <employee>\n"
+ " <id>0</id>\n"
+ " <name>John Doe</name>\n"
+ " <age>28</age>\n"
+ " </employee>\n"
+ " <employee>\n"
+ " <id>1</id>\n"
+ " <name>Dohn Joe</name>\n"
+ " <age>20</age>\n"
+ " </employee>\n"
+ " </employees>\n"
+ "</ice-cream-shop>\n"
+ "<random xmlns=\"urn:module\">\n"
+ " <aleaf>string</aleaf>\n"
+ " <xml-data><anyxml>data</anyxml></xml-data>\n"
+ " <any-data><notif/></any-data>\n"
+ " <leaflist>l0</leaflist>\n"
+ " <leaflist>l1</leaflist>\n"
+ " <leaflist>l2</leaflist>\n"
+ " <g1>40</g1>\n"
+ " <g2>string</g2>\n"
+ " <aug-leaf>string</aug-leaf>\n"
+ " <rg1>string</rg1>\n"
+ " <rg2>string</rg2>\n"
+ " <lref>reference leaf</lref>\n"
+ " <iref>random-identity</iref>\n"
+ "</random>\n";
+
+ UTEST_ADD_MODULE(links_yang, LYS_IN_YANG, NULL, NULL);
+ UTEST_ADD_MODULE(statements_yang, LYS_IN_YANG, NULL, NULL);
+
+ check_print_parse(state, data_xml);
+}
+
+static void
+test_opaq(void **state)
+{
+ const char *nc_feats[] = {"writable-running", NULL};
+ const char *data_xml =
+ "<edit-config xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
+ " <target>\n"
+ " <running/>\n"
+ " </target>\n"
+ " <config>\n"
+ " <top xmlns=\"urn:ed\">\n"
+ " <first>TestFirst</first>\n"
+ " </top>\n"
+ " </config>\n"
+ "</edit-config>\n";
+ struct ly_in *in;
+ struct lyd_node *tree_1;
+ struct lyd_node *tree_2;
+ char *xml_out; /* tree_2 */
+ LY_ERR rc;
+
+ assert_non_null(ly_ctx_load_module(UTEST_LYCTX, "ietf-netconf", NULL, nc_feats));
+
+ ly_in_new_memory(data_xml, &in);
+ rc = lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_XML, LYD_TYPE_RPC_YANG, &tree_1, NULL);
+ ly_in_free(in, 0);
+ assert_int_equal(rc, LY_SUCCESS);
+
+ assert_int_equal(lyd_print_mem(&xml_out, tree_1, LYD_LYB, LYD_PRINT_WITHSIBLINGS), 0);
+
+ ly_in_new_memory(xml_out, &in);
+ rc = lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_LYB, LYD_TYPE_RPC_YANG, &tree_2, NULL);
+ ly_in_free(in, 0);
+ assert_int_equal(rc, LY_SUCCESS);
+
+ /* compare models */
+ CHECK_LYD(tree_1, tree_2);
+
+ /* clean */
+ free(xml_out);
+ lyd_free_all(tree_1);
+ lyd_free_all(tree_2);
+}
+
+static void
+test_collisions(void **state)
+{
+ char *counters_yang, *data_xml;
+
+ counters_yang = malloc(32768);
+ strcpy(counters_yang,
+ "module counters {\n"
+ " namespace \"urn:counters\";\n"
+ " prefix c;\n"
+ "\n"
+ " container stats {\n");
+ strcat(counters_yang,
+ " leaf counter1 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter2 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter3 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter4 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter5 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter6 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter7 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter8 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter9 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter10 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter11 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter12 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter13 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter14 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter15 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter16 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter17 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter18 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter19 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter20 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter21 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter22 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter23 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter24 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter25 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter26 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter27 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter28 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter29 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter30 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter31 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter32 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter33 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter34 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter35 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter36 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter37 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter38 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter39 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter40 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter41 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter42 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter43 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter44 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter45 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter46 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter47 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter48 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter49 {\n"
+ " type uint64;\n"
+ " }\n");
+ strcat(counters_yang,
+ " leaf counter50 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter51 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter52 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter53 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter54 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter55 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter56 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter57 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter58 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter59 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter60 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter61 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter62 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter63 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter64 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter65 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter66 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter67 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter68 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter69 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter70 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter71 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter72 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter73 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter74 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter75 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter76 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter77 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter78 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter79 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter80 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter81 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter82 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter83 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter84 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter85 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter86 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter87 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter88 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter89 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter90 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter91 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter92 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter93 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter94 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter95 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter96 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter97 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter98 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter99 {\n"
+ " type uint64;\n"
+ " }\n");
+ strcat(counters_yang,
+ " leaf counter100 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter101 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter102 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter103 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter104 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter105 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter106 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter107 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter108 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter109 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter110 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter111 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter112 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter113 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter114 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter115 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter116 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter117 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter118 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter119 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter120 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter121 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter122 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter123 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter124 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter125 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter126 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter127 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter128 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter129 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter130 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter131 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter132 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter133 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter134 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter135 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter136 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter137 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter138 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter139 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter140 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter141 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter142 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter143 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter144 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter145 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter146 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter147 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter148 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter149 {\n"
+ " type uint64;\n"
+ " }\n");
+ strcat(counters_yang,
+ " leaf counter150 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter151 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter152 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter153 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter154 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter155 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter156 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter157 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter158 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter159 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter160 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter161 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter162 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter163 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter164 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter165 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter166 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter167 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter168 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter169 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter170 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter171 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter172 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter173 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter174 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter175 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter176 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter177 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter178 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter179 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter180 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter181 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter182 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter183 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter184 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter185 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter186 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter187 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter188 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter189 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter190 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter191 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter192 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter193 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter194 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter195 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter196 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter197 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter198 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter199 {\n"
+ " type uint64;\n"
+ " }\n");
+ strcat(counters_yang,
+ " leaf counter200 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter201 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter202 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter203 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter204 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter205 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter206 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter207 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter208 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter209 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter210 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter211 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter212 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter213 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter214 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter215 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter216 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter217 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter218 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter219 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter220 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter221 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter222 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter223 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter224 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter225 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter226 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter227 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter228 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter229 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter230 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter231 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter232 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter233 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter234 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter235 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter236 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter237 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter238 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter239 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter240 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter241 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter242 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter243 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter244 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter245 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter246 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter247 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter248 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter249 {\n"
+ " type uint64;\n"
+ " }\n");
+ strcat(counters_yang,
+ " leaf counter250 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter251 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter252 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter253 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter254 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter255 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter256 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter257 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter258 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter259 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter260 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter261 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter262 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter263 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter264 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter265 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter266 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter267 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter268 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter269 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter270 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter271 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter272 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter273 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter274 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter275 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter276 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter277 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter278 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter279 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter280 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter281 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter282 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter283 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter284 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter285 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter286 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter287 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter288 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter289 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter290 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter291 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter292 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter293 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter294 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter295 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter296 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter297 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter298 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter299 {\n"
+ " type uint64;\n"
+ " }\n");
+ strcat(counters_yang,
+ " leaf counter300 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter301 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter302 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter303 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter304 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter305 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter306 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter307 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter308 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter309 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter310 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter311 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter312 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter313 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter314 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter315 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter316 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter317 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter318 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter319 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter320 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter321 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter322 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter323 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter324 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter325 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter326 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter327 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter328 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter329 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter330 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter331 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter332 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter333 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter334 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter335 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter336 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter337 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter338 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter339 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter340 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter341 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter342 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter343 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter344 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter345 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter346 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter347 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter348 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter349 {\n"
+ " type uint64;\n"
+ " }\n");
+ strcat(counters_yang,
+ " leaf counter350 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter351 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter352 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter353 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter354 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter355 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter356 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter357 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter358 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter359 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter360 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter361 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter362 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter363 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter364 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter365 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter366 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter367 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter368 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter369 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter370 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter371 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter372 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter373 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter374 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter375 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter376 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter377 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter378 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter379 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter380 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter381 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter382 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter383 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter384 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter385 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter386 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter387 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter388 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter389 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter390 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter391 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter392 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter393 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter394 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter395 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter396 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter397 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter398 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter399 {\n"
+ " type uint64;\n"
+ " }\n");
+ strcat(counters_yang,
+ " leaf counter400 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter401 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter402 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter403 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter404 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter405 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter406 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter407 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter408 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter409 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter410 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter411 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter412 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter413 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter414 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter415 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter416 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter417 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter418 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter419 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter420 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter421 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter422 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter423 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter424 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter425 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter426 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter427 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter428 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter429 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter430 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter431 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter432 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter433 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter434 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter435 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter436 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter437 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter438 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter439 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter440 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter441 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter442 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter443 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter444 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter445 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter446 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter447 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter448 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter449 {\n"
+ " type uint64;\n"
+ " }\n");
+ strcat(counters_yang,
+ " leaf counter450 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter451 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter452 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter453 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter454 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter455 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter456 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter457 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter458 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter459 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter460 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter461 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter462 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter463 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter464 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter465 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter466 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter467 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter468 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter469 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter470 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter471 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter472 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter473 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter474 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter475 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter476 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter477 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter478 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter479 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter480 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter481 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter482 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter483 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter484 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter485 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter486 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter487 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter488 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter489 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter490 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter491 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter492 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter493 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter494 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter495 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter496 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter497 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter498 {\n"
+ " type uint64;\n"
+ " }\n"
+ " leaf counter499 {\n"
+ " type uint64;\n"
+ " }\n"
+ " }\n"
+ "}\n");
+
+ data_xml = malloc(16384);
+ strcpy(data_xml,
+ "<stats xmlns=\"urn:counters\">\n");
+ strcat(data_xml,
+ " <counter1>1</counter1>\n"
+ " <counter2>2</counter2>\n"
+ " <counter3>3</counter3>\n"
+ " <counter4>4</counter4>\n"
+ " <counter5>5</counter5>\n"
+ " <counter6>6</counter6>\n"
+ " <counter7>7</counter7>\n"
+ " <counter8>8</counter8>\n"
+ " <counter9>9</counter9>\n"
+ " <counter10>10</counter10>\n"
+ " <counter11>11</counter11>\n"
+ " <counter12>12</counter12>\n"
+ " <counter13>13</counter13>\n"
+ " <counter14>14</counter14>\n"
+ " <counter15>15</counter15>\n"
+ " <counter16>16</counter16>\n"
+ " <counter17>17</counter17>\n"
+ " <counter18>18</counter18>\n"
+ " <counter19>19</counter19>\n"
+ " <counter20>20</counter20>\n"
+ " <counter21>21</counter21>\n"
+ " <counter22>22</counter22>\n"
+ " <counter23>23</counter23>\n"
+ " <counter24>24</counter24>\n"
+ " <counter25>25</counter25>\n"
+ " <counter26>26</counter26>\n"
+ " <counter27>27</counter27>\n"
+ " <counter28>28</counter28>\n"
+ " <counter29>29</counter29>\n"
+ " <counter30>30</counter30>\n"
+ " <counter31>31</counter31>\n"
+ " <counter32>32</counter32>\n"
+ " <counter33>33</counter33>\n"
+ " <counter34>34</counter34>\n"
+ " <counter35>35</counter35>\n"
+ " <counter36>36</counter36>\n"
+ " <counter37>37</counter37>\n"
+ " <counter38>38</counter38>\n"
+ " <counter39>39</counter39>\n"
+ " <counter40>40</counter40>\n"
+ " <counter41>41</counter41>\n"
+ " <counter42>42</counter42>\n"
+ " <counter43>43</counter43>\n"
+ " <counter44>44</counter44>\n"
+ " <counter45>45</counter45>\n"
+ " <counter46>46</counter46>\n"
+ " <counter47>47</counter47>\n"
+ " <counter48>48</counter48>\n"
+ " <counter49>49</counter49>\n"
+ " <counter50>50</counter50>\n"
+ " <counter51>51</counter51>\n"
+ " <counter52>52</counter52>\n"
+ " <counter53>53</counter53>\n"
+ " <counter54>54</counter54>\n"
+ " <counter55>55</counter55>\n"
+ " <counter56>56</counter56>\n"
+ " <counter57>57</counter57>\n"
+ " <counter58>58</counter58>\n"
+ " <counter59>59</counter59>\n"
+ " <counter60>60</counter60>\n"
+ " <counter61>61</counter61>\n"
+ " <counter62>62</counter62>\n"
+ " <counter63>63</counter63>\n"
+ " <counter64>64</counter64>\n"
+ " <counter65>65</counter65>\n"
+ " <counter66>66</counter66>\n"
+ " <counter67>67</counter67>\n"
+ " <counter68>68</counter68>\n"
+ " <counter69>69</counter69>\n"
+ " <counter70>70</counter70>\n"
+ " <counter71>71</counter71>\n"
+ " <counter72>72</counter72>\n"
+ " <counter73>73</counter73>\n"
+ " <counter74>74</counter74>\n"
+ " <counter75>75</counter75>\n"
+ " <counter76>76</counter76>\n"
+ " <counter77>77</counter77>\n"
+ " <counter78>78</counter78>\n"
+ " <counter79>79</counter79>\n"
+ " <counter80>80</counter80>\n"
+ " <counter81>81</counter81>\n"
+ " <counter82>82</counter82>\n"
+ " <counter83>83</counter83>\n"
+ " <counter84>84</counter84>\n"
+ " <counter85>85</counter85>\n"
+ " <counter86>86</counter86>\n"
+ " <counter87>87</counter87>\n"
+ " <counter88>88</counter88>\n"
+ " <counter89>89</counter89>\n"
+ " <counter90>90</counter90>\n"
+ " <counter91>91</counter91>\n"
+ " <counter92>92</counter92>\n"
+ " <counter93>93</counter93>\n"
+ " <counter94>94</counter94>\n"
+ " <counter95>95</counter95>\n"
+ " <counter96>96</counter96>\n"
+ " <counter97>97</counter97>\n"
+ " <counter98>98</counter98>\n"
+ " <counter99>99</counter99>\n");
+ strcat(data_xml,
+ " <counter100>100</counter100>\n"
+ " <counter101>101</counter101>\n"
+ " <counter102>102</counter102>\n"
+ " <counter103>103</counter103>\n"
+ " <counter104>104</counter104>\n"
+ " <counter105>105</counter105>\n"
+ " <counter106>106</counter106>\n"
+ " <counter107>107</counter107>\n"
+ " <counter108>108</counter108>\n"
+ " <counter109>109</counter109>\n"
+ " <counter110>110</counter110>\n"
+ " <counter111>111</counter111>\n"
+ " <counter112>112</counter112>\n"
+ " <counter113>113</counter113>\n"
+ " <counter114>114</counter114>\n"
+ " <counter115>115</counter115>\n"
+ " <counter116>116</counter116>\n"
+ " <counter117>117</counter117>\n"
+ " <counter118>118</counter118>\n"
+ " <counter119>119</counter119>\n"
+ " <counter120>120</counter120>\n"
+ " <counter121>121</counter121>\n"
+ " <counter122>122</counter122>\n"
+ " <counter123>123</counter123>\n"
+ " <counter124>124</counter124>\n"
+ " <counter125>125</counter125>\n"
+ " <counter126>126</counter126>\n"
+ " <counter127>127</counter127>\n"
+ " <counter128>128</counter128>\n"
+ " <counter129>129</counter129>\n"
+ " <counter130>130</counter130>\n"
+ " <counter131>131</counter131>\n"
+ " <counter132>132</counter132>\n"
+ " <counter133>133</counter133>\n"
+ " <counter134>134</counter134>\n"
+ " <counter135>135</counter135>\n"
+ " <counter136>136</counter136>\n"
+ " <counter137>137</counter137>\n"
+ " <counter138>138</counter138>\n"
+ " <counter139>139</counter139>\n"
+ " <counter140>140</counter140>\n"
+ " <counter141>141</counter141>\n"
+ " <counter142>142</counter142>\n"
+ " <counter143>143</counter143>\n"
+ " <counter144>144</counter144>\n"
+ " <counter145>145</counter145>\n"
+ " <counter146>146</counter146>\n"
+ " <counter147>147</counter147>\n"
+ " <counter148>148</counter148>\n"
+ " <counter149>149</counter149>\n"
+ " <counter150>150</counter150>\n"
+ " <counter151>151</counter151>\n"
+ " <counter152>152</counter152>\n"
+ " <counter153>153</counter153>\n"
+ " <counter154>154</counter154>\n"
+ " <counter155>155</counter155>\n"
+ " <counter156>156</counter156>\n"
+ " <counter157>157</counter157>\n"
+ " <counter158>158</counter158>\n"
+ " <counter159>159</counter159>\n"
+ " <counter160>160</counter160>\n"
+ " <counter161>161</counter161>\n"
+ " <counter162>162</counter162>\n"
+ " <counter163>163</counter163>\n"
+ " <counter164>164</counter164>\n"
+ " <counter165>165</counter165>\n"
+ " <counter166>166</counter166>\n"
+ " <counter167>167</counter167>\n"
+ " <counter168>168</counter168>\n"
+ " <counter169>169</counter169>\n"
+ " <counter170>170</counter170>\n"
+ " <counter171>171</counter171>\n"
+ " <counter172>172</counter172>\n"
+ " <counter173>173</counter173>\n"
+ " <counter174>174</counter174>\n"
+ " <counter175>175</counter175>\n"
+ " <counter176>176</counter176>\n"
+ " <counter177>177</counter177>\n"
+ " <counter178>178</counter178>\n"
+ " <counter179>179</counter179>\n"
+ " <counter180>180</counter180>\n"
+ " <counter181>181</counter181>\n"
+ " <counter182>182</counter182>\n"
+ " <counter183>183</counter183>\n"
+ " <counter184>184</counter184>\n"
+ " <counter185>185</counter185>\n"
+ " <counter186>186</counter186>\n"
+ " <counter187>187</counter187>\n"
+ " <counter188>188</counter188>\n"
+ " <counter189>189</counter189>\n"
+ " <counter190>190</counter190>\n"
+ " <counter191>191</counter191>\n"
+ " <counter192>192</counter192>\n"
+ " <counter193>193</counter193>\n"
+ " <counter194>194</counter194>\n"
+ " <counter195>195</counter195>\n"
+ " <counter196>196</counter196>\n"
+ " <counter197>197</counter197>\n"
+ " <counter198>198</counter198>\n"
+ " <counter199>199</counter199>\n");
+ strcat(data_xml,
+ " <counter200>200</counter200>\n"
+ " <counter201>201</counter201>\n"
+ " <counter202>202</counter202>\n"
+ " <counter203>203</counter203>\n"
+ " <counter204>204</counter204>\n"
+ " <counter205>205</counter205>\n"
+ " <counter206>206</counter206>\n"
+ " <counter207>207</counter207>\n"
+ " <counter208>208</counter208>\n"
+ " <counter209>209</counter209>\n"
+ " <counter210>210</counter210>\n"
+ " <counter211>211</counter211>\n"
+ " <counter212>212</counter212>\n"
+ " <counter213>213</counter213>\n"
+ " <counter214>214</counter214>\n"
+ " <counter215>215</counter215>\n"
+ " <counter216>216</counter216>\n"
+ " <counter217>217</counter217>\n"
+ " <counter218>218</counter218>\n"
+ " <counter219>219</counter219>\n"
+ " <counter220>220</counter220>\n"
+ " <counter221>221</counter221>\n"
+ " <counter222>222</counter222>\n"
+ " <counter223>223</counter223>\n"
+ " <counter224>224</counter224>\n"
+ " <counter225>225</counter225>\n"
+ " <counter226>226</counter226>\n"
+ " <counter227>227</counter227>\n"
+ " <counter228>228</counter228>\n"
+ " <counter229>229</counter229>\n"
+ " <counter230>230</counter230>\n"
+ " <counter231>231</counter231>\n"
+ " <counter232>232</counter232>\n"
+ " <counter233>233</counter233>\n"
+ " <counter234>234</counter234>\n"
+ " <counter235>235</counter235>\n"
+ " <counter236>236</counter236>\n"
+ " <counter237>237</counter237>\n"
+ " <counter238>238</counter238>\n"
+ " <counter239>239</counter239>\n"
+ " <counter240>240</counter240>\n"
+ " <counter241>241</counter241>\n"
+ " <counter242>242</counter242>\n"
+ " <counter243>243</counter243>\n"
+ " <counter244>244</counter244>\n"
+ " <counter245>245</counter245>\n"
+ " <counter246>246</counter246>\n"
+ " <counter247>247</counter247>\n"
+ " <counter248>248</counter248>\n"
+ " <counter249>249</counter249>\n"
+ " <counter250>250</counter250>\n"
+ " <counter251>251</counter251>\n"
+ " <counter252>252</counter252>\n"
+ " <counter253>253</counter253>\n"
+ " <counter254>254</counter254>\n"
+ " <counter255>255</counter255>\n"
+ " <counter256>256</counter256>\n"
+ " <counter257>257</counter257>\n"
+ " <counter258>258</counter258>\n"
+ " <counter259>259</counter259>\n"
+ " <counter260>260</counter260>\n"
+ " <counter261>261</counter261>\n"
+ " <counter262>262</counter262>\n"
+ " <counter263>263</counter263>\n"
+ " <counter264>264</counter264>\n"
+ " <counter265>265</counter265>\n"
+ " <counter266>266</counter266>\n"
+ " <counter267>267</counter267>\n"
+ " <counter268>268</counter268>\n"
+ " <counter269>269</counter269>\n"
+ " <counter270>270</counter270>\n"
+ " <counter271>271</counter271>\n"
+ " <counter272>272</counter272>\n"
+ " <counter273>273</counter273>\n"
+ " <counter274>274</counter274>\n"
+ " <counter275>275</counter275>\n"
+ " <counter276>276</counter276>\n"
+ " <counter277>277</counter277>\n"
+ " <counter278>278</counter278>\n"
+ " <counter279>279</counter279>\n"
+ " <counter280>280</counter280>\n"
+ " <counter281>281</counter281>\n"
+ " <counter282>282</counter282>\n"
+ " <counter283>283</counter283>\n"
+ " <counter284>284</counter284>\n"
+ " <counter285>285</counter285>\n"
+ " <counter286>286</counter286>\n"
+ " <counter287>287</counter287>\n"
+ " <counter288>288</counter288>\n"
+ " <counter289>289</counter289>\n"
+ " <counter290>290</counter290>\n"
+ " <counter291>291</counter291>\n"
+ " <counter292>292</counter292>\n"
+ " <counter293>293</counter293>\n"
+ " <counter294>294</counter294>\n"
+ " <counter295>295</counter295>\n"
+ " <counter296>296</counter296>\n"
+ " <counter297>297</counter297>\n"
+ " <counter298>298</counter298>\n"
+ " <counter299>299</counter299>\n");
+ strcat(data_xml,
+ " <counter300>300</counter300>\n"
+ " <counter301>301</counter301>\n"
+ " <counter302>302</counter302>\n"
+ " <counter303>303</counter303>\n"
+ " <counter304>304</counter304>\n"
+ " <counter305>305</counter305>\n"
+ " <counter306>306</counter306>\n"
+ " <counter307>307</counter307>\n"
+ " <counter308>308</counter308>\n"
+ " <counter309>309</counter309>\n"
+ " <counter310>310</counter310>\n"
+ " <counter311>311</counter311>\n"
+ " <counter312>312</counter312>\n"
+ " <counter313>313</counter313>\n"
+ " <counter314>314</counter314>\n"
+ " <counter315>315</counter315>\n"
+ " <counter316>316</counter316>\n"
+ " <counter317>317</counter317>\n"
+ " <counter318>318</counter318>\n"
+ " <counter319>319</counter319>\n"
+ " <counter320>320</counter320>\n"
+ " <counter321>321</counter321>\n"
+ " <counter322>322</counter322>\n"
+ " <counter323>323</counter323>\n"
+ " <counter324>324</counter324>\n"
+ " <counter325>325</counter325>\n"
+ " <counter326>326</counter326>\n"
+ " <counter327>327</counter327>\n"
+ " <counter328>328</counter328>\n"
+ " <counter329>329</counter329>\n"
+ " <counter330>330</counter330>\n"
+ " <counter331>331</counter331>\n"
+ " <counter332>332</counter332>\n"
+ " <counter333>333</counter333>\n"
+ " <counter334>334</counter334>\n"
+ " <counter335>335</counter335>\n"
+ " <counter336>336</counter336>\n"
+ " <counter337>337</counter337>\n"
+ " <counter338>338</counter338>\n"
+ " <counter339>339</counter339>\n"
+ " <counter340>340</counter340>\n"
+ " <counter341>341</counter341>\n"
+ " <counter342>342</counter342>\n"
+ " <counter343>343</counter343>\n"
+ " <counter344>344</counter344>\n"
+ " <counter345>345</counter345>\n"
+ " <counter346>346</counter346>\n"
+ " <counter347>347</counter347>\n"
+ " <counter348>348</counter348>\n"
+ " <counter349>349</counter349>\n"
+ " <counter350>350</counter350>\n"
+ " <counter351>351</counter351>\n"
+ " <counter352>352</counter352>\n"
+ " <counter353>353</counter353>\n"
+ " <counter354>354</counter354>\n"
+ " <counter355>355</counter355>\n"
+ " <counter356>356</counter356>\n"
+ " <counter357>357</counter357>\n"
+ " <counter358>358</counter358>\n"
+ " <counter359>359</counter359>\n"
+ " <counter360>360</counter360>\n"
+ " <counter361>361</counter361>\n"
+ " <counter362>362</counter362>\n"
+ " <counter363>363</counter363>\n"
+ " <counter364>364</counter364>\n"
+ " <counter365>365</counter365>\n"
+ " <counter366>366</counter366>\n"
+ " <counter367>367</counter367>\n"
+ " <counter368>368</counter368>\n"
+ " <counter369>369</counter369>\n"
+ " <counter370>370</counter370>\n"
+ " <counter371>371</counter371>\n"
+ " <counter372>372</counter372>\n"
+ " <counter373>373</counter373>\n"
+ " <counter374>374</counter374>\n"
+ " <counter375>375</counter375>\n"
+ " <counter376>376</counter376>\n"
+ " <counter377>377</counter377>\n"
+ " <counter378>378</counter378>\n"
+ " <counter379>379</counter379>\n"
+ " <counter380>380</counter380>\n"
+ " <counter381>381</counter381>\n"
+ " <counter382>382</counter382>\n"
+ " <counter383>383</counter383>\n"
+ " <counter384>384</counter384>\n"
+ " <counter385>385</counter385>\n"
+ " <counter386>386</counter386>\n"
+ " <counter387>387</counter387>\n"
+ " <counter388>388</counter388>\n"
+ " <counter389>389</counter389>\n"
+ " <counter390>390</counter390>\n"
+ " <counter391>391</counter391>\n"
+ " <counter392>392</counter392>\n"
+ " <counter393>393</counter393>\n"
+ " <counter394>394</counter394>\n"
+ " <counter395>395</counter395>\n"
+ " <counter396>396</counter396>\n"
+ " <counter397>397</counter397>\n"
+ " <counter398>398</counter398>\n"
+ " <counter399>399</counter399>\n");
+ strcat(data_xml,
+ " <counter400>400</counter400>\n"
+ " <counter401>401</counter401>\n"
+ " <counter402>402</counter402>\n"
+ " <counter403>403</counter403>\n"
+ " <counter404>404</counter404>\n"
+ " <counter405>405</counter405>\n"
+ " <counter406>406</counter406>\n"
+ " <counter407>407</counter407>\n"
+ " <counter408>408</counter408>\n"
+ " <counter409>409</counter409>\n"
+ " <counter410>410</counter410>\n"
+ " <counter411>411</counter411>\n"
+ " <counter412>412</counter412>\n"
+ " <counter413>413</counter413>\n"
+ " <counter414>414</counter414>\n"
+ " <counter415>415</counter415>\n"
+ " <counter416>416</counter416>\n"
+ " <counter417>417</counter417>\n"
+ " <counter418>418</counter418>\n"
+ " <counter419>419</counter419>\n"
+ " <counter420>420</counter420>\n"
+ " <counter421>421</counter421>\n"
+ " <counter422>422</counter422>\n"
+ " <counter423>423</counter423>\n"
+ " <counter424>424</counter424>\n"
+ " <counter425>425</counter425>\n"
+ " <counter426>426</counter426>\n"
+ " <counter427>427</counter427>\n"
+ " <counter428>428</counter428>\n"
+ " <counter429>429</counter429>\n"
+ " <counter430>430</counter430>\n"
+ " <counter431>431</counter431>\n"
+ " <counter432>432</counter432>\n"
+ " <counter433>433</counter433>\n"
+ " <counter434>434</counter434>\n"
+ " <counter435>435</counter435>\n"
+ " <counter436>436</counter436>\n"
+ " <counter437>437</counter437>\n"
+ " <counter438>438</counter438>\n"
+ " <counter439>439</counter439>\n"
+ " <counter440>440</counter440>\n"
+ " <counter441>441</counter441>\n"
+ " <counter442>442</counter442>\n"
+ " <counter443>443</counter443>\n"
+ " <counter444>444</counter444>\n"
+ " <counter445>445</counter445>\n"
+ " <counter446>446</counter446>\n"
+ " <counter447>447</counter447>\n"
+ " <counter448>448</counter448>\n"
+ " <counter449>449</counter449>\n"
+ " <counter450>450</counter450>\n"
+ " <counter451>451</counter451>\n"
+ " <counter452>452</counter452>\n"
+ " <counter453>453</counter453>\n"
+ " <counter454>454</counter454>\n"
+ " <counter455>455</counter455>\n"
+ " <counter456>456</counter456>\n"
+ " <counter457>457</counter457>\n"
+ " <counter458>458</counter458>\n"
+ " <counter459>459</counter459>\n"
+ " <counter460>460</counter460>\n"
+ " <counter461>461</counter461>\n"
+ " <counter462>462</counter462>\n"
+ " <counter463>463</counter463>\n"
+ " <counter464>464</counter464>\n"
+ " <counter465>465</counter465>\n"
+ " <counter466>466</counter466>\n"
+ " <counter467>467</counter467>\n"
+ " <counter468>468</counter468>\n"
+ " <counter469>469</counter469>\n"
+ " <counter470>470</counter470>\n"
+ " <counter471>471</counter471>\n"
+ " <counter472>472</counter472>\n"
+ " <counter473>473</counter473>\n"
+ " <counter474>474</counter474>\n"
+ " <counter475>475</counter475>\n"
+ " <counter476>476</counter476>\n"
+ " <counter477>477</counter477>\n"
+ " <counter478>478</counter478>\n"
+ " <counter479>479</counter479>\n"
+ " <counter480>480</counter480>\n"
+ " <counter481>481</counter481>\n"
+ " <counter482>482</counter482>\n"
+ " <counter483>483</counter483>\n"
+ " <counter484>484</counter484>\n"
+ " <counter485>485</counter485>\n"
+ " <counter486>486</counter486>\n"
+ " <counter487>487</counter487>\n"
+ " <counter488>488</counter488>\n"
+ " <counter489>489</counter489>\n"
+ " <counter490>490</counter490>\n"
+ " <counter491>491</counter491>\n"
+ " <counter492>492</counter492>\n"
+ " <counter493>493</counter493>\n"
+ " <counter494>494</counter494>\n"
+ " <counter495>495</counter495>\n"
+ " <counter496>496</counter496>\n"
+ " <counter497>497</counter497>\n"
+ " <counter498>498</counter498>\n"
+ " <counter499>499</counter499>\n"
+ "</stats>\n");
+
+ UTEST_ADD_MODULE(counters_yang, LYS_IN_YANG, NULL, NULL);
+
+ check_print_parse(state, data_xml);
+
+ free(counters_yang);
+ free(data_xml);
+}
+
+#if 0
+
+static void
+test_types(void **state)
+{
+ struct state *st = (*state);
+ int ret;
+
+ ly_ctx_set_searchdir(st->ctx, TESTS_DIR "/data/files");
+ assert_non_null(ly_ctx_load_module(st->ctx, "types", NULL));
+
+ st->dt1 = lyd_parse_path(st->ctx, TESTS_DIR "/data/files/types.xml", LYD_XML, LYD_OPT_CONFIG);
+ assert_ptr_not_equal(st->dt1, NULL);
+
+ ret = lyd_print_mem(&st->mem, st->dt1, LYD_LYB, LYP_WITHSIBLINGS);
+ assert_int_equal(ret, 0);
+
+ st->dt2 = lyd_parse_mem(st->ctx, st->mem, LYD_LYB, LYD_OPT_CONFIG | LYD_OPT_STRICT);
+ assert_ptr_not_equal(st->dt2, NULL);
+
+ check_data_tree(st->dt1, st->dt2);
+}
+
+static void
+test_annotations(void **state)
+{
+ struct state *st = (*state);
+ int ret;
+
+ ly_ctx_set_searchdir(st->ctx, TESTS_DIR "/data/files");
+ assert_non_null(ly_ctx_load_module(st->ctx, "annotations", NULL));
+
+ st->dt1 = lyd_parse_path(st->ctx, TESTS_DIR "/data/files/annotations.xml", LYD_XML, LYD_OPT_CONFIG);
+ assert_ptr_not_equal(st->dt1, NULL);
+
+ ret = lyd_print_mem(&st->mem, st->dt1, LYD_LYB, LYP_WITHSIBLINGS);
+ assert_int_equal(ret, 0);
+
+ st->dt2 = lyd_parse_mem(st->ctx, st->mem, LYD_LYB, LYD_OPT_CONFIG | LYD_OPT_STRICT);
+ assert_ptr_not_equal(st->dt2, NULL);
+
+ check_data_tree(st->dt1, st->dt2);
+}
+
+static void
+test_similar_annot_names(void **state)
+{
+ struct state *st = (*state);
+ int ret;
+
+ ly_ctx_set_searchdir(st->ctx, TESTS_DIR "/data/files");
+ assert_non_null(ly_ctx_load_module(st->ctx, "annotations", NULL));
+
+ st->dt1 = lyd_parse_path(st->ctx, TESTS_DIR "/data/files/similar-annot-names.xml", LYD_XML, LYD_OPT_CONFIG);
+ assert_ptr_not_equal(st->dt1, NULL);
+
+ ret = lyd_print_mem(&st->mem, st->dt1, LYD_LYB, LYP_WITHSIBLINGS);
+ assert_int_equal(ret, 0);
+
+ st->dt2 = lyd_parse_mem(st->ctx, st->mem, LYD_LYB, LYD_OPT_CONFIG | LYD_OPT_STRICT);
+ assert_ptr_not_equal(st->dt2, NULL);
+
+ check_data_tree(st->dt1, st->dt2);
+}
+
+static void
+test_many_child_annot(void **state)
+{
+ struct state *st = (*state);
+ int ret;
+
+ ly_ctx_set_searchdir(st->ctx, TESTS_DIR "/data/files");
+ assert_non_null(ly_ctx_load_module(st->ctx, "annotations", NULL));
+
+ st->dt1 = lyd_parse_path(st->ctx, TESTS_DIR "/data/files/many-childs-annot.xml", LYD_XML, LYD_OPT_CONFIG);
+ assert_ptr_not_equal(st->dt1, NULL);
+
+ ret = lyd_print_mem(&st->mem, st->dt1, LYD_LYB, LYP_WITHSIBLINGS);
+ assert_int_equal(ret, 0);
+
+ st->dt2 = lyd_parse_mem(st->ctx, st->mem, LYD_LYB, LYD_OPT_CONFIG | LYD_OPT_STRICT);
+ assert_ptr_not_equal(st->dt2, NULL);
+
+ check_data_tree(st->dt1, st->dt2);
+}
+
+static void
+test_union(void **state)
+{
+ struct state *st = (*state);
+ int ret;
+
+ ly_ctx_set_searchdir(st->ctx, TESTS_DIR "/data/files");
+ assert_non_null(ly_ctx_load_module(st->ctx, "union", NULL));
+
+ st->dt1 = lyd_parse_path(st->ctx, TESTS_DIR "/data/files/union.xml", LYD_XML, LYD_OPT_CONFIG);
+ assert_ptr_not_equal(st->dt1, NULL);
+
+ ret = lyd_print_mem(&st->mem, st->dt1, LYD_LYB, LYP_WITHSIBLINGS);
+ assert_int_equal(ret, 0);
+
+ st->dt2 = lyd_parse_mem(st->ctx, st->mem, LYD_LYB, LYD_OPT_CONFIG | LYD_OPT_STRICT);
+ assert_ptr_not_equal(st->dt2, NULL);
+
+ check_data_tree(st->dt1, st->dt2);
+}
+
+static void
+test_union2(void **state)
+{
+ struct state *st = (*state);
+ int ret;
+
+ ly_ctx_set_searchdir(st->ctx, TESTS_DIR "/data/files");
+ assert_non_null(ly_ctx_load_module(st->ctx, "statements", NULL));
+
+ st->dt1 = lyd_parse_path(st->ctx, TESTS_DIR "/data/files/union2.xml", LYD_XML, LYD_OPT_CONFIG);
+ assert_ptr_not_equal(st->dt1, NULL);
+
+ ret = lyd_print_mem(&st->mem, st->dt1, LYD_LYB, LYP_WITHSIBLINGS);
+ assert_int_equal(ret, 0);
+
+ st->dt2 = lyd_parse_mem(st->ctx, st->mem, LYD_LYB, LYD_OPT_CONFIG | LYD_OPT_STRICT);
+ assert_ptr_not_equal(st->dt2, NULL);
+
+ check_data_tree(st->dt1, st->dt2);
+}
+
+static void
+test_collisions(void **state)
+{
+ struct state *st = (*state);
+ int ret;
+
+ ly_ctx_set_searchdir(st->ctx, TESTS_DIR "/data/files");
+ assert_non_null(ly_ctx_load_module(st->ctx, "annotations", NULL));
+
+ st->dt1 = lyd_parse_path(st->ctx, TESTS_DIR "/data/files/collisions.xml", LYD_XML, LYD_OPT_CONFIG);
+ assert_ptr_not_equal(st->dt1, NULL);
+
+ ret = lyd_print_mem(&st->mem, st->dt1, LYD_LYB, LYP_WITHSIBLINGS);
+ assert_int_equal(ret, 0);
+
+ st->dt2 = lyd_parse_mem(st->ctx, st->mem, LYD_LYB, LYD_OPT_CONFIG | LYD_OPT_STRICT);
+ assert_ptr_not_equal(st->dt2, NULL);
+
+ check_data_tree(st->dt1, st->dt2);
+}
+
+static void
+test_anydata(void **state)
+{
+ struct state *st = (*state);
+ const struct lys_module *mod;
+ int ret;
+ const char *test_anydata =
+ "module test-anydata {"
+ " namespace \"urn:test-anydata\";"
+ " prefix ya;"
+ ""
+ " container cont {"
+ " anydata ntf;"
+ " }"
+ "}";
+
+ assert_non_null(ly_ctx_load_module(st->ctx, "ietf-netconf-notifications", NULL));
+
+ st->dt1 = lyd_parse_path(st->ctx, TESTS_DIR "/data/files/ietf-netconf-notifications.json", LYD_JSON, LYD_OPT_NOTIF | LYD_OPT_TRUSTED, NULL);
+ assert_ptr_not_equal(st->dt1, NULL);
+
+ / *get notification in LYB format to set as anydata content * /
+ ret = lyd_print_mem(&st->mem, st->dt1, LYD_LYB, LYP_WITHSIBLINGS);
+ assert_int_equal(ret, 0);
+
+ lyd_free_withsiblings(st->dt1);
+ st->dt1 = NULL;
+
+ / *now comes the real test, test anydata * /
+ mod = lys_parse_mem(st->ctx, test_anydata, LYS_YANG);
+ assert_non_null(mod);
+
+ st->dt1 = lyd_new(NULL, mod, "cont");
+ assert_non_null(st->dt1);
+
+ assert_non_null(lyd_new_anydata(st->dt1, NULL, "ntf", st->mem, LYD_ANYDATA_LYBD));
+ st->mem = NULL;
+
+ ret = lyd_print_mem(&st->mem, st->dt1, LYD_LYB, LYP_WITHSIBLINGS);
+ assert_int_equal(ret, 0);
+
+ ret = lyd_validate(&st->dt1, LYD_OPT_CONFIG, NULL);
+ assert_int_equal(ret, 0);
+
+ st->dt2 = lyd_parse_mem(st->ctx, st->mem, LYD_LYB, LYD_OPT_CONFIG | LYD_OPT_STRICT);
+ assert_ptr_not_equal(st->dt2, NULL);
+
+ check_data_tree(st->dt1, st->dt2);
+
+ /* and also test the embedded notification itself */
+ free(st->mem);
+ ret = lyd_lyb_data_length(((struct lyd_node_anydata *)st->dt1->child)->value.mem);
+ st->mem = malloc(ret);
+ memcpy(st->mem, ((struct lyd_node_anydata *)st->dt1->child)->value.mem, ret);
+
+ lyd_free_withsiblings(st->dt2);
+ st->dt2 = lyd_parse_mem(st->ctx, st->mem, LYD_LYB, LYD_OPT_NOTIF | LYD_OPT_STRICT | LYD_OPT_NOEXTDEPS, NULL);
+ assert_ptr_not_equal(st->dt2, NULL);
+
+ /* parse the JSON again for this comparison */
+ lyd_free_withsiblings(st->dt1);
+ st->dt1 = lyd_parse_path(st->ctx, TESTS_DIR "/data/files/ietf-netconf-notifications.json", LYD_JSON, LYD_OPT_NOTIF | LYD_OPT_TRUSTED, NULL);
+ assert_ptr_not_equal(st->dt1, NULL);
+
+ check_data_tree(st->dt1, st->dt2);
+}
+
+static void
+test_submodule_feature(void **state)
+{
+ struct state *st = (*state);
+ const struct lys_module *mod;
+ int ret;
+
+ ly_ctx_set_searchdir(st->ctx, TESTS_DIR "/data/files");
+ mod = ly_ctx_load_module(st->ctx, "feature-submodule-main", NULL);
+ assert_non_null(mod);
+ assert_int_equal(lys_features_enable(mod, "test-submodule-feature"), 0);
+
+ st->dt1 = lyd_parse_path(st->ctx, TESTS_DIR "/data/files/test-submodule-feature.json", LYD_JSON, LYD_OPT_CONFIG);
+ assert_ptr_not_equal(st->dt1, NULL);
+
+ ret = lyd_print_mem(&st->mem, st->dt1, LYD_LYB, LYP_WITHSIBLINGS);
+ assert_int_equal(ret, 0);
+
+ st->dt2 = lyd_parse_mem(st->ctx, st->mem, LYD_LYB, LYD_OPT_CONFIG | LYD_OPT_STRICT);
+ assert_ptr_not_equal(st->dt2, NULL);
+
+ check_data_tree(st->dt1, st->dt2);
+}
+
+static void
+test_coliding_augments(void **state)
+{
+ struct state *st = (*state);
+ int ret;
+
+ ly_ctx_set_searchdir(st->ctx, TESTS_DIR "/data/files");
+ assert_non_null(ly_ctx_load_module(st->ctx, "augment-target", NULL));
+ assert_non_null(ly_ctx_load_module(st->ctx, "augment0", NULL));
+ assert_non_null(ly_ctx_load_module(st->ctx, "augment1", NULL));
+
+ st->dt1 = lyd_parse_path(st->ctx, TESTS_DIR "/data/files/augment.xml", LYD_XML, LYD_OPT_CONFIG);
+ assert_ptr_not_equal(st->dt1, NULL);
+
+ ret = lyd_print_mem(&st->mem, st->dt1, LYD_LYB, LYP_WITHSIBLINGS);
+ assert_int_equal(ret, 0);
+
+ st->dt2 = lyd_parse_mem(st->ctx, st->mem, LYD_LYB, LYD_OPT_CONFIG | LYD_OPT_STRICT);
+ assert_ptr_not_equal(st->dt2, NULL);
+
+ check_data_tree(st->dt1, st->dt2);
+}
+
+static void
+test_leafrefs(void **state)
+{
+ struct state *st = (*state);
+ int ret;
+
+ ly_ctx_set_searchdir(st->ctx, TESTS_DIR "/data/files");
+ assert_non_null(ly_ctx_load_module(st->ctx, "leafrefs2", NULL));
+
+ st->dt1 = lyd_parse_path(st->ctx, TESTS_DIR "/data/files/leafrefs2.json", LYD_JSON, LYD_OPT_CONFIG | LYD_OPT_STRICT);
+ assert_ptr_not_equal(st->dt1, NULL);
+
+ ret = lyd_print_mem(&st->mem, st->dt1, LYD_LYB, LYP_WITHSIBLINGS);
+ assert_int_equal(ret, 0);
+
+ st->dt2 = lyd_parse_mem(st->ctx, st->mem, LYD_LYB, LYD_OPT_CONFIG | LYD_OPT_STRICT);
+ assert_ptr_not_equal(st->dt2, NULL);
+
+ check_data_tree(st->dt1, st->dt2);
+}
+
+#endif
+
+int
+main(void)
+{
+ const struct CMUnitTest tests[] = {
+ UTEST(tests_leaflist),
+ UTEST(tests_list),
+ UTEST(tests_any),
+ UTEST(test_ietf_interfaces, setup),
+ UTEST(test_origin, setup),
+ UTEST(test_statements, setup),
+ UTEST(test_opaq, setup),
+ UTEST(test_collisions, setup),
+#if 0
+ cmocka_unit_test_setup_teardown(test_types, setup_f, teardown_f),
+ cmocka_unit_test_setup_teardown(test_annotations, setup_f, teardown_f),
+ cmocka_unit_test_setup_teardown(test_similar_annot_names, setup_f, teardown_f),
+ cmocka_unit_test_setup_teardown(test_many_child_annot, setup_f, teardown_f),
+ cmocka_unit_test_setup_teardown(test_union, setup_f, teardown_f),
+ cmocka_unit_test_setup_teardown(test_union2, setup_f, teardown_f),
+ cmocka_unit_test_setup_teardown(test_collisions, setup_f, teardown_f),
+ cmocka_unit_test_setup_teardown(test_anydata, setup_f, teardown_f),
+ cmocka_unit_test_setup_teardown(test_submodule_feature, setup_f, teardown_f),
+ cmocka_unit_test_setup_teardown(test_coliding_augments, setup_f, teardown_f),
+ cmocka_unit_test_setup_teardown(test_leafrefs, setup_f, teardown_f),
+#endif
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/tests/utests/data/test_merge.c b/tests/utests/data/test_merge.c
new file mode 100644
index 0000000..3e7b772
--- /dev/null
+++ b/tests/utests/data/test_merge.c
@@ -0,0 +1,756 @@
+/**
+ * @file test_merge.c
+ * @author Michal Vasko <mvasko@cesnet.cz>
+ * @brief tests for complex data merges.
+ *
+ * Copyright (c) 2020 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.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ */
+#define _UTEST_MAIN_
+#include "utests.h"
+
+#include "libyang.h"
+
+#define LYD_TREE_CREATE(INPUT, MODEL) \
+ CHECK_PARSE_LYD_PARAM(INPUT, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, MODEL)
+
+#define CONTEXT_CREATE \
+ CONTEXT_CREATE_PATH(NULL)
+
+#define LYD_TREE_CHECK_CHAR(MODEL, TEXT, PARAMS) \
+ CHECK_LYD_STRING_PARAM(MODEL, TEXT, LYD_XML, LYD_PRINT_WITHSIBLINGS | PARAMS)
+
+static void
+test_batch(void **state)
+{
+ const char *start =
+ "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
+ " <module>\n"
+ " <name>yang</name>\n"
+ " <revision>2016-02-11</revision>\n"
+ " <conformance-type>implement</conformance-type>\n"
+ " </module>\n"
+ "</modules-state>\n";
+ const char *data[] = {
+ "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
+ " <module>\n"
+ " <name>ietf-yang-library</name>\n"
+ " <revision>2016-02-01</revision>\n"
+ " <conformance-type>implement</conformance-type>\n"
+ " </module>\n"
+ "</modules-state>\n",
+ "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
+ " <module>\n"
+ " <name>ietf-netconf-acm</name>\n"
+ " <revision>2012-02-22</revision>\n"
+ " <conformance-type>implement</conformance-type>\n"
+ " </module>\n"
+ "</modules-state>\n",
+ "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
+ " <module>\n"
+ " <name>ietf-netconf</name>\n"
+ " <revision>2011-06-01</revision>\n"
+ " <conformance-type>implement</conformance-type>\n"
+ " </module>\n"
+ "</modules-state>\n",
+ "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
+ " <module>\n"
+ " <name>ietf-netconf-monitoring</name>\n"
+ " <revision>2010-10-04</revision>\n"
+ " <conformance-type>implement</conformance-type>\n"
+ " </module>\n"
+ "</modules-state>\n",
+ "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
+ " <module>\n"
+ " <name>ietf-netconf-with-defaults</name>\n"
+ " <revision>2011-06-01</revision>\n"
+ " <conformance-type>implement</conformance-type>\n"
+ " </module>\n"
+ "</modules-state>\n",
+ "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
+ " <module>\n"
+ " <name>yang</name>\n"
+ " <revision>2016-02-11</revision>\n"
+ " <namespace>urn:ietf:params:xml:ns:yang:1</namespace>\n"
+ " <conformance-type>implement</conformance-type>\n"
+ " </module>\n"
+ "</modules-state>\n",
+ "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
+ " <module>\n"
+ " <name>ietf-yang-library</name>\n"
+ " <revision>2016-02-01</revision>\n"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace>\n"
+ " <conformance-type>implement</conformance-type>\n"
+ " </module>\n"
+ "</modules-state>\n",
+ "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
+ " <module>\n"
+ " <name>ietf-netconf-acm</name>\n"
+ " <revision>2012-02-22</revision>\n"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-netconf-acm</namespace>\n"
+ " <conformance-type>implement</conformance-type>\n"
+ " </module>\n"
+ "</modules-state>\n",
+ "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
+ " <module>\n"
+ " <name>ietf-netconf</name>\n"
+ " <revision>2011-06-01</revision>\n"
+ " <namespace>urn:ietf:params:xml:ns:netconf:base:1.0</namespace>\n"
+ " <feature>writable-running</feature>\n"
+ " <feature>candidate</feature>\n"
+ " <feature>rollback-on-error</feature>\n"
+ " <feature>validate</feature>\n"
+ " <feature>startup</feature>\n"
+ " <feature>xpath</feature>\n"
+ " <conformance-type>implement</conformance-type>\n"
+ " </module>\n"
+ "</modules-state>\n",
+ "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
+ " <module>\n"
+ " <name>ietf-netconf-monitoring</name>\n"
+ " <revision>2010-10-04</revision>\n"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring</namespace>\n"
+ " <conformance-type>implement</conformance-type>\n"
+ " </module>\n"
+ "</modules-state>\n",
+ "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
+ " <module>\n"
+ " <name>ietf-netconf-with-defaults</name>\n"
+ " <revision>2011-06-01</revision>\n"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults</namespace>\n"
+ " <conformance-type>implement</conformance-type>\n"
+ " </module>\n"
+ "</modules-state>\n"
+ };
+ const char *output_template =
+ "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
+ " <module>\n"
+ " <name>yang</name>\n"
+ " <revision>2016-02-11</revision>\n"
+ " <namespace>urn:ietf:params:xml:ns:yang:1</namespace>\n"
+ " <conformance-type>implement</conformance-type>\n"
+ " </module>\n"
+ " <module>\n"
+ " <name>ietf-yang-library</name>\n"
+ " <revision>2016-02-01</revision>\n"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace>\n"
+ " <conformance-type>implement</conformance-type>\n"
+ " </module>\n"
+ " <module>\n"
+ " <name>ietf-netconf-acm</name>\n"
+ " <revision>2012-02-22</revision>\n"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-netconf-acm</namespace>\n"
+ " <conformance-type>implement</conformance-type>\n"
+ " </module>\n"
+ " <module>\n"
+ " <name>ietf-netconf</name>\n"
+ " <revision>2011-06-01</revision>\n"
+ " <namespace>urn:ietf:params:xml:ns:netconf:base:1.0</namespace>\n"
+ " <feature>writable-running</feature>\n"
+ " <feature>candidate</feature>\n"
+ " <feature>rollback-on-error</feature>\n"
+ " <feature>validate</feature>\n"
+ " <feature>startup</feature>\n"
+ " <feature>xpath</feature>\n"
+ " <conformance-type>implement</conformance-type>\n"
+ " </module>\n"
+ " <module>\n"
+ " <name>ietf-netconf-monitoring</name>\n"
+ " <revision>2010-10-04</revision>\n"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring</namespace>\n"
+ " <conformance-type>implement</conformance-type>\n"
+ " </module>\n"
+ " <module>\n"
+ " <name>ietf-netconf-with-defaults</name>\n"
+ " <revision>2011-06-01</revision>\n"
+ " <namespace>urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults</namespace>\n"
+ " <conformance-type>implement</conformance-type>\n"
+ " </module>\n"
+ "</modules-state>\n";
+
+ struct lyd_node *target;
+
+ CHECK_PARSE_LYD_PARAM(start, LYD_XML, LYD_PARSE_ONLY, 0, LY_SUCCESS, target);
+
+ for (int32_t i = 0; i < 11; ++i) {
+ struct lyd_node *source;
+
+ CHECK_PARSE_LYD_PARAM(data[i], LYD_XML, LYD_PARSE_ONLY, 0, LY_SUCCESS, source);
+ assert_int_equal(LY_SUCCESS, lyd_merge_siblings(&target, source, LYD_MERGE_DESTRUCT));
+ }
+
+ LYD_TREE_CHECK_CHAR(target, output_template, 0);
+
+ lyd_free_all(target);
+}
+
+static void
+test_leaf(void **state)
+{
+ const char *sch = "module x {"
+ " namespace urn:x;"
+ " prefix x;"
+ " container A {"
+ " leaf f1 {type string;}"
+ " container B {"
+ " leaf f2 {type string;}"
+ " }"
+ " }"
+ " }";
+ const char *trg = "<A xmlns=\"urn:x\"> <f1>block</f1> </A>";
+ const char *src = "<A xmlns=\"urn:x\"> <f1>aa</f1> <B> <f2>bb</f2> </B> </A>";
+ const char *result = "<A xmlns=\"urn:x\"><f1>aa</f1><B><f2>bb</f2></B></A>";
+ struct lyd_node *source, *target;
+
+ UTEST_ADD_MODULE(sch, LYS_IN_YANG, NULL, NULL);
+
+ LYD_TREE_CREATE(src, source);
+ LYD_TREE_CREATE(trg, target);
+
+ /* merge them */
+ assert_int_equal(lyd_merge_siblings(&target, source, 0), LY_SUCCESS);
+ assert_int_equal(lyd_validate_all(&target, NULL, LYD_VALIDATE_PRESENT, NULL), LY_SUCCESS);
+
+ /* check the result */
+ LYD_TREE_CHECK_CHAR(target, result, LYD_PRINT_SHRINK);
+
+ lyd_free_all(target);
+ lyd_free_all(source);
+}
+
+static void
+test_container(void **state)
+{
+ const char *sch =
+ "module A {\n"
+ " namespace \"aa:A\";\n"
+ " prefix A;\n"
+ " container A {\n"
+ " leaf f1 {type string;}\n"
+ " container B {\n"
+ " leaf f2 {type string;}\n"
+ " }\n"
+ " container C {\n"
+ " leaf f3 {type string;}\n"
+ " }\n"
+ " }\n"
+ "}\n";
+
+ const char *trg = "<A xmlns=\"aa:A\"> <B> <f2>aaa</f2> </B> </A>";
+ const char *src = "<A xmlns=\"aa:A\"> <C> <f3>bbb</f3> </C> </A>";
+ const char *result = "<A xmlns=\"aa:A\"><B><f2>aaa</f2></B><C><f3>bbb</f3></C></A>";
+ struct lyd_node *source, *target;
+
+ UTEST_ADD_MODULE(sch, LYS_IN_YANG, NULL, NULL);
+
+ LYD_TREE_CREATE(src, source);
+ LYD_TREE_CREATE(trg, target);
+
+ /* merge them */
+ assert_int_equal(lyd_merge_siblings(&target, source, 0), LY_SUCCESS);
+ assert_int_equal(lyd_validate_all(&target, NULL, LYD_VALIDATE_PRESENT, NULL), LY_SUCCESS);
+
+ /* check the result */
+ LYD_TREE_CHECK_CHAR(target, result, LYD_PRINT_SHRINK);
+
+ /* destroy */
+ lyd_free_all(source);
+ lyd_free_all(target);
+}
+
+static void
+test_list(void **state)
+{
+ const char *sch =
+ "module merge {\n"
+ " namespace \"http://test/merge\";\n"
+ " prefix merge;\n"
+ "\n"
+ " container inner1 {\n"
+ " list b-list1 {\n"
+ " key p1;\n"
+ " leaf p1 {\n"
+ " type uint8;\n"
+ " }\n"
+ " leaf p2 {\n"
+ " type string;\n"
+ " }\n"
+ " leaf p3 {\n"
+ " type boolean;\n"
+ " default false;\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ "}\n";
+
+ const char *trg =
+ "<inner1 xmlns=\"http://test/merge\">\n"
+ " <b-list1>\n"
+ " <p1>1</p1>\n"
+ " <p2>a</p2>\n"
+ " <p3>true</p3>\n"
+ " </b-list1>\n"
+ "</inner1>\n";
+ const char *src =
+ "<inner1 xmlns=\"http://test/merge\">\n"
+ " <b-list1>\n"
+ " <p1>1</p1>\n"
+ " <p2>b</p2>\n"
+ " </b-list1>\n"
+ "</inner1>\n";
+ const char *result =
+ "<inner1 xmlns=\"http://test/merge\">\n"
+ " <b-list1>\n"
+ " <p1>1</p1>\n"
+ " <p2>b</p2>\n"
+ " <p3>true</p3>\n"
+ " </b-list1>\n"
+ "</inner1>\n";
+ struct lyd_node *source, *target;
+
+ UTEST_ADD_MODULE(sch, LYS_IN_YANG, NULL, NULL);
+
+ LYD_TREE_CREATE(src, source);
+ LYD_TREE_CREATE(trg, target);
+
+ /* merge them */
+ assert_int_equal(lyd_merge_siblings(&target, source, 0), LY_SUCCESS);
+ assert_int_equal(lyd_validate_all(&target, NULL, LYD_VALIDATE_PRESENT, NULL), LY_SUCCESS);
+
+ /* check the result */
+ LYD_TREE_CHECK_CHAR(target, result, 0);
+
+ lyd_free_all(target);
+ lyd_free_all(source);
+}
+
+static void
+test_list2(void **state)
+{
+ const char *sch =
+ "module merge {\n"
+ " namespace \"http://test/merge\";\n"
+ " prefix merge;\n"
+ "\n"
+ " container inner1 {\n"
+ " list b-list1 {\n"
+ " key p1;\n"
+ " leaf p1 {\n"
+ " type uint8;\n"
+ " }\n"
+ " leaf p2 {\n"
+ " type string;\n"
+ " }\n"
+ " container inner2 {\n"
+ " leaf p3 {\n"
+ " type boolean;\n"
+ " default false;\n"
+ " }\n"
+ " leaf p4 {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ "}\n";
+
+ const char *trg =
+ "<inner1 xmlns=\"http://test/merge\">\n"
+ " <b-list1>\n"
+ " <p1>1</p1>\n"
+ " <p2>a</p2>\n"
+ " <inner2>\n"
+ " <p4>val</p4>\n"
+ " </inner2>\n"
+ " </b-list1>\n"
+ "</inner1>\n";
+ const char *src =
+ "<inner1 xmlns=\"http://test/merge\">\n"
+ " <b-list1>\n"
+ " <p1>1</p1>\n"
+ " <p2>b</p2>\n"
+ " </b-list1>\n"
+ "</inner1>\n";
+ const char *result =
+ "<inner1 xmlns=\"http://test/merge\">\n"
+ " <b-list1>\n"
+ " <p1>1</p1>\n"
+ " <p2>b</p2>\n"
+ " <inner2>\n"
+ " <p4>val</p4>\n"
+ " </inner2>\n"
+ " </b-list1>\n"
+ "</inner1>\n";
+ struct lyd_node *source, *target;
+
+ UTEST_ADD_MODULE(sch, LYS_IN_YANG, NULL, NULL);
+
+ LYD_TREE_CREATE(src, source);
+ LYD_TREE_CREATE(trg, target);
+
+ /* merge them */
+ assert_int_equal(lyd_merge_siblings(&target, source, 0), LY_SUCCESS);
+ assert_int_equal(lyd_validate_all(&target, NULL, LYD_VALIDATE_PRESENT, NULL), LY_SUCCESS);
+
+ /* check the result */
+ LYD_TREE_CHECK_CHAR(target, result, 0);
+
+ lyd_free_all(source);
+ lyd_free_all(target);
+}
+
+static void
+test_dup_inst_list(void **state)
+{
+ const char *sch =
+ "module merge {\n"
+ " namespace \"http://test/merge\";\n"
+ " prefix merge;\n"
+ "\n"
+ " container inner1 {\n"
+ " config false;\n"
+ " list b-list1 {\n"
+ " leaf p1 {\n"
+ " type uint8;\n"
+ " }\n"
+ " leaf p2 {\n"
+ " type string;\n"
+ " }\n"
+ " container inner2 {\n"
+ " leaf p4 {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ "}\n";
+
+ const char *trg =
+ "<inner1 xmlns=\"http://test/merge\">\n"
+ " <b-list1>\n"
+ " <p1>1</p1>\n"
+ " <p2>b</p2>\n"
+ " </b-list1>\n"
+ " <b-list1>\n"
+ " <p1>1</p1>\n"
+ " <p2>a</p2>\n"
+ " <inner2>\n"
+ " <p4>val</p4>\n"
+ " </inner2>\n"
+ " </b-list1>\n"
+ "</inner1>\n";
+ const char *src =
+ "<inner1 xmlns=\"http://test/merge\">\n"
+ " <b-list1>\n"
+ " <p1>1</p1>\n"
+ " <p2>b</p2>\n"
+ " </b-list1>\n"
+ " <b-list1>\n"
+ " <p1>2</p1>\n"
+ " <p2>a</p2>\n"
+ " </b-list1>\n"
+ "</inner1>\n";
+ const char *result =
+ "<inner1 xmlns=\"http://test/merge\">\n"
+ " <b-list1>\n"
+ " <p1>1</p1>\n"
+ " <p2>b</p2>\n"
+ " </b-list1>\n"
+ " <b-list1>\n"
+ " <p1>1</p1>\n"
+ " <p2>a</p2>\n"
+ " <inner2>\n"
+ " <p4>val</p4>\n"
+ " </inner2>\n"
+ " </b-list1>\n"
+ " <b-list1>\n"
+ " <p1>2</p1>\n"
+ " <p2>a</p2>\n"
+ " </b-list1>\n"
+ "</inner1>\n";
+ struct lyd_node *source, *target;
+
+ UTEST_ADD_MODULE(sch, LYS_IN_YANG, NULL, NULL);
+
+ LYD_TREE_CREATE(src, source);
+ LYD_TREE_CREATE(trg, target);
+
+ /* merge them */
+ assert_int_equal(lyd_merge_siblings(&target, source, 0), LY_SUCCESS);
+ assert_int_equal(lyd_validate_all(&target, NULL, LYD_VALIDATE_PRESENT, NULL), LY_SUCCESS);
+
+ /* check the result */
+ LYD_TREE_CHECK_CHAR(target, result, 0);
+
+ lyd_free_all(source);
+ lyd_free_all(target);
+}
+
+static void
+test_dup_inst_llist(void **state)
+{
+ const char *sch =
+ "module merge {\n"
+ " namespace \"http://test/merge\";\n"
+ " prefix merge;\n"
+ "\n"
+ " container inner1 {\n"
+ " config false;\n"
+ " leaf-list b-llist1 {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ "}\n";
+
+ const char *trg =
+ "<inner1 xmlns=\"http://test/merge\">\n"
+ " <b-llist1>a</b-llist1>\n"
+ " <b-llist1>b</b-llist1>\n"
+ " <b-llist1>c</b-llist1>\n"
+ " <b-llist1>d</b-llist1>\n"
+ " <b-llist1>a</b-llist1>\n"
+ " <b-llist1>b</b-llist1>\n"
+ " <b-llist1>c</b-llist1>\n"
+ " <b-llist1>d</b-llist1>\n"
+ "</inner1>\n";
+ const char *src =
+ "<inner1 xmlns=\"http://test/merge\">\n"
+ " <b-llist1>d</b-llist1>\n"
+ " <b-llist1>c</b-llist1>\n"
+ " <b-llist1>b</b-llist1>\n"
+ " <b-llist1>a</b-llist1>\n"
+ " <b-llist1>a</b-llist1>\n"
+ " <b-llist1>a</b-llist1>\n"
+ " <b-llist1>a</b-llist1>\n"
+ " <b-llist1>f</b-llist1>\n"
+ " <b-llist1>f</b-llist1>\n"
+ "</inner1>\n";
+ const char *result =
+ "<inner1 xmlns=\"http://test/merge\">\n"
+ " <b-llist1>a</b-llist1>\n"
+ " <b-llist1>b</b-llist1>\n"
+ " <b-llist1>c</b-llist1>\n"
+ " <b-llist1>d</b-llist1>\n"
+ " <b-llist1>a</b-llist1>\n"
+ " <b-llist1>b</b-llist1>\n"
+ " <b-llist1>c</b-llist1>\n"
+ " <b-llist1>d</b-llist1>\n"
+ " <b-llist1>a</b-llist1>\n"
+ " <b-llist1>a</b-llist1>\n"
+ " <b-llist1>f</b-llist1>\n"
+ " <b-llist1>f</b-llist1>\n"
+ "</inner1>\n";
+ struct lyd_node *source, *target;
+
+ UTEST_ADD_MODULE(sch, LYS_IN_YANG, NULL, NULL);
+
+ LYD_TREE_CREATE(src, source);
+ LYD_TREE_CREATE(trg, target);
+
+ /* merge them */
+ assert_int_equal(lyd_merge_siblings(&target, source, 0), LY_SUCCESS);
+ assert_int_equal(lyd_validate_all(&target, NULL, LYD_VALIDATE_PRESENT, NULL), LY_SUCCESS);
+
+ /* check the result */
+ LYD_TREE_CHECK_CHAR(target, result, 0);
+
+ lyd_free_all(source);
+ lyd_free_all(target);
+}
+
+static void
+test_case(void **state)
+{
+ const char *sch =
+ "module merge {\n"
+ " namespace \"http://test/merge\";\n"
+ " prefix merge;\n"
+ " container cont {\n"
+ " choice ch {\n"
+ " container inner {\n"
+ " leaf p1 {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ " case c2 {\n"
+ " leaf p1 {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ "}\n";
+
+ const char *trg =
+ "<cont xmlns=\"http://test/merge\">\n"
+ " <inner>\n"
+ " <p1>1</p1>\n"
+ " </inner>\n"
+ "</cont>\n";
+ const char *src =
+ "<cont xmlns=\"http://test/merge\">\n"
+ " <p1>1</p1>\n"
+ "</cont>\n";
+ const char *result =
+ "<cont xmlns=\"http://test/merge\">\n"
+ " <p1>1</p1>\n"
+ "</cont>\n";
+ struct lyd_node *source, *target;
+
+ UTEST_ADD_MODULE(sch, LYS_IN_YANG, NULL, NULL);
+
+ LYD_TREE_CREATE(src, source);
+ LYD_TREE_CREATE(trg, target);
+
+ /* merge them */
+ assert_int_equal(lyd_merge_siblings(&target, source, 0), LY_SUCCESS);
+ assert_int_equal(lyd_validate_all(&target, NULL, LYD_VALIDATE_PRESENT, NULL), LY_SUCCESS);
+
+ /* check the result */
+ LYD_TREE_CHECK_CHAR(target, result, 0);
+
+ lyd_free_all(source);
+ lyd_free_all(target);
+}
+
+static void
+test_dflt(void **state)
+{
+ const char *sch =
+ "module merge-dflt {\n"
+ " namespace \"urn:merge-dflt\";\n"
+ " prefix md;\n"
+ " container top {\n"
+ " leaf a {\n"
+ " type string;\n"
+ " }\n"
+ " leaf b {\n"
+ " type string;\n"
+ " }\n"
+ " leaf c {\n"
+ " type string;\n"
+ " default \"c_dflt\";\n"
+ " }\n"
+ " }\n"
+ "}\n";
+ struct lyd_node *target = NULL;
+ struct lyd_node *source = NULL;
+
+ UTEST_ADD_MODULE(sch, LYS_IN_YANG, NULL, NULL);
+
+ assert_int_equal(lyd_new_path(NULL, UTEST_LYCTX, "/merge-dflt:top/c", "c_dflt", 0, &target), LY_SUCCESS);
+ assert_int_equal(lyd_validate_all(&target, NULL, LYD_VALIDATE_PRESENT, NULL), LY_SUCCESS);
+
+ assert_int_equal(lyd_new_path(NULL, UTEST_LYCTX, "/merge-dflt:top/a", "a_val", 0, &source), LY_SUCCESS);
+ assert_int_equal(lyd_new_path(source, UTEST_LYCTX, "/merge-dflt:top/b", "b_val", 0, NULL), LY_SUCCESS);
+ assert_int_equal(lyd_validate_all(&source, NULL, LYD_VALIDATE_PRESENT, NULL), LY_SUCCESS);
+
+ assert_int_equal(lyd_merge_siblings(&target, source, LYD_MERGE_DESTRUCT | LYD_MERGE_DEFAULTS), LY_SUCCESS);
+ source = NULL;
+
+ /* c should be replaced and now be default */
+ assert_string_equal(lyd_child(target)->prev->schema->name, "c");
+ assert_true(lyd_child(target)->prev->flags & LYD_DEFAULT);
+
+ lyd_free_all(target);
+ lyd_free_all(source);
+}
+
+static void
+test_dflt2(void **state)
+{
+ const char *sch =
+ "module merge-dflt {\n"
+ " namespace \"urn:merge-dflt\";\n"
+ " prefix md;\n"
+ " container top {\n"
+ " leaf a {\n"
+ " type string;\n"
+ " }\n"
+ " leaf b {\n"
+ " type string;\n"
+ " }\n"
+ " leaf c {\n"
+ " type string;\n"
+ " default \"c_dflt\";\n"
+ " }\n"
+ " }\n"
+ "}\n";
+ struct lyd_node *target;
+ struct lyd_node *source;
+
+ UTEST_ADD_MODULE(sch, LYS_IN_YANG, NULL, NULL);
+
+ assert_int_equal(lyd_new_path(NULL, UTEST_LYCTX, "/merge-dflt:top/c", "c_dflt", 0, &target), LY_SUCCESS);
+ assert_int_equal(lyd_validate_all(&target, NULL, LYD_VALIDATE_PRESENT, NULL), LY_SUCCESS);
+
+ assert_int_equal(lyd_new_path(NULL, UTEST_LYCTX, "/merge-dflt:top/a", "a_val", 0, &source), LY_SUCCESS);
+ assert_int_equal(lyd_new_path(source, UTEST_LYCTX, "/merge-dflt:top/b", "b_val", 0, NULL), LY_SUCCESS);
+ assert_int_equal(lyd_validate_all(&source, NULL, LYD_VALIDATE_PRESENT, NULL), LY_SUCCESS);
+
+ assert_int_equal(lyd_merge_siblings(&target, source, 0), LY_SUCCESS);
+
+ /* c should not be replaced, so c remains not default */
+ assert_false(lyd_child(target)->flags & LYD_DEFAULT);
+
+ lyd_free_all(target);
+ lyd_free_all(source);
+}
+
+static void
+test_leafrefs(void **state)
+{
+ const char *sch = "module x {"
+ " namespace urn:x;"
+ " prefix x;"
+ " list l {"
+ " key n;"
+ " leaf n { type string; }"
+ " leaf t { type string; }"
+ " leaf r { type leafref { path '/l/n'; } }}}";
+ const char *trg = "<l xmlns=\"urn:x\"><n>a</n></l>"
+ "<l xmlns=\"urn:x\"><n>b</n><r>a</r></l>";
+ const char *src = "<l xmlns=\"urn:x\"><n>c</n><r>a</r></l>"
+ "<l xmlns=\"urn:x\"><n>a</n><t>*</t></l>";
+ const char *res = "<l xmlns=\"urn:x\"><n>a</n><t>*</t></l>"
+ "<l xmlns=\"urn:x\"><n>b</n><r>a</r></l>"
+ "<l xmlns=\"urn:x\"><n>c</n><r>a</r></l>";
+ struct lyd_node *source, *target;
+
+ UTEST_ADD_MODULE(sch, LYS_IN_YANG, NULL, NULL);
+
+ LYD_TREE_CREATE(src, source);
+ LYD_TREE_CREATE(trg, target);
+
+ assert_int_equal(lyd_merge_siblings(&target, source, 0), LY_SUCCESS);
+
+ LYD_TREE_CHECK_CHAR(target, res, LYD_PRINT_SHRINK);
+
+ lyd_free_all(source);
+ lyd_free_all(target);
+}
+
+int
+main(void)
+{
+ const struct CMUnitTest tests[] = {
+ UTEST(test_batch),
+ UTEST(test_leaf),
+ UTEST(test_container),
+ UTEST(test_list),
+ UTEST(test_list2),
+ UTEST(test_dup_inst_list),
+ UTEST(test_dup_inst_llist),
+ UTEST(test_case),
+ UTEST(test_dflt),
+ UTEST(test_dflt2),
+ UTEST(test_leafrefs),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/tests/utests/data/test_new.c b/tests/utests/data/test_new.c
new file mode 100644
index 0000000..7642960
--- /dev/null
+++ b/tests/utests/data/test_new.c
@@ -0,0 +1,446 @@
+/**
+ * @file test_new.c
+ * @author: Michal Vasko <mvasko@cesnet.cz>
+ * @brief unit tests for functions for creating data
+ *
+ * Copyright (c) 2020 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.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ */
+#define _UTEST_MAIN_
+#include "utests.h"
+
+#include "libyang.h"
+
+/* common module for the tests */
+const char *schema_a = "module a {\n"
+ " namespace urn:tests:a;\n"
+ " prefix a;yang-version 1.1;\n"
+ " list l1 {\n"
+ " key \"a b\";\n"
+ " leaf a {\n"
+ " type string;\n"
+ " }\n"
+ " leaf b {\n"
+ " type string;\n"
+ " }\n"
+ " leaf c {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ " list l11 {\n"
+ " key \"a\";\n"
+ " leaf a {\n"
+ " type uint32;\n"
+ " }\n"
+ " leaf b {\n"
+ " type uint32;\n"
+ " }\n"
+ " }\n"
+ " leaf foo {\n"
+ " type uint16;\n"
+ " }\n"
+ " leaf-list ll {\n"
+ " type string;\n"
+ " }\n"
+ " container c {\n"
+ " leaf-list x {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ " anydata any {\n"
+ " config false;\n"
+ " }\n"
+ " leaf-list ll2 {\n"
+ " config false;\n"
+ " type string;\n"
+ " }\n"
+ " list l2 {\n"
+ " config false;\n"
+ " container c {\n"
+ " leaf x {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " container c2 {\n"
+ " config false;\n"
+ " list l3 {\n"
+ " leaf x {\n"
+ " type string;\n"
+ " }\n"
+ " leaf y {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " rpc oper {\n"
+ " input {\n"
+ " leaf param {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ " output {\n"
+ " leaf param {\n"
+ " type int8;\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ "}\n";
+
+static void
+test_top_level(void **state)
+{
+ struct lys_module *mod;
+ struct lyd_node *node, *rpc;
+
+ UTEST_ADD_MODULE(schema_a, LYS_IN_YANG, NULL, &mod);
+
+ /* list */
+ assert_int_equal(lyd_new_list(NULL, mod, "l1", 0, &node, "val_a", "val_b"), LY_SUCCESS);
+ lyd_free_tree(node);
+
+ assert_int_equal(lyd_new_list2(NULL, mod, "l1", "[]", 0, &node), LY_EVALID);
+ CHECK_LOG_CTX("Unexpected XPath token \"]\" (\"]\").", "Schema location \"/a:l1\".");
+
+ assert_int_equal(lyd_new_list2(NULL, mod, "l1", "[key1='a'][key2='b']", 0, &node), LY_ENOTFOUND);
+ CHECK_LOG_CTX("Not found node \"key1\" in path.", "Schema location \"/a:l1\".");
+
+ assert_int_equal(lyd_new_list2(NULL, mod, "l1", "[a='a'][b='b'][c='c']", 0, &node), LY_EVALID);
+ CHECK_LOG_CTX("Key expected instead of leaf \"c\" in path.", "Schema location \"/a:l1\".");
+
+ assert_int_equal(lyd_new_list2(NULL, mod, "c", "[a='a'][b='b']", 0, &node), LY_ENOTFOUND);
+ CHECK_LOG_CTX("List node \"c\" not found.", NULL);
+
+ assert_int_equal(lyd_new_list2(NULL, mod, "l1", "[a='a'][b='b']", 0, &node), LY_SUCCESS);
+ lyd_free_tree(node);
+
+ assert_int_equal(lyd_new_list2(NULL, mod, "l1", "[a=''][b='']", 0, &node), LY_SUCCESS);
+ lyd_free_tree(node);
+
+ assert_int_equal(lyd_new_list2(NULL, mod, "l1", "[a:a='a'][a:b='b']", 0, &node), LY_SUCCESS);
+ lyd_free_tree(node);
+
+ assert_int_equal(lyd_new_list2(NULL, mod, "l1", "[a= 'a']\n[b =\t'b']", 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\".");
+
+ assert_int_equal(lyd_new_term(NULL, mod, "c", "value", 0, &node), LY_ENOTFOUND);
+ CHECK_LOG_CTX("Term node \"c\" not found.", NULL);
+
+ assert_int_equal(lyd_new_term(NULL, mod, "foo", "256", 0, &node), LY_SUCCESS);
+ lyd_free_tree(node);
+
+ /* leaf-list */
+ assert_int_equal(lyd_new_term(NULL, mod, "ll", "ahoy", 0, &node), LY_SUCCESS);
+ lyd_free_tree(node);
+
+ /* container */
+ assert_int_equal(lyd_new_inner(NULL, mod, "c", 0, &node), LY_SUCCESS);
+ lyd_free_tree(node);
+
+ assert_int_equal(lyd_new_inner(NULL, mod, "l1", 0, &node), LY_ENOTFOUND);
+ CHECK_LOG_CTX("Inner node (container, notif, RPC, or action) \"l1\" not found.", NULL);
+
+ assert_int_equal(lyd_new_inner(NULL, mod, "l2", 0, &node), LY_ENOTFOUND);
+ CHECK_LOG_CTX("Inner node (container, notif, RPC, or action) \"l2\" not found.", NULL);
+
+ /* anydata */
+ assert_int_equal(lyd_new_any(NULL, mod, "any", "{\"node\":\"val\"}", 0, LYD_ANYDATA_STRING, 0, &node), LY_SUCCESS);
+ lyd_free_tree(node);
+ assert_int_equal(lyd_new_any(NULL, mod, "any", "<node>val</node>", 0, LYD_ANYDATA_STRING, 0, &node), LY_SUCCESS);
+ lyd_free_tree(node);
+
+ /* key-less list */
+ assert_int_equal(lyd_new_list2(NULL, mod, "l2", "[a='a'][b='b']", 0, &node), LY_EVALID);
+ CHECK_LOG_CTX("List predicate defined for keyless list \"l2\" in path.", "Schema location \"/a:l2\".");
+
+ assert_int_equal(lyd_new_list2(NULL, mod, "l2", "", 0, &node), LY_SUCCESS);
+ lyd_free_tree(node);
+
+ assert_int_equal(lyd_new_list2(NULL, mod, "l2", NULL, 0, &node), LY_SUCCESS);
+ lyd_free_tree(node);
+
+ assert_int_equal(lyd_new_list(NULL, mod, "l2", 0, &node), LY_SUCCESS);
+ lyd_free_tree(node);
+
+ /* RPC */
+ assert_int_equal(lyd_new_inner(NULL, mod, "oper", 0, &rpc), LY_SUCCESS);
+ assert_int_equal(lyd_new_term(rpc, mod, "param", "22", 0, &node), LY_SUCCESS);
+ assert_int_equal(LY_TYPE_STRING, ((struct lysc_node_leaf *)node->schema)->type->basetype);
+ assert_int_equal(lyd_new_term(rpc, mod, "param", "22", 1, &node), LY_SUCCESS);
+ assert_int_equal(LY_TYPE_INT8, ((struct lysc_node_leaf *)node->schema)->type->basetype);
+ lyd_free_tree(rpc);
+}
+
+static void
+test_opaq(void **state)
+{
+ struct lyd_node *root, *node;
+ struct lyd_node_opaq *opq;
+
+ UTEST_ADD_MODULE(schema_a, LYS_IN_YANG, NULL, NULL);
+
+ assert_int_equal(lyd_new_opaq(NULL, UTEST_LYCTX, "node1", NULL, NULL, "my-module", &root), LY_SUCCESS);
+ assert_null(root->schema);
+ opq = (struct lyd_node_opaq *)root;
+ assert_string_equal(opq->name.name, "node1");
+ assert_string_equal(opq->name.module_name, "my-module");
+ assert_string_equal(opq->value, "");
+
+ assert_int_equal(lyd_new_opaq(root, NULL, "node2", "value", NULL, "my-module2", &node), LY_SUCCESS);
+ assert_null(node->schema);
+ opq = (struct lyd_node_opaq *)node;
+ assert_string_equal(opq->name.name, "node2");
+ assert_string_equal(opq->name.module_name, "my-module2");
+ assert_string_equal(opq->value, "value");
+ assert_ptr_equal(opq->parent, root);
+
+ lyd_free_tree(root);
+}
+
+static void
+test_path(void **state)
+{
+ LY_ERR ret;
+ struct lyd_node *root, *node, *parent;
+ struct lys_module *mod;
+ char *str;
+
+ UTEST_ADD_MODULE(schema_a, LYS_IN_YANG, NULL, &mod);
+
+ /* create 2 nodes */
+ ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:c/x[.='val']", "vvv", 0, 0, 0, &root, &node);
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_non_null(root);
+ assert_string_equal(root->schema->name, "c");
+ assert_non_null(node);
+ assert_string_equal(node->schema->name, "x");
+ assert_string_equal("val", lyd_get_value(node));
+
+ /* append another */
+ ret = lyd_new_path2(root, NULL, "/a:c/x", "val2", 0, 0, 0, &parent, &node);
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_ptr_equal(parent, node);
+ assert_string_equal(node->schema->name, "x");
+ assert_string_equal("val2", lyd_get_value(node));
+
+ /* and a last one */
+ ret = lyd_new_path2(root, NULL, "x", "val3", 0, 0, 0, &parent, &node);
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_ptr_equal(parent, node);
+ assert_string_equal(node->schema->name, "x");
+ assert_string_equal("val3", lyd_get_value(node));
+
+ lyd_free_tree(root);
+
+ /* try LYD_NEWOPT_OPAQ */
+ ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:l1", NULL, 0, 0, 0, NULL, NULL);
+ assert_int_equal(ret, LY_EINVAL);
+ CHECK_LOG_CTX("Predicate missing for list \"l1\" in path \"/a:l1\".", "Schema location \"/a:l1\".");
+
+ ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:l1", NULL, 0, 0, LYD_NEW_PATH_OPAQ, NULL, &root);
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_non_null(root);
+ assert_null(root->schema);
+
+ lyd_free_tree(root);
+
+ ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:foo", NULL, 0, 0, 0, NULL, NULL);
+ assert_int_equal(ret, LY_EVALID);
+ CHECK_LOG_CTX("Invalid type uint16 empty value.", "Schema location \"/a:foo\".");
+
+ ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:foo", NULL, 0, 0, LYD_NEW_PATH_OPAQ, NULL, &root);
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_non_null(root);
+ assert_null(root->schema);
+
+ lyd_free_tree(root);
+
+ ret = lyd_new_path(NULL, UTEST_LYCTX, "/a:l11", NULL, LYD_NEW_PATH_OPAQ, &root);
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_non_null(root);
+ assert_null(root->schema);
+
+ ret = lyd_new_path(root, NULL, "a", NULL, LYD_NEW_PATH_OPAQ, NULL);
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_non_null(lyd_child(root));
+ assert_null(lyd_child(root)->schema);
+
+ ret = lyd_new_path(root, NULL, "b", NULL, LYD_NEW_PATH_OPAQ, NULL);
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_non_null(lyd_child(root)->next);
+ assert_null(lyd_child(root)->next->schema);
+
+ lyd_free_tree(root);
+
+ /* key-less list */
+ ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:c2/l3/x", "val1", 0, 0, 0, &root, &node);
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_non_null(root);
+ assert_string_equal(node->schema->name, "x");
+ assert_string_equal("val1", lyd_get_value(node));
+
+ ret = lyd_new_path2(root, NULL, "/a:c2/l3[1]", NULL, 0, 0, 0, NULL, &node);
+ assert_int_equal(ret, LY_EEXIST);
+
+ ret = lyd_new_path2(root, NULL, "/a:c2/l3[2]/x", "val2", 0, 0, 0, NULL, &node);
+ assert_int_equal(ret, LY_SUCCESS);
+
+ ret = lyd_new_path2(root, NULL, "/a:c2/l3/x", "val3", 0, 0, 0, NULL, &node);
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_non_null(node);
+
+ ret = lyd_new_path2(root, NULL, "/a:c2/l3[4]/x", "empty", 0, 0, 0, NULL, &node);
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_non_null(node);
+
+ ret = lyd_new_path2(root, NULL, "/a:c2/l3[4]/x", "val4", 0, 0, LYD_NEW_PATH_UPDATE, NULL, &node);
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_non_null(node);
+
+ ret = lyd_new_path2(root, NULL, "/a:c2/l3[5]/x", "val5", 0, 0, 0, NULL, &node);
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_non_null(node);
+
+ ret = lyd_new_path2(root, NULL, "/a:c2/l3[6]/x", "val6", 0, 0, 0, NULL, &node);
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_non_null(node);
+
+ lyd_print_mem(&str, root, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+ assert_string_equal(str,
+ "<c2 xmlns=\"urn:tests:a\">\n"
+ " <l3>\n"
+ " <x>val1</x>\n"
+ " </l3>\n"
+ " <l3>\n"
+ " <x>val2</x>\n"
+ " </l3>\n"
+ " <l3>\n"
+ " <x>val3</x>\n"
+ " </l3>\n"
+ " <l3>\n"
+ " <x>val4</x>\n"
+ " </l3>\n"
+ " <l3>\n"
+ " <x>val5</x>\n"
+ " </l3>\n"
+ " <l3>\n"
+ " <x>val6</x>\n"
+ " </l3>\n"
+ "</c2>\n");
+ free(str);
+ lyd_free_siblings(root);
+
+ /* state leaf-list */
+ ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:ll2", "val_first", 0, 0, 0, &root, &node);
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_non_null(root);
+ assert_string_equal(node->schema->name, "ll2");
+ assert_string_equal("val_first", lyd_get_value(node));
+
+ ret = lyd_new_path2(root, NULL, "/a:ll2[1]", "", 0, 0, 0, NULL, &node);
+ assert_int_equal(ret, LY_EEXIST);
+
+ ret = lyd_new_path2(root, NULL, "/a:ll2[2]", "val2", 0, 0, 0, NULL, &node);
+ assert_int_equal(ret, LY_SUCCESS);
+
+ ret = lyd_new_path2(root, NULL, "/a:ll2[1]", "val", 0, 0, LYD_NEW_PATH_UPDATE, NULL, &node);
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_non_null(node);
+
+ ret = lyd_new_path2(root, UTEST_LYCTX, "/a:ll2", "val3", 0, 0, 0, NULL, &node);
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_non_null(node);
+
+ ret = lyd_new_path2(root, NULL, "/a:ll2[3][.='val3']", NULL, 0, 0, 0, NULL, &node);
+ assert_int_equal(ret, LY_EVALID);
+
+ lyd_print_mem(&str, root, LYD_XML, LYD_PRINT_WITHSIBLINGS);
+ assert_string_equal(str,
+ "<ll2 xmlns=\"urn:tests:a\">val</ll2>\n"
+ "<ll2 xmlns=\"urn:tests:a\">val2</ll2>\n"
+ "<ll2 xmlns=\"urn:tests:a\">val3</ll2>\n");
+ free(str);
+ lyd_free_siblings(root);
+
+ /* anydata */
+ ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:any", "<elem>val</elem>", 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,
+ "<any xmlns=\"urn:tests:a\">\n"
+ " <elem>val</elem>\n"
+ "</any>\n");
+ free(str);
+ lyd_print_mem(&str, root, LYD_JSON, LYD_PRINT_WITHSIBLINGS);
+ assert_string_equal(str,
+ "{\n"
+ " \"a:any\": {\n"
+ " \"elem\": \"val\"\n"
+ " }\n"
+ "}\n");
+ free(str);
+ lyd_free_siblings(root);
+}
+
+static void
+test_path_ext(void **state)
+{
+ LY_ERR ret;
+ struct lyd_node *root, *node;
+ struct lys_module *mod;
+ const char *mod_str = "module ext {yang-version 1.1; namespace urn:tests:extensions:ext; prefix e;"
+ "import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
+ "rc:yang-data template {container c {leaf x {type string;} leaf y {type string;} leaf z {type string;}}}}";
+
+ assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_DIR_MODULES_YANG));
+ assert_non_null(ly_ctx_load_module(UTEST_LYCTX, "ietf-restconf", "2017-01-26", NULL));
+
+ UTEST_ADD_MODULE(mod_str, LYS_IN_YANG, NULL, &mod);
+
+ /* create x */
+ ret = lyd_new_ext_path(NULL, &mod->compiled->exts[0], "/ext:c/x", "xxx", 0, &root);
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_non_null(root);
+ assert_string_equal(root->schema->name, "c");
+ assert_non_null(node = lyd_child(root));
+ assert_string_equal(node->schema->name, "x");
+ assert_string_equal("xxx", lyd_get_value(node));
+
+ /* append y */
+ ret = lyd_new_ext_path(root, &mod->compiled->exts[0], "/ext:c/y", "yyy", 0, &node);
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_string_equal(node->schema->name, "y");
+ assert_string_equal("yyy", lyd_get_value(node));
+
+ /* append z */
+ ret = lyd_new_path(root, NULL, "ext:z", "zzz", 0, &node);
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_string_equal(node->schema->name, "z");
+ assert_string_equal("zzz", lyd_get_value(node));
+
+ lyd_free_tree(root);
+}
+
+int
+main(void)
+{
+ const struct CMUnitTest tests[] = {
+ UTEST(test_top_level),
+ UTEST(test_opaq),
+ UTEST(test_path),
+ UTEST(test_path_ext),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/tests/utests/data/test_parser_json.c b/tests/utests/data/test_parser_json.c
new file mode 100644
index 0000000..d341e31
--- /dev/null
+++ b/tests/utests/data/test_parser_json.c
@@ -0,0 +1,793 @@
+/*
+ * @file test_parser_json.c
+ * @author: Radek Krejci <rkrejci@cesnet.cz>
+ * @brief unit tests for functions from parser_xml.c
+ *
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ */
+#define _UTEST_MAIN_
+#include "utests.h"
+
+#include "context.h"
+#include "in.h"
+#include "out.h"
+#include "parser_data.h"
+#include "printer_data.h"
+#include "tests_config.h"
+#include "tree_data_internal.h"
+#include "tree_schema.h"
+
+static int
+setup(void **state)
+{
+ const char *schema = "module a {namespace urn:tests:a;prefix a;yang-version 1.1; import ietf-yang-metadata {prefix md;}"
+ "md:annotation hint { type int8;}"
+ "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;}}"
+ "}"
+ "leaf foo { type string;}"
+ "container c {"
+ " leaf x {type string;}"
+ " action act { input { leaf al {type string;} } output { leaf al {type uint8;} } }"
+ " notification n1 { leaf nl {type string;} }"
+ "}"
+ "container cp {presence \"container switch\"; leaf y {type string;} leaf z {type int8;}}"
+ "anydata any {config false;}"
+ "anyxml axml;"
+ "leaf-list ll1 { type uint8; }"
+ "leaf foo2 { type string; default \"default-val\"; }"
+ "leaf foo3 { type uint32; }"
+ "notification n2;}";
+
+ UTEST_SETUP;
+
+ UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
+ assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_DIR_MODULES_YANG));
+
+ return 0;
+}
+
+#define CHECK_PARSE_LYD(INPUT, PARSE_OPTION, VALIDATE_OPTION, TREE) \
+ CHECK_PARSE_LYD_PARAM(INPUT, LYD_JSON, PARSE_OPTION, VALIDATE_OPTION, LY_SUCCESS, TREE)
+
+#define PARSER_CHECK_ERROR(INPUT, PARSE_OPTION, VALIDATE_OPTION, MODEL, RET_VAL, ERR_MESSAGE, ERR_PATH) \
+ assert_int_equal(RET_VAL, lyd_parse_data_mem(UTEST_LYCTX, INPUT, LYD_JSON, PARSE_OPTION, VALIDATE_OPTION, &MODEL));\
+ CHECK_LOG_CTX(ERR_MESSAGE, ERR_PATH);\
+ assert_null(MODEL)
+
+#define CHECK_LYD_STRING(IN_MODEL, PRINT_OPTION, TEXT) \
+ CHECK_LYD_STRING_PARAM(IN_MODEL, TEXT, LYD_JSON, PRINT_OPTION)
+
+static void
+test_leaf(void **state)
+{
+ struct lyd_node *tree;
+ struct lyd_node_term *leaf;
+ const char *data;
+
+ assert_non_null(ly_ctx_load_module(UTEST_LYCTX, "ietf-netconf-with-defaults", "2011-06-01", NULL));
+
+ data = "{\"a:foo\":\"foo value\"}";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "foo", 1, LYS_LEAF, 0, 0, NULL, 0);
+ leaf = (struct lyd_node_term *)tree;
+ CHECK_LYD_VALUE(leaf->value, STRING, "foo value");
+
+ CHECK_LYSC_NODE(tree->next->next->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_SET_DFLT, 1, "foo2",
+ 1, LYS_LEAF, 0, 0, NULL, 0);
+ leaf = (struct lyd_node_term *)tree->next->next;
+
+ CHECK_LYD_VALUE(leaf->value, STRING, "default-val");
+ assert_true(leaf->flags & LYD_DEFAULT);
+
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ /* make foo2 explicit */
+ data = "{\"a:foo2\":\"default-val\"}";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ assert_non_null(tree);
+ tree = tree->next;
+ CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_SET_DFLT, 1, "foo2",
+ 1, LYS_LEAF, 0, 0, NULL, 0);
+ leaf = (struct lyd_node_term *)tree;
+ CHECK_LYD_VALUE(leaf->value, STRING, "default-val");
+ assert_false(leaf->flags & LYD_DEFAULT);
+
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ /* parse foo2 but make it implicit */
+ data = "{\"a:foo2\":\"default-val\",\"@a:foo2\":{\"ietf-netconf-with-defaults:default\":true}}";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ assert_non_null(tree);
+ tree = tree->next;
+ CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_SET_DFLT, 1, "foo2",
+ 1, LYS_LEAF, 0, 0, NULL, 0);
+ leaf = (struct lyd_node_term *)tree;
+ CHECK_LYD_VALUE(leaf->value, STRING, "default-val");
+ assert_true(leaf->flags & LYD_DEFAULT);
+
+ /* print default values */
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS | LYD_PRINT_WD_ALL_TAG, data);
+ lyd_free_all(tree);
+
+ /* skip leaf */
+ data = "{\"a:cp\":{\"x\":\"val\",\"y\":\"valy\",\"z\":5}}";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ assert_non_null(tree);
+
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, "{\"a:cp\":{\"y\":\"valy\",\"z\":5}}");
+ lyd_free_all(tree);
+
+ /* multiple meatadata hint and unknown metadata xxx supposed to be skipped since it is from missing schema */
+ data = "{\"@a:foo\":{\"a:hint\":1,\"a:hint\":2,\"x:xxx\":{\"value\":\"/x:no/x:yes\"}},\"a:foo\":\"xxx\"}";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "foo", 1, LYS_LEAF, 0, 0, NULL, 0);
+ CHECK_LYD_META(tree->meta, 1, "hint", 1, 1, INT8, "1", 1);
+ CHECK_LYD_META(tree->meta->next, 1, "hint", 0, 1, INT8, "2", 2);
+ assert_null(tree->meta->next->next);
+
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS,
+ "{\"a:foo\":\"xxx\",\"@a:foo\":{\"a:hint\":1,\"a:hint\":2}}");
+ lyd_free_all(tree);
+
+ PARSER_CHECK_ERROR(data, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
+ "Unknown (or not implemented) YANG module \"x\" of metadata \"x:xxx\".", "Data location \"/@a:foo\", line number 1.");
+
+ /* missing referenced metadata node */
+ PARSER_CHECK_ERROR("{\"@a:foo\" : { \"a:hint\" : 1 }}", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
+ "Missing JSON data instance to be coupled with @a:foo metadata.", "Data location \"/@a:foo\", line number 1.");
+
+ /* missing namespace for meatadata*/
+ PARSER_CHECK_ERROR("{\"a:foo\" : \"value\", \"@a:foo\" : { \"hint\" : 1 }}", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
+ "Metadata in JSON must be namespace-qualified, missing prefix for \"hint\".",
+ "Schema location \"/a:foo\", line number 1.");
+
+ /* invalid JSON type */
+ data = "{\"a:l1\" : [{ \"a\" : \"val-a\", \"b\" : \"val-b\", \"c\" : 1, \"cont\" : { \"e\" : \"0\" } }]}";
+ PARSER_CHECK_ERROR(data, 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
+ "Invalid non-boolean-encoded boolean value \"0\".",
+ "Data location \"/a:l1[a='val-a'][b='val-b'][c='1']/cont/e\", line number 1.");
+
+ /* 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));
+}
+
+static void
+test_leaflist(void **state)
+{
+ const char *data;
+ struct lyd_node *tree;
+ struct lyd_node_term *ll;
+
+ data = "{\"a:ll1\":[10,11]}";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ assert_non_null(tree);
+ tree = tree->next;
+ CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_ORDBY_SYSTEM, 1, "ll1",
+ 1, LYS_LEAFLIST, 0, 0, NULL, 0);
+ ll = (struct lyd_node_term *)tree;
+ CHECK_LYD_VALUE(ll->value, UINT8, "10", 10);
+
+ assert_non_null(tree->next);
+ CHECK_LYSC_NODE(tree->next->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_ORDBY_SYSTEM, 1, "ll1",
+ 1, LYS_LEAFLIST, 0, 0, NULL, 0);
+ ll = (struct lyd_node_term *)tree->next;
+ CHECK_LYD_VALUE(ll->value, UINT8, "11", 11);
+
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ /* accept empty */
+ data = "{\"a:ll1\":[]}";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ assert_null(tree);
+
+ /* simple metadata */
+ data = "{\"a:ll1\":[10,11],\"@a:ll1\":[null,{\"a:hint\":2}]}";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ assert_non_null(tree);
+ tree = tree->next;
+ CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_ORDBY_SYSTEM, 1, "ll1",
+ 1, LYS_LEAFLIST, 0, 0, NULL, 0);
+ ll = (struct lyd_node_term *)tree;
+ CHECK_LYD_VALUE(ll->value, UINT8, "10", 10);
+ assert_null(ll->meta);
+
+ assert_non_null(tree->next);
+ CHECK_LYSC_NODE(tree->next->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_ORDBY_SYSTEM, 1, "ll1",
+ 1, LYS_LEAFLIST, 0, 0, NULL, 0);
+ ll = (struct lyd_node_term *)tree->next;
+ CHECK_LYD_VALUE(ll->value, UINT8, "11", 11);
+ CHECK_LYD_META(ll->meta, 1, "hint", 0, 1, INT8, "2", 2);
+ assert_null(ll->meta->next);
+
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ /* multiple meatadata hint and unknown metadata xxx supposed to be skipped since it is from missing schema */
+ data = "{\"@a:ll1\" : [{\"a:hint\" : 1, \"x:xxx\" : { \"value\" : \"/x:no/x:yes\" }, "
+ "\"a:hint\" : 10},null,{\"a:hint\" : 3}], \"a:ll1\" : [1,2,3]}";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ assert_non_null(tree);
+ tree = tree->next;
+ CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_ORDBY_SYSTEM, 1, "ll1",
+ 1, LYS_LEAFLIST, 0, 0, NULL, 0);
+ ll = (struct lyd_node_term *)tree;
+ CHECK_LYD_VALUE(ll->value, UINT8, "1", 1);
+ CHECK_LYD_META(ll->meta, 1, "hint", 1, 1, INT8, "1", 1);
+ CHECK_LYD_META(ll->meta->next, 1, "hint", 0, 1, INT8, "10", 10);
+
+ assert_non_null(tree->next);
+ CHECK_LYSC_NODE(tree->next->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_ORDBY_SYSTEM, 1, "ll1",
+ 1, LYS_LEAFLIST, 0, 0, NULL, 0);
+ ll = (struct lyd_node_term *)tree->next;
+ CHECK_LYD_VALUE(ll->value, UINT8, "2", 2);
+ assert_null(ll->meta);
+
+ assert_non_null(tree->next->next);
+ CHECK_LYSC_NODE(tree->next->next->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_ORDBY_SYSTEM, 1, "ll1",
+ 1, LYS_LEAFLIST, 0, 0, NULL, 0);
+ ll = (struct lyd_node_term *)tree->next->next;
+ CHECK_LYD_VALUE(ll->value, UINT8, "3", 3);
+ CHECK_LYD_META(ll->meta, 1, "hint", 0, 1, INT8, "3", 3);
+ assert_null(ll->meta->next);
+
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS,
+ "{\"a:ll1\":[1,2,3],\"@a:ll1\":[{\"a:hint\":1,\"a:hint\":10},null,{\"a:hint\":3}]}");
+ lyd_free_all(tree);
+
+ /* missing referenced metadata node */
+ PARSER_CHECK_ERROR("{\"@a:ll1\":[{\"a:hint\":1}]}", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
+ "Missing JSON data instance to be coupled with @a:ll1 metadata.", "Data location \"/@a:ll1\", line number 1.");
+
+ PARSER_CHECK_ERROR("{\"a:ll1\":[1],\"@a:ll1\":[{\"a:hint\":1},{\"a:hint\":2}]}", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
+ "Missing JSON data instance #2 of a:ll1 to be coupled with metadata.", "Schema location \"/a:ll1\", line number 1.");
+
+ PARSER_CHECK_ERROR("{\"@a:ll1\":[{\"a:hint\":1},{\"a:hint\":2},{\"a:hint\":3}],\"a:ll1\" : [1, 2]}", 0, LYD_VALIDATE_PRESENT,
+ tree, LY_EVALID, "Missing JSON data instance #3 to be coupled with @a:ll1 metadata.",
+ "Data location \"/@a:ll1\", line number 1.");
+}
+
+static void
+test_anydata(void **state)
+{
+ const char *data;
+ struct lyd_node *tree;
+
+ data = "{\"a:any\":{\"x:element1\":{\"element2\":\"/a:some/a:path\",\"list\":[{},{\"key\":\"a\"}]}}}";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ assert_non_null(tree);
+ tree = tree->next;
+ CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_R | LYS_SET_CONFIG, 1, "any",
+ 1, LYS_ANYDATA, 0, 0, NULL, 0);
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ data = "{\"a:any\":{}}";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ assert_non_null(tree);
+ tree = tree->next;
+ CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_R | LYS_SET_CONFIG, 1, "any",
+ 1, LYS_ANYDATA, 0, 0, NULL, 0);
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ data = "{\"a:any\":{\"node\":20}}";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ assert_non_null(tree);
+ tree = tree->next;
+ CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_R | LYS_SET_CONFIG, 1, "any",
+ 1, LYS_ANYDATA, 0, 0, NULL, 0);
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+}
+
+static void
+test_anyxml(void **state)
+{
+ const char *data;
+ struct lyd_node *tree;
+
+ data = "{\"a:axml\":\"some-value in string\"}";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ assert_non_null(tree);
+ tree = tree->next;
+ CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ data = "{\"a:axml\":\"\"}";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ assert_non_null(tree);
+ tree = tree->next;
+ CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ data = "{\"a:axml\":55}";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ assert_non_null(tree);
+ tree = tree->next;
+ CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ data = "{\"a:axml\":false}";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ assert_non_null(tree);
+ tree = tree->next;
+ CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ data = "{\"a:axml\":null}";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ assert_non_null(tree);
+ tree = tree->next;
+ CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ data = "{\"a:axml\":[null,true,false]}";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ assert_non_null(tree);
+ tree = tree->next;
+ CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ data = "{\"a:axml\":[null,true,{\"name\":[25,40, false]}]}";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ assert_non_null(tree);
+ tree = tree->next;
+ CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ /* same as anydata tests */
+ data = "{\"a:axml\":{\"x:element1\":{\"element2\":\"/a:some/a:path\",\"list\":[{},{\"key\":\"a\"}]}}}";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ assert_non_null(tree);
+ tree = tree->next;
+ CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ data = "{\"a:axml\":{}}";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ assert_non_null(tree);
+ tree = tree->next;
+ CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+}
+
+static void
+test_list(void **state)
+{
+ const char *data;
+ struct lyd_node *tree, *iter;
+ struct lyd_node_inner *list;
+ struct lyd_node_term *leaf;
+
+ /* check hashes */
+ data = "{\"a:l1\":[{\"a\":\"one\",\"b\":\"one\",\"c\":1}]}";
+ CHECK_PARSE_LYD(data, 0, 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);
+ list = (struct lyd_node_inner *)tree;
+ LY_LIST_FOR(list->child, iter) {
+ assert_int_not_equal(0, iter->hash);
+ }
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ /* accept empty */
+ data = "{\"a:l1\":[]}";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ assert_null(tree);
+
+ /* missing keys */
+ PARSER_CHECK_ERROR("{ \"a:l1\": [ {\"c\" : 1, \"b\" : \"b\"}]}", 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.");
+
+ PARSER_CHECK_ERROR("{ \"a:l1\": [ {\"a\" : \"a\"}]}", 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("{ \"a:l1\": [ {\"b\" : \"b\", \"a\" : \"a\"}]}", 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.");
+
+ /* key duplicate */
+ PARSER_CHECK_ERROR("{ \"a:l1\": [ {\"c\" : 1, \"b\" : \"b\", \"a\" : \"a\", \"c\" : 1}]}", 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.");
+
+ /* keys order, in contrast to XML, JSON accepts keys in any order even in strict mode */
+ CHECK_PARSE_LYD("{ \"a:l1\": [ {\"d\" : \"d\", \"a\" : \"a\", \"c\" : 1, \"b\" : \"b\"}]}", 0, 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);
+ list = (struct lyd_node_inner *)tree;
+ assert_non_null(leaf = (struct lyd_node_term *)list->child);
+ CHECK_LYSC_NODE(leaf->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_KEY, 1, "a", 1, LYS_LEAF, 1, 0, NULL, 0);
+ 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, "b", 1, LYS_LEAF, 1, 0, NULL, 0);
+ 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);
+ 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);
+ list = (struct lyd_node_inner *)tree;
+ assert_non_null(leaf = (struct lyd_node_term *)list->child);
+ CHECK_LYSC_NODE(leaf->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_KEY, 1, "a",
+ 1, LYS_LEAF, 1, 0, NULL, 0);
+ 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, "b",
+ 1, LYS_LEAF, 1, 0, NULL, 0);
+ 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(NULL, NULL);
+
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS,
+ "{\"a:l1\":[{\"a\":\"a\",\"b\":\"b\",\"c\":1}]}");
+ lyd_free_all(tree);
+
+ data = "{\"a:cp\":{\"@\":{\"a:hint\":1}}}";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ assert_non_null(tree);
+ tree = tree->next;
+ CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_PRESENCE, 1, "cp",
+ 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);
+}
+
+static void
+test_container(void **state)
+{
+ const char *data;
+ struct lyd_node *tree;
+ struct lyd_node_inner *cont;
+
+ CHECK_PARSE_LYD("{\"a:c\":{}}", 0, LYD_VALIDATE_PRESENT, tree);
+ CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "c",
+ 1, LYS_CONTAINER, 0, 0, NULL, 0);
+ cont = (struct lyd_node_inner *)tree;
+ assert_true(cont->flags & LYD_DEFAULT);
+
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, "{}");
+ lyd_free_all(tree);
+
+ data = "{\"a:cp\":{}}";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ assert_non_null(tree);
+ tree = tree->next;
+ CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_PRESENCE, 1, "cp",
+ 1, LYS_CONTAINER, 0, 0, NULL, 0);
+ cont = (struct lyd_node_inner *)tree;
+ assert_false(cont->flags & LYD_DEFAULT);
+
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ /* skip container */
+ CHECK_PARSE_LYD("{\"a:unknown\":{\"a\":\"val\",\"b\":5}}", 0, LYD_VALIDATE_PRESENT, tree);
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, "{}");
+ lyd_free_all(tree);
+}
+
+static void
+test_opaq(void **state)
+{
+ const char *data;
+ struct lyd_node *tree;
+
+ /* invalid value, no flags */
+ data = "{\"a:foo3\":[null]}";
+ PARSER_CHECK_ERROR(data, 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
+ "Invalid non-number-encoded uint32 value \"\".", "Schema location \"/a:foo3\", line number 1.");
+
+ /* 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_JSON, "foo3", 0, 0, NULL, 0, "");
+ 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,
+ "List instance is missing its key \"c\".",
+ "Data location \"/a:l1[a='val_a'][b='val_b']\", line number 1.");
+
+ /* 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_JSON, "l1", 0, 0, NULL, 0, "");
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ /* invalid key, no flags */
+ data = "{\"a:l1\":[{\"a\":\"val_a\",\"b\":\"val_b\",\"c\":\"val_c\"}]}";
+ PARSER_CHECK_ERROR(data, 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
+ "Invalid non-number-encoded int16 value \"val_c\".",
+ "Data location \"/a:l1[a='val_a'][b='val_b']/c\", line number 1.");
+
+ /* 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_JSON, "l1", 0, 0, NULL, 0, "");
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ data = "{\"a:l1\":[{\"a\":\"val_a\",\"b\":\"val_b\",\"c\":{\"val\":\"val_c\"}}]}";
+ 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_JSON, "l1", 0, 0, NULL, 0, "");
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ data = "{\"a:l1\":[{\"a\":\"val_a\",\"b\":\"val_b\"}]}";
+ 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_JSON, "l1", 0, 0, NULL, 0, "");
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ /* 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\".");
+
+ /* 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.");
+
+ /* opaque data tree format print */
+ data =
+ "{\n"
+ " \"ietf-netconf-nmda:get-data\": {\n"
+ " \"data\": {\n"
+ " \"ietf-keystore:keystore\": {\n"
+ " \"asymmetric-keys\": {\n"
+ " \"asymmetric-key\": [\n"
+ " {\n"
+ " \"name\": \"genkey\",\n"
+ " \"algorithm\": \"rsa2048\"\n"
+ " }\n"
+ " ]\n"
+ " }\n"
+ " },\n"
+ " \"ietf-netconf-server:netconf-server\": {\n"
+ " \"listen\": {\n"
+ " \"idle-timeout\": 3600,\n"
+ " \"endpoint\": [\n"
+ " {\n"
+ " \"name\": \"default-ssh\",\n"
+ " \"ssh\": {\n"
+ " \"tcp-server-parameters\": {\n"
+ " \"local-address\": \"0.0.0.0\",\n"
+ " \"local-port\": 830\n"
+ " },\n"
+ " \"ssh-server-parameters\": {\n"
+ " \"server-identity\": {\n"
+ " \"host-key\": [\n"
+ " {\n"
+ " \"name\": \"default-key\",\n"
+ " \"public-key\": {\n"
+ " \"keystore-reference\": \"genkey\"\n"
+ " }\n"
+ " }\n"
+ " ]\n"
+ " },\n"
+ " \"client-authentication\": {\n"
+ " \"supported-authentication-methods\": {\n"
+ " \"publickey\": [null],\n"
+ " \"passsword\": [null],\n"
+ " \"other\": [\n"
+ " \"interactive\",\n"
+ " \"gssapi\"\n"
+ " ]\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " ]\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ "}\n";
+ CHECK_PARSE_LYD(data, LYD_PARSE_OPAQ | LYD_PARSE_ONLY, 0, tree);
+ CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+}
+
+static void
+test_rpc(void **state)
+{
+ const char *data;
+ struct ly_in *in;
+ struct lyd_node *tree, *op;
+ const struct lyd_node *node;
+ const char *dsc = "Edit data in an NMDA datastore.\n"
+ "\n"
+ "If an error condition occurs such that an error severity\n"
+ "<rpc-error> element is generated, the server will stop\n"
+ "processing the <edit-data> operation and restore the\n"
+ "specified configuration to its complete state at\n"
+ "the start of this <edit-data> operation.";
+
+ assert_non_null((ly_ctx_load_module(UTEST_LYCTX, "ietf-netconf-nmda", "2019-01-07", NULL)));
+
+ 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\"}]}"
+ "}}";
+ 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_RPC_YANG, &tree, &op));
+ ly_in_free(in, 0);
+
+ assert_non_null(op);
+
+ CHECK_LYSC_ACTION((struct lysc_node_action *)op->schema, dsc, 0, LYS_STATUS_CURR,
+ 1, 0, 0, 1, "edit-data", LYS_RPC,
+ 0, 0, 0, 0, 0, NULL, 0);
+
+ node = tree;
+ CHECK_LYSC_ACTION((struct lysc_node_action *)node->schema, dsc, 0, LYS_STATUS_CURR,
+ 1, 0, 0, 1, "edit-data", LYS_RPC,
+ 0, 0, 0, 0, 0, NULL, 0);
+ node = lyd_child(node)->next;
+ CHECK_LYSC_NODE(node->schema, "Inline config content.", 0, LYS_STATUS_CURR | LYS_IS_INPUT, 1, "config",
+ 0, LYS_ANYDATA, 1, 0, NULL, 0);
+
+ node = ((struct lyd_node_any *)node)->value.tree;
+ CHECK_LYSC_NODE(node->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_PRESENCE, 1, "cp",
+ 1, LYS_CONTAINER, 0, 0, NULL, 0);
+ node = lyd_child(node);
+ /* z has no value */
+ CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)node, 0x1, 0, LY_VALUE_JSON, "z", 0, 0, NULL, 0, "");
+ 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_JSON, "l1", 0, 0, NULL, 0, "");
+
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ /* wrong namespace, element name, whatever... */
+ /* TODO */
+}
+
+static void
+test_action(void **state)
+{
+ const char *data;
+ struct ly_in *in;
+ struct lyd_node *tree, *op;
+
+ data = "{\"a:c\":{\"act\":{\"al\":\"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_RPC_YANG, &tree, &op));
+ ly_in_free(in, 0);
+
+ assert_non_null(op);
+ CHECK_LYSC_ACTION((struct lysc_node_action *)op->schema, NULL, 0, LYS_STATUS_CURR,
+ 1, 0, 0, 1, "act", LYS_ACTION,
+ 1, 0, 0, 1, 0, NULL, 0);
+
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ /* wrong namespace, element name, whatever... */
+ /* TODO */
+}
+
+static void
+test_notification(void **state)
+{
+ const char *data;
+ struct ly_in *in;
+ struct lyd_node *tree, *ntf;
+
+ data = "{\"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_YANG, &tree, &ntf));
+ ly_in_free(in, 0);
+
+ assert_non_null(ntf);
+ CHECK_LYSC_NOTIF((struct lysc_node_notif *)ntf->schema, 1, NULL, 0, 0x4, 1, 0, "n1", 1, 0, NULL, 0);
+
+ CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "c", 1, LYS_CONTAINER, 0, 0, NULL, 0);
+
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ data = "{\"a:n2\":{}}";
+ 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_YANG, &tree, &ntf));
+ ly_in_free(in, 0);
+
+ assert_non_null(ntf);
+ CHECK_LYSC_NOTIF((struct lysc_node_notif *)ntf->schema, 0, NULL, 0, 0x4, 1, 0, "n2", 0, 0, NULL, 0);
+
+ assert_non_null(tree);
+ assert_ptr_equal(ntf, tree);
+
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ /* wrong namespace, element name, whatever... */
+ /* TODO */
+}
+
+static void
+test_reply(void **state)
+{
+ const char *data;
+ struct ly_in *in;
+ struct lyd_node *tree, *op;
+ const struct lyd_node *node;
+
+ data = "{\"a:c\":{\"act\":{\"al\":25}}}";
+ 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_REPLY_YANG, &tree, &op));
+ ly_in_free(in, 0);
+
+ assert_non_null(op);
+ CHECK_LYSC_ACTION((struct lysc_node_action *)op->schema, NULL, 0, LYS_STATUS_CURR,
+ 1, 0, 0, 1, "act", LYS_ACTION,
+ 1, 0, 0, 1, 0, NULL, 0);
+ node = lyd_child(op);
+ CHECK_LYSC_NODE(node->schema, NULL, 0, LYS_STATUS_CURR | LYS_IS_OUTPUT, 1, "al", 0, LYS_LEAF, 1, 0, NULL, 0);
+
+ CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "c", 1, LYS_CONTAINER, 0, 0, NULL, 0);
+
+ /* TODO print only rpc-reply node and then output subtree */
+ CHECK_LYD_STRING(lyd_child(op), LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, "{\"a:al\":25}");
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, "{\"a:c\":{\"act\":{\"al\":25}}}");
+ lyd_free_all(tree);
+
+ /* wrong namespace, element name, whatever... */
+ /* TODO */
+}
+
+int
+main(void)
+{
+ const struct CMUnitTest tests[] = {
+ UTEST(test_leaf, setup),
+ UTEST(test_leaflist, setup),
+ UTEST(test_anydata, setup),
+ UTEST(test_anyxml, setup),
+ UTEST(test_list, setup),
+ UTEST(test_container, setup),
+ UTEST(test_opaq, setup),
+ UTEST(test_rpc, setup),
+ UTEST(test_action, setup),
+ UTEST(test_notification, setup),
+ UTEST(test_reply, 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
new file mode 100644
index 0000000..7defd9c
--- /dev/null
+++ b/tests/utests/data/test_parser_xml.c
@@ -0,0 +1,836 @@
+/**
+ * @file test_parser_xml.c
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @author Michal Vasko <mvasko@cesnet.cz>
+ * @brief unit tests for functions from parser_xml.c
+ *
+ * Copyright (c) 2019 - 2022 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.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ */
+#define _UTEST_MAIN_
+#include "utests.h"
+
+#include "context.h"
+#include "in.h"
+#include "out.h"
+#include "parser_data.h"
+#include "printer_data.h"
+#include "tree_data_internal.h"
+#include "tree_schema.h"
+
+static int
+setup(void **state)
+{
+ const char *schema =
+ "module a {\n"
+ " namespace urn:tests:a;\n"
+ " prefix a;\n"
+ " yang-version 1.1;\n"
+ " 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;}}"
+ " }"
+ " leaf foo { type string;}\n"
+ " container c {\n"
+ " leaf x {type string;}\n"
+ " action act { input { leaf al {type string;} } output { leaf al {type uint8;} } }\n"
+ " 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"
+ " leaf foo2 { type string; default \"default-val\"; }\n"
+ " leaf foo3 { type uint32; }\n"
+ " notification n2;}";
+
+ UTEST_SETUP;
+
+ UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
+ assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_DIR_MODULES_YANG));
+
+ return 0;
+}
+
+#define CHECK_PARSE_LYD(INPUT, PARSE_OPTION, VALIDATE_OPTION, TREE) \
+ CHECK_PARSE_LYD_PARAM(INPUT, LYD_XML, PARSE_OPTION, VALIDATE_OPTION, LY_SUCCESS, TREE)
+
+#define PARSER_CHECK_ERROR(INPUT, PARSE_OPTION, VALIDATE_OPTION, MODEL, RET_VAL, ERR_MESSAGE, ERR_PATH) \
+ assert_int_equal(RET_VAL, lyd_parse_data_mem(UTEST_LYCTX, INPUT, LYD_XML, PARSE_OPTION, VALIDATE_OPTION, &MODEL));\
+ CHECK_LOG_CTX(ERR_MESSAGE, ERR_PATH);\
+ assert_null(MODEL)
+
+#define CHECK_LYD_STRING(IN_MODEL, PRINT_OPTION, TEXT) \
+ CHECK_LYD_STRING_PARAM(IN_MODEL, TEXT, LYD_XML, PRINT_OPTION)
+
+static void
+test_leaf(void **state)
+{
+ const char *data = "<foo xmlns=\"urn:tests:a\">foo value</foo>";
+ struct lyd_node *tree;
+ struct lyd_node_term *leaf;
+
+ assert_non_null(ly_ctx_load_module(UTEST_LYCTX, "ietf-netconf-with-defaults", "2011-06-01", NULL));
+
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "foo", 1, LYS_LEAF, 0, 0, NULL, 0);
+ leaf = (struct lyd_node_term *)tree;
+ CHECK_LYD_VALUE(leaf->value, STRING, "foo value");
+
+ CHECK_LYSC_NODE(tree->next->next->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_SET_DFLT, 1, "foo2",
+ 1, LYS_LEAF, 0, 0, NULL, 0);
+ leaf = (struct lyd_node_term *)tree->next->next;
+ CHECK_LYD_VALUE(leaf->value, STRING, "default-val");
+ assert_true(leaf->flags & LYD_DEFAULT);
+ lyd_free_all(tree);
+
+ /* make foo2 explicit */
+ data = "<foo2 xmlns=\"urn:tests:a\">default-val</foo2>";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ assert_non_null(tree);
+ tree = tree->next;
+ CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_SET_DFLT, 1, "foo2",
+ 1, LYS_LEAF, 0, 0, NULL, 0);
+ leaf = (struct lyd_node_term *)tree;
+ CHECK_LYD_VALUE(leaf->value, STRING, "default-val");
+ assert_false(leaf->flags & LYD_DEFAULT);
+ lyd_free_all(tree);
+
+ /* parse foo2 but make it implicit, skip metadata xxx from missing schema */
+ data = "<foo2 xmlns=\"urn:tests:a\" xmlns:wd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" "
+ "wd:default=\"true\" xmlns:x=\"urn:x\" x:xxx=\"false\">default-val</foo2>";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ assert_non_null(tree);
+ tree = tree->next;
+ CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_SET_DFLT, 1, "foo2",
+ 1, LYS_LEAF, 0, 0, NULL, 0);
+ leaf = (struct lyd_node_term *)tree;
+ CHECK_LYD_VALUE(leaf->value, STRING, "default-val");
+ assert_true(leaf->flags & LYD_DEFAULT);
+ lyd_free_all(tree);
+
+ /* invalid value */
+ data = "<l1 xmlns=\"urn:tests:a\"><a>val-a</a><b>val-b</b><c>1</c><cont><e>0</e></cont></l1>";
+ PARSER_CHECK_ERROR(data, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
+ "Invalid boolean value \"0\".",
+ "Data location \"/a:l1[a='val-a'][b='val-b'][c='1']/cont/e\", line number 1.");
+}
+
+static void
+test_anydata(void **state)
+{
+ const char *data;
+ struct lyd_node *tree;
+
+ data = "<any xmlns=\"urn:tests:a\">\n"
+ " <element1>\n"
+ " <x:element2 x:attr2=\"test\" xmlns:a=\"urn:tests:a\" xmlns:x=\"urn:x\">a:data</x:element2>\n"
+ " </element1>\n"
+ " <element1a/>\n"
+ "</any>\n";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ assert_non_null(tree);
+ tree = tree->next;
+ CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_R | LYS_STATUS_CURR | LYS_SET_CONFIG, 1, "any",
+ 1, LYS_ANYDATA, 0, 0, NULL, 0);
+
+ const char *data_expected =
+ "<any xmlns=\"urn:tests:a\">\n"
+ " <element1>\n"
+ " <element2 xmlns=\"urn:x\" xmlns:x=\"urn:x\" x:attr2=\"test\" xmlns:a=\"urn:tests:a\">a:data</element2>\n"
+ " </element1>\n"
+ " <element1a/>\n"
+ "</any>\n";
+
+ CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data_expected);
+ lyd_free_all(tree);
+}
+
+static void
+test_list(void **state)
+{
+ const char *data;
+ struct lyd_node *tree, *iter;
+ struct lyd_node_inner *list;
+ struct lyd_node_term *leaf;
+
+ /* check hashes */
+ data = "<l1 xmlns=\"urn:tests:a\"><a>one</a><b>one</b><c>1</c></l1>";
+ CHECK_PARSE_LYD(data, 0, 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);
+ list = (struct lyd_node_inner *)tree;
+ LY_LIST_FOR(list->child, iter) {
+ assert_int_not_equal(0, iter->hash);
+ }
+ lyd_free_all(tree);
+
+ /* 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.");
+
+ 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.");
+
+ /* 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.");
+
+ /* 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);
+ 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);
+ list = (struct lyd_node_inner *)tree;
+ assert_non_null(leaf = (struct lyd_node_term *)list->child);
+ CHECK_LYSC_NODE(leaf->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_KEY, 1, "a", 1, LYS_LEAF, 1, 0, NULL, 0);
+ 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, "b", 1, LYS_LEAF, 1, 0, NULL, 0);
+ 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);
+ 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("Invalid position of the key \"b\" in a list.", NULL);
+ lyd_free_all(tree);
+
+ data = "<l1 xmlns=\"urn:tests:a\"><c>1</c><b>b</b><a>a</a></l1>";
+ CHECK_PARSE_LYD(data, 0, 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);
+ list = (struct lyd_node_inner *)tree;
+ assert_non_null(leaf = (struct lyd_node_term *)list->child);
+ CHECK_LYSC_NODE(leaf->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_KEY, 1, "a", 1, LYS_LEAF, 1, 0, NULL, 0);
+ 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, "b", 1, LYS_LEAF, 1, 0, NULL, 0);
+ 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);
+ lyd_free_all(tree);
+
+ PARSER_CHECK_ERROR(data, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
+ "Invalid position of the key \"b\" in a list.", "Data location \"/a:l1[c='1']/b\", line number 1.");
+}
+
+static void
+test_container(void **state)
+{
+ struct lyd_node *tree;
+ struct lyd_node_inner *cont;
+
+ CHECK_PARSE_LYD("<c xmlns=\"urn:tests:a\"/>", 0, LYD_VALIDATE_PRESENT, tree);
+ CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "c", 1, LYS_CONTAINER, 0, 0, NULL, 0);
+ cont = (struct lyd_node_inner *)tree;
+ assert_true(cont->flags & LYD_DEFAULT);
+ lyd_free_all(tree);
+
+ CHECK_PARSE_LYD("<cp xmlns=\"urn:tests:a\"/>", 0, LYD_VALIDATE_PRESENT, tree);
+ assert_non_null(tree);
+ tree = tree->next;
+ CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_PRESENCE, 1, "cp",
+ 1, LYS_CONTAINER, 0, 0, NULL, 0);
+ cont = (struct lyd_node_inner *)tree;
+ assert_false(cont->flags & LYD_DEFAULT);
+ lyd_free_all(tree);
+}
+
+static void
+test_opaq(void **state)
+{
+ const char *data;
+ struct lyd_node *tree;
+
+ /* invalid value, no flags */
+ data = "<foo3 xmlns=\"urn:tests:a\"/>";
+ PARSER_CHECK_ERROR(data, 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
+ "Invalid type uint32 empty value.", "Schema location \"/a:foo3\", line number 1.");
+
+ /* 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_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_STRING(tree, LYD_PRINT_WITHSIBLINGS, "<l1 xmlns=\"urn:tests:a\"/>\n");
+ lyd_free_all(tree);
+
+ /* missing key, no flags */
+ data = "<l1 xmlns=\"urn:tests:a\">\n"
+ " <a>val_a</a>\n"
+ " <b>val_b</b>\n"
+ " <d>val_d</d>\n"
+ "</l1>\n";
+ PARSER_CHECK_ERROR(data, 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
+ "List instance is missing its key \"c\".",
+ "Data location \"/a:l1[a='val_a'][b='val_b']\", line number 5.");
+
+ /* 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_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ /* invalid key, no flags */
+ data = "<l1 xmlns=\"urn:tests:a\">\n"
+ " <a>val_a</a>\n"
+ " <b>val_b</b>\n"
+ " <c>val_c</c>\n"
+ "</l1>\n";
+ PARSER_CHECK_ERROR(data, 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
+ "Invalid type int16 value \"val_c\".",
+ "Data location \"/a:l1[a='val_a'][b='val_b']/c\", line number 4.");
+
+ /* 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_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ /* opaq flag and fail */
+ assert_int_equal(LY_EVALID, lyd_parse_data_mem(UTEST_LYCTX,
+ "<a xmlns=\"ns\">\n"
+ " <b>x</b>\n"
+ " <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.");
+}
+
+static void
+test_rpc(void **state)
+{
+ const char *data;
+ struct ly_in *in;
+ struct lyd_node *tree, *op;
+ const struct lyd_node *node;
+ const char *dsc = "The <edit-config> operation loads all or part of a specified\n"
+ "configuration to the specified target configuration.";
+ const char *ref = "RFC 6241, Section 7.2";
+ const char *feats[] = {"writable-running", NULL};
+
+ assert_non_null((ly_ctx_load_module(UTEST_LYCTX, "ietf-netconf", "2011-06-01", feats)));
+
+ data = "<edit-config xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
+ " <target>\n"
+ " <running/>\n"
+ " </target>\n"
+ " <config xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
+ " <l1 xmlns=\"urn:tests:a\" nc:operation=\"replace\">\n"
+ " <a>val_a</a>\n"
+ " <b>val_b</b>\n"
+ " <c>val_c</c>\n"
+ " </l1>\n"
+ " <cp xmlns=\"urn:tests:a\">\n"
+ " <z nc:operation=\"delete\"/>\n"
+ " </cp>\n"
+ " </config>\n"
+ "</edit-config>\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_RPC_YANG, &tree, &op));
+ ly_in_free(in, 0);
+
+ assert_non_null(op);
+
+ CHECK_LYSC_ACTION((struct lysc_node_action *)op->schema, dsc, 0, LYS_STATUS_CURR,
+ 1, 0, 0, 1, "edit-config", LYS_RPC,
+ 0, 0, 0, 0, 0, ref, 0);
+
+ assert_non_null(tree);
+
+ node = tree;
+ CHECK_LYSC_ACTION((struct lysc_node_action *)node->schema, dsc, 0, LYS_STATUS_CURR,
+ 1, 0, 0, 1, "edit-config", LYS_RPC,
+ 0, 0, 0, 0, 0, ref, 0);
+ node = lyd_child(node)->next;
+ dsc = "Inline Config content.";
+ CHECK_LYSC_NODE(node->schema, dsc, 0, LYS_STATUS_CURR | LYS_IS_INPUT, 1, "config", 0, LYS_ANYXML, 1, 0, NULL, 0);
+
+ node = ((struct lyd_node_any *)node)->value.tree;
+ CHECK_LYSC_NODE(node->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_PRESENCE, 1, "cp",
+ 1, LYS_CONTAINER, 0, 0, NULL, 0);
+
+ 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, "");
+ 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_STRING(tree, LYD_PRINT_WITHSIBLINGS,
+ "<edit-config xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
+ " <target>\n"
+ " <running/>\n"
+ " </target>\n"
+ " <config>\n"
+ " <cp xmlns=\"urn:tests:a\">\n"
+ " <z xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\" nc:operation=\"delete\"/>\n"
+ " </cp>\n"
+ " <l1 xmlns=\"urn:tests:a\" xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\" nc:operation=\"replace\">\n"
+ " <a>val_a</a>\n"
+ " <b>val_b</b>\n"
+ " <c>val_c</c>\n"
+ " </l1>\n"
+ " </config>\n"
+ "</edit-config>\n");
+
+ lyd_free_all(tree);
+
+ /* wrong namespace, element name, whatever... */
+ /* TODO */
+}
+
+static void
+test_action(void **state)
+{
+ const char *data;
+ struct ly_in *in;
+ struct lyd_node *tree, *op;
+
+ data = "<c xmlns=\"urn:tests:a\">\n"
+ " <act>\n"
+ " <al>value</al>\n"
+ " </act>\n"
+ "</c>\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_RPC_YANG, &tree, &op));
+ ly_in_free(in, 0);
+
+ assert_non_null(op);
+ CHECK_LYSC_ACTION((struct lysc_node_action *)op->schema, NULL, 0, LYS_STATUS_CURR,
+ 1, 0, 0, 1, "act", LYS_ACTION,
+ 1, 0, 0, 1, 0, NULL, 0);
+
+ CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS,
+ "<c xmlns=\"urn:tests:a\">\n"
+ " <act>\n"
+ " <al>value</al>\n"
+ " </act>\n"
+ "</c>\n");
+
+ lyd_free_all(tree);
+
+ /* wrong namespace, element name, whatever... */
+ /* TODO */
+}
+
+static void
+test_notification(void **state)
+{
+ const char *data;
+ struct ly_in *in;
+ struct lyd_node *tree, *ntf;
+
+ data = "<c xmlns=\"urn:tests:a\">\n"
+ " <n1>\n"
+ " <nl>value</nl>\n"
+ " </n1>\n"
+ "</c>\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_YANG, &tree, &ntf));
+ ly_in_free(in, 0);
+
+ assert_non_null(ntf);
+ CHECK_LYSC_NOTIF((struct lysc_node_notif *)ntf->schema, 1, NULL, 0, 0x4, 1, 0, "n1", 1, 0, NULL, 0);
+
+ CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "c", 1, LYS_CONTAINER, 0, 0, NULL, 0);
+
+ CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ /* top-level notif without envelope */
+ data = "<n2 xmlns=\"urn:tests:a\"/>\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_YANG, &tree, &ntf));
+ ly_in_free(in, 0);
+
+ assert_non_null(ntf);
+ CHECK_LYSC_NOTIF((struct lysc_node_notif *)ntf->schema, 0, NULL, 0, 0x4, 1, 0, "n2", 0, 0, NULL, 0);
+
+ assert_non_null(tree);
+ assert_ptr_equal(ntf, tree);
+
+ CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ /* wrong namespace, element name, whatever... */
+ /* TODO */
+}
+
+static void
+test_reply(void **state)
+{
+ const char *data;
+ struct ly_in *in;
+ struct lyd_node *tree, *op;
+ const struct lyd_node *node;
+
+ data = "<c xmlns=\"urn:tests:a\">\n"
+ " <act>\n"
+ " <al>25</al>\n"
+ " </act>\n"
+ "</c>\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_REPLY_YANG, &tree, &op));
+ ly_in_free(in, 0);
+
+ assert_non_null(op);
+
+ CHECK_LYSC_ACTION((struct lysc_node_action *)op->schema, NULL, 0, LYS_STATUS_CURR,
+ 1, 0, 0, 1, "act", LYS_ACTION,
+ 1, 0, 0, 1, 0, NULL, 0);
+ node = lyd_child(op);
+ CHECK_LYSC_NODE(node->schema, NULL, 0, LYS_STATUS_CURR | LYS_IS_OUTPUT, 1, "al", 0, LYS_LEAF, 1, 0, NULL, 0);
+
+ CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "c", 1, LYS_CONTAINER, 0, 0, NULL, 0);
+
+ /* TODO print only rpc-reply node and then output subtree */
+ CHECK_LYD_STRING(lyd_child(op), LYD_PRINT_WITHSIBLINGS, "<al xmlns=\"urn:tests:a\">25</al>\n");
+ lyd_free_all(tree);
+
+ /* wrong namespace, element name, whatever... */
+ /* TODO */
+}
+
+static void
+test_netconf_rpc(void **state)
+{
+ const char *data;
+ struct ly_in *in;
+ struct lyd_node *tree, *op;
+ const struct lyd_node *node;
+ const char *dsc = "The <edit-config> operation loads all or part of a specified\n"
+ "configuration to the specified target configuration.";
+ const char *ref = "RFC 6241, Section 7.2";
+ const char *feats[] = {"writable-running", NULL};
+
+ assert_non_null((ly_ctx_load_module(UTEST_LYCTX, "ietf-netconf", "2011-06-01", feats)));
+
+ data = "<rpc message-id=\"25\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
+ "<edit-config>\n"
+ " <target>\n"
+ " <running/>\n"
+ " </target>\n"
+ " <config xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
+ " <l1 xmlns=\"urn:tests:a\" nc:operation=\"replace\">\n"
+ " <a>val_a</a>\n"
+ " <b>val_b</b>\n"
+ " <c>val_c</c>\n"
+ " </l1>\n"
+ " <cp xmlns=\"urn:tests:a\">\n"
+ " <z nc:operation=\"delete\"/>\n"
+ " </cp>\n"
+ " </config>\n"
+ "</edit-config>\n"
+ "</rpc>\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_RPC_NETCONF, &tree, &op));
+ ly_in_free(in, 0);
+
+ assert_non_null(op);
+
+ node = tree;
+ CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)node, 1, 0, LY_VALUE_XML, "rpc", 0, 0, 0, 0, "");
+
+ assert_non_null(tree);
+
+ node = op;
+ CHECK_LYSC_ACTION((struct lysc_node_action *)node->schema, dsc, 0, LYS_STATUS_CURR,
+ 1, 0, 0, 1, "edit-config", LYS_RPC,
+ 0, 0, 0, 0, 0, ref, 0);
+ node = lyd_child(node)->next;
+ dsc = "Inline Config content.";
+ CHECK_LYSC_NODE(node->schema, dsc, 0, LYS_STATUS_CURR | LYS_IS_INPUT, 1, "config", 0, LYS_ANYXML, 1, 0, NULL, 0);
+
+ node = ((struct lyd_node_any *)node)->value.tree;
+ CHECK_LYSC_NODE(node->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_PRESENCE, 1, "cp",
+ 1, LYS_CONTAINER, 0, 0, NULL, 0);
+
+ 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, "");
+ 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_STRING(tree, LYD_PRINT_WITHSIBLINGS,
+ "<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" message-id=\"25\"/>\n");
+ CHECK_LYD_STRING(op, LYD_PRINT_WITHSIBLINGS,
+ "<edit-config xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
+ " <target>\n"
+ " <running/>\n"
+ " </target>\n"
+ " <config>\n"
+ " <cp xmlns=\"urn:tests:a\">\n"
+ " <z xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\" nc:operation=\"delete\"/>\n"
+ " </cp>\n"
+ " <l1 xmlns=\"urn:tests:a\" xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\" nc:operation=\"replace\">\n"
+ " <a>val_a</a>\n"
+ " <b>val_b</b>\n"
+ " <c>val_c</c>\n"
+ " </l1>\n"
+ " </config>\n"
+ "</edit-config>\n");
+
+ lyd_free_all(tree);
+ lyd_free_all(op);
+
+ /* wrong namespace, element name, whatever... */
+ /* TODO */
+}
+
+static void
+test_netconf_action(void **state)
+{
+ const char *data;
+ struct ly_in *in;
+ struct lyd_node *tree, *op;
+
+ data = "<rpc message-id=\"25\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
+ "<action xmlns=\"urn:ietf:params:xml:ns:yang:1\">"
+ "<c xmlns=\"urn:tests:a\">\n"
+ " <act>\n"
+ " <al>value</al>\n"
+ " </act>\n"
+ "</c>\n"
+ "</action>\n"
+ "</rpc>\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_RPC_NETCONF, &tree, &op));
+ ly_in_free(in, 0);
+
+ CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 1, 1, LY_VALUE_XML, "rpc", 0, 0, 0, 0, "");
+ CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)lyd_child(tree), 0, 0, LY_VALUE_XML, "action", 0, 0, 0, 0, "");
+
+ assert_non_null(op);
+ CHECK_LYSC_ACTION((struct lysc_node_action *)op->schema, NULL, 0, LYS_STATUS_CURR,
+ 1, 0, 0, 1, "act", LYS_ACTION,
+ 1, 0, 0, 1, 0, NULL, 0);
+
+ CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS,
+ "<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" message-id=\"25\">\n"
+ " <action xmlns=\"urn:ietf:params:xml:ns:yang:1\"/>\n"
+ "</rpc>\n");
+ CHECK_LYD_STRING(op, LYD_PRINT_WITHSIBLINGS,
+ "<act xmlns=\"urn:tests:a\">\n"
+ " <al>value</al>\n"
+ "</act>\n");
+
+ lyd_free_all(tree);
+ lyd_free_all(op);
+
+ /* wrong namespace, element name, whatever... */
+ /* TODO */
+}
+
+static void
+test_netconf_reply_or_notification(void **state)
+{
+ const char *data;
+ struct ly_in *in;
+ struct lyd_node *action, *tree, *op, *op2;
+
+ /* parse the action */
+ data = "<c xmlns=\"urn:tests:a\">\n"
+ " <act>\n"
+ " <al>value</al>\n"
+ " </act>\n"
+ "</c>\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_RPC_YANG, &action, &op));
+ ly_in_free(in, 0);
+
+ /* parse notification first */
+ data = "<notification xmlns=\"urn:ietf:params:xml:ns:netconf:notification:1.0\">\n"
+ "<eventTime>2010-12-06T08:00:01Z</eventTime>\n"
+ "<c xmlns=\"urn:tests:a\">\n"
+ " <n1>\n"
+ " <nl>value</nl>\n"
+ " </n1>\n"
+ "</c>\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);
+
+ CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 0, 1, LY_VALUE_XML, "notification", 0, 0, 0, 0, "");
+ CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)lyd_child(tree), 0, 0, LY_VALUE_XML, "eventTime", 0, 0, 0, 0,
+ "2010-12-06T08:00:01Z");
+
+ assert_non_null(op2);
+ CHECK_LYSC_NOTIF((struct lysc_node_notif *)op2->schema, 1, NULL, 0, 0x4, 1, 0, "n1", 1, 0, NULL, 0);
+
+ CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS,
+ "<notification xmlns=\"urn:ietf:params:xml:ns:netconf:notification:1.0\">\n"
+ " <eventTime>2010-12-06T08:00:01Z</eventTime>\n"
+ "</notification>\n");
+ CHECK_LYD_STRING(op2, LYD_PRINT_WITHSIBLINGS,
+ "<n1 xmlns=\"urn:tests:a\">\n"
+ " <nl>value</nl>\n"
+ "</n1>\n");
+
+ 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"
+ "</rpc-reply>\n";
+ assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
+ assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, op, in, LYD_XML, LYD_TYPE_REPLY_NETCONF, &tree, NULL));
+ ly_in_free(in, 0);
+
+ CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 1, 0, LY_VALUE_XML, "rpc-reply", 0, 0, 0, 0, "");
+
+ CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS,
+ "<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" message-id=\"55\"/>\n");
+
+ lyd_free_all(tree);
+ /* it was connected to the action, do not free */
+
+ /* parse an ok reply */
+ data = "<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" message-id=\"55\">\n"
+ " <ok/>\n"
+ "</rpc-reply>\n";
+ assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
+ assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, op, in, LYD_XML, LYD_TYPE_REPLY_NETCONF, &tree, NULL));
+ ly_in_free(in, 0);
+
+ CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 1, 1, LY_VALUE_XML, "rpc-reply", 0, 0, 0, 0, "");
+ CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)lyd_child(tree), 0, 0, LY_VALUE_XML, "ok", 0, 0, 0, 0, "");
+
+ CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
+
+ lyd_free_all(tree);
+
+ /* parse an error reply */
+ data = "<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" message-id=\"55\">\n"
+ " <rpc-error>\n"
+ " <error-type>rpc</error-type>\n"
+ " <error-tag>missing-attribute</error-tag>\n"
+ " <error-severity>error</error-severity>\n"
+ " <error-info>\n"
+ " <bad-attribute>message-id</bad-attribute>\n"
+ " <bad-element>rpc</bad-element>\n"
+ " </error-info>\n"
+ " </rpc-error>\n"
+ "</rpc-reply>\n";
+ assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
+ assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, op, in, LYD_XML, LYD_TYPE_REPLY_NETCONF, &tree, NULL));
+ ly_in_free(in, 0);
+
+ CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 1, 1, LY_VALUE_XML, "rpc-reply", 0, 0, 0, 0, "");
+ CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)lyd_child(tree), 0, 1, LY_VALUE_XML, "rpc-error", 0, 0, 0, 0, "");
+
+ CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
+
+ lyd_free_all(tree);
+
+ lyd_free_all(action);
+
+ /* wrong namespace, element name, whatever... */
+ /* TODO */
+}
+
+static void
+test_filter_attributes(void **state)
+{
+ const char *data;
+ struct ly_in *in;
+ struct lyd_node *tree;
+ const struct lyd_node *node;
+ const char *dsc;
+ const char *ref = "RFC 6241, Section 7.7";
+ const char *feats[] = {"writable-running", NULL};
+
+ assert_non_null((ly_ctx_load_module(UTEST_LYCTX, "ietf-netconf", "2011-06-01", feats)));
+ assert_non_null((ly_ctx_load_module(UTEST_LYCTX, "notifications", "2008-07-14", NULL)));
+
+ data = "<get xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
+ " <filter type=\"xpath\" select=\"/*\"/>\n"
+ "</get>\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_RPC_YANG, &tree, NULL));
+ ly_in_free(in, 0);
+ assert_non_null(tree);
+
+ node = tree;
+ dsc = "Retrieve running configuration and device state information.";
+ CHECK_LYSC_ACTION((struct lysc_node_action *)node->schema, dsc, 0, LYS_STATUS_CURR,
+ 1, 0, 0, 1, "get", LYS_RPC,
+ 1, 0, 0, 0, 0, ref, 0);
+ node = lyd_child(node);
+ dsc = "This parameter specifies the portion of the system\nconfiguration and state data to retrieve.";
+ CHECK_LYSC_NODE(node->schema, dsc, 1, LYS_STATUS_CURR | LYS_IS_INPUT, 1, "filter", 0, LYS_ANYXML, 1, 0, NULL, 0);
+
+ CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ data = "<create-subscription xmlns=\"urn:ietf:params:xml:ns:netconf:notification:1.0\">\n"
+ " <filter type=\"subtree\">\n"
+ " <inner-node xmlns=\"my:urn\"/>\n"
+ " </filter>\n"
+ "</create-subscription>\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_RPC_YANG, &tree, NULL));
+ ly_in_free(in, 0);
+ assert_non_null(tree);
+
+ CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+}
+
+static void
+test_data_skip(void **state)
+{
+ const char *data;
+ struct lyd_node *tree;
+ struct lyd_node_term *leaf;
+
+ /* add invalid data to a module that is not implemented */
+ data = "<foo xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-metadata\"><u/></foo>";
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(_UC->ctx, data, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
+ assert_null(tree);
+
+ /* add invalid data to a module that is implemented */
+ data = "<fooX xmlns=\"urn:tests:a\"><u/><list><value/></list></fooX>";
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(_UC->ctx, data, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
+ assert_null(tree);
+
+ /* first invalid, next valid */
+ data = "<fooX xmlns=\"urn:tests:a\"><u/></fooX> <foo xmlns=\"urn:tests:a\">foo value</foo>";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "foo", 1, LYS_LEAF, 0, 0, NULL, 0);
+ leaf = (struct lyd_node_term *)tree;
+ CHECK_LYD_VALUE(leaf->value, STRING, "foo value");
+ lyd_free_all(tree);
+}
+
+int
+main(void)
+{
+ const struct CMUnitTest tests[] = {
+ UTEST(test_leaf, setup),
+ UTEST(test_anydata, setup),
+ UTEST(test_list, setup),
+ UTEST(test_container, setup),
+ UTEST(test_opaq, setup),
+ UTEST(test_rpc, setup),
+ UTEST(test_action, setup),
+ UTEST(test_notification, setup),
+ UTEST(test_reply, setup),
+ UTEST(test_netconf_rpc, setup),
+ UTEST(test_netconf_action, setup),
+ UTEST(test_netconf_reply_or_notification, setup),
+ UTEST(test_filter_attributes, setup),
+ UTEST(test_data_skip, 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
new file mode 100644
index 0000000..d533c41
--- /dev/null
+++ b/tests/utests/data/test_printer_xml.c
@@ -0,0 +1,343 @@
+/*
+ * @file test_printer_xml.c
+ * @author: Radek Krejci <rkrejci@cesnet.cz>
+ * @brief unit tests for functions from printer_yang.c
+ *
+ * Copyright (c) 2019-2020 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.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ */
+#define _UTEST_MAIN_
+#include "utests.h"
+
+#include <string.h>
+
+#include "context.h"
+#include "out.h"
+#include "parser_data.h"
+#include "printer_data.h"
+#include "tests_config.h"
+#include "tree_schema.h"
+
+static int
+setup(void **state)
+{
+ const char *schema_defs = "module defs {namespace urn:tests:defs;prefix d;yang-version 1.1;"
+ "identity crypto-alg; identity interface-type; identity ethernet {base interface-type;} identity fast-ethernet {base ethernet;}}";
+ const char *schema_types = "module types {namespace urn:tests:types;prefix t;yang-version 1.1; import defs {prefix defs;}"
+ "feature f; identity gigabit-ethernet { base defs:ethernet;}"
+ "container cont {leaf leaftarget {type empty;}"
+ " list listtarget {key id; max-elements 5;leaf id {type uint8;} leaf value {type string;}"
+ " action test {input {leaf a {type string;}} output {leaf b {type string;}}}}"
+ " leaf-list leaflisttarget {type uint8; max-elements 5;}}"
+ "list list {key id; leaf id {type string;} leaf value {type string;} leaf-list targets {type string;}}"
+ "list list2 {key \"id value\"; leaf id {type string;} leaf value {type string;}}"
+ "list list_inst {key id; leaf id {type instance-identifier {require-instance true;}} leaf value {type string;}}"
+ "list list_ident {key id; leaf id {type identityref {base defs:interface-type;}} leaf value {type string;}}"
+ "leaf-list leaflisttarget {type string;}"
+ "leaf binary {type binary {length 5 {error-message \"This base64 value must be of length 5.\";}}}"
+ "leaf binary-norestr {type binary;}"
+ "leaf int8 {type int8 {range 10..20;}}"
+ "leaf uint8 {type uint8 {range 150..200;}}"
+ "leaf int16 {type int16 {range -20..-10;}}"
+ "leaf uint16 {type uint16 {range 150..200;}}"
+ "leaf int32 {type int32;}"
+ "leaf uint32 {type uint32;}"
+ "leaf int64 {type int64;}"
+ "leaf uint64 {type uint64;}"
+ "leaf bits {type bits {bit zero; bit one {if-feature f;} bit two;}}"
+ "leaf enums {type enumeration {enum white; enum yellow {if-feature f;}}}"
+ "leaf dec64 {type decimal64 {fraction-digits 1; range 1.5..10;}}"
+ "leaf dec64-norestr {type decimal64 {fraction-digits 18;}}"
+ "leaf str {type string {length 8..10; pattern '[a-z ]*';}}"
+ "leaf str-norestr {type string;}"
+ "leaf bool {type boolean;}"
+ "leaf empty {type empty;}"
+ "leaf ident {type identityref {base defs:interface-type;}}"
+ "leaf inst {type instance-identifier {require-instance true;}}"
+ "leaf inst-noreq {type instance-identifier {require-instance false;}}"
+ "leaf lref {type leafref {path /leaflisttarget; require-instance true;}}"
+ "leaf lref2 {type leafref {path \"../list[id = current()/../str-norestr]/targets\"; require-instance true;}}"
+ "leaf un1 {type union {"
+ " type leafref {path /int8; require-instance true;}"
+ " type union { type identityref {base defs:interface-type;} type instance-identifier {require-instance true;} }"
+ " type string {length 1..20;}}}"
+ "anydata any;"
+ "rpc sum {input {leaf x {type uint8;} leaf y {type uint8;}} output {leaf result {type uint16;}}}}";
+ const char *schema_defaults =
+ "module defaults {\n"
+ " namespace \"urn:defaults\";\n"
+ " prefix d;\n"
+ " leaf a {\n"
+ " type union {\n"
+ " type instance-identifier;\n"
+ " type string;\n"
+ " }\n"
+ " default \"/d:b\";\n"
+ " }\n"
+ " leaf b {\n"
+ " type string;\n"
+ " }\n"
+ " leaf c {\n"
+ " type string;\n"
+ " }\n"
+ "}";
+
+ UTEST_SETUP;
+
+ UTEST_ADD_MODULE(schema_defs, LYS_IN_YANG, NULL, NULL);
+ UTEST_ADD_MODULE(schema_types, LYS_IN_YANG, NULL, NULL);
+ UTEST_ADD_MODULE(schema_defaults, LYS_IN_YANG, NULL, NULL);
+
+ return 0;
+}
+
+#define CHECK_PARSE_LYD(INPUT, PARSE_OPTION, VALIDATE_OPTION, TREE) \
+ CHECK_PARSE_LYD_PARAM(INPUT, LYD_XML, PARSE_OPTION, VALIDATE_OPTION, LY_SUCCESS, TREE)
+
+#define CHECK_LYD_STRING(IN_MODEL, PRINT_OPTION, TEXT) \
+ CHECK_LYD_STRING_PARAM(IN_MODEL, TEXT, LYD_XML, PRINT_OPTION)
+
+static void
+test_anydata(void **state)
+{
+ struct lyd_node *tree;
+ const char *data;
+
+ data = "<any xmlns=\"urn:tests:types\"><somexml xmlns:x=\"url:x\" xmlns=\"example.com\"><x:x/></somexml></any>";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ /* canonized */
+ data = "<any xmlns=\"urn:tests:types\"><somexml xmlns=\"example.com\"><x xmlns=\"url:x\"/></somexml></any>";
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ data = "<any xmlns=\"urn:tests:types\"/>";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ data = "<any xmlns=\"urn:tests:types\">\n"
+ " <cont>\n"
+ " <defs:elem1 xmlns:defs=\"urn:tests:defs\">\n"
+ " <elem2 xmlns:defaults=\"urn:defaults\" defs:attr1=\"defaults:val\" attr2=\"/defaults:node/defs:node2\">\n"
+ " </elem2>\n"
+ " </defs:elem1>\n"
+ " </cont>\n"
+ "</any>\n";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ assert_non_null(tree);
+ tree = tree->next;
+ /* cont should be normally parsed */
+ CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "any", 0, LYS_ANYDATA, 0, 0, NULL, 0);
+ CHECK_LYD_NODE_ANY((struct lyd_node_any *)tree, 0, 0, 0, LYD_ANYDATA_DATATREE);
+ struct lyd_node *tree_tmp = ((struct lyd_node_any *)tree)->value.tree;
+
+ CHECK_LYSC_NODE(tree_tmp->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "cont", 1, LYS_CONTAINER, 0, 0, NULL, 0);
+ /* but its children not */
+ assert_null(((struct lyd_node_inner *)tree_tmp)->child->schema);
+ /* canonized */
+ data =
+ "<any xmlns=\"urn:tests:types\">\n"
+ " <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"
+ " </elem1>\n"
+ " </cont>\n"
+ "</any>\n";
+ CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ data = "<any xmlns=\"urn:tests:types\">\n"
+ " <ahoj attr=\"&lt;test\">\n"
+ " ahoj jak se vede &lt; how are you"
+ " </ahoj>\n"
+ "</any>\n";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ data = "<any xmlns=\"urn:tests:types\">\n"
+ " <leaflisttarget> ahoj </leaflisttarget>\n"
+ " <leaflisttarget> nazdar </leaflisttarget>\n"
+ " <leaflisttarget> ÄŒau </leaflisttarget>\n"
+ "</any>\n";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ data = "<any xmlns=\"urn:tests:types\">\n"
+ " <cont2/>\n"
+ "</any>\n";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ data = "<any xmlns=\"urn:tests:types\">\n"
+ " <cont>\n"
+ " &lt; how are you"
+ " </cont>\n"
+ "</any>\n";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+}
+
+static void
+test_defaults(void **state)
+{
+ struct lyd_node *tree;
+ const char *data;
+ const char *data_trim;
+ const char *data_all;
+ const char *data_all_tag;
+ const char *data_impl_tag;
+
+ assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_DIR_MODULES_YANG));
+ assert_non_null(ly_ctx_load_module(UTEST_LYCTX, "ietf-netconf-with-defaults", "2011-06-01", NULL));
+
+ /* standard default value */
+ data = "<c xmlns=\"urn:defaults\">aa</c>";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ CHECK_LYD_STRING(tree, LYD_PRINT_WD_TRIM | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+
+ data = "<a xmlns=\"urn:defaults\" xmlns:d=\"urn:defaults\">/d:b</a><c xmlns=\"urn:defaults\">aa</c>";
+ CHECK_LYD_STRING(tree, LYD_PRINT_WD_ALL | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+
+ data = "<a xmlns=\"urn:defaults\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\""
+ " ncwd:default=\"true\" xmlns:d=\"urn:defaults\">/d:b</a>"
+ "<c xmlns=\"urn:defaults\">aa</c>";
+ CHECK_LYD_STRING(tree, LYD_PRINT_WD_ALL_TAG | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+
+ data = "<a xmlns=\"urn:defaults\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\""
+ " ncwd:default=\"true\" xmlns:d=\"urn:defaults\">/d:b</a>"
+ "<c xmlns=\"urn:defaults\">aa</c>";
+ CHECK_LYD_STRING(tree, LYD_PRINT_WD_IMPL_TAG | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ /* string value equal to the default but default is an unresolved instance-identifier, so they are not considered equal */
+ data = "<a xmlns=\"urn:defaults\">/d:b</a><c xmlns=\"urn:defaults\">aa</c>";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ CHECK_LYD_STRING(tree, LYD_PRINT_WD_TRIM | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ CHECK_LYD_STRING(tree, LYD_PRINT_WD_ALL | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ CHECK_LYD_STRING(tree, LYD_PRINT_WD_ALL_TAG | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ CHECK_LYD_STRING(tree, LYD_PRINT_WD_IMPL_TAG | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+ lyd_free_all(tree);
+
+ /* instance-identifier value equal to the default, should be considered equal */
+ data = "<a xmlns=\"urn:defaults\" xmlns:d=\"urn:defaults\">/d:b</a><b xmlns=\"urn:defaults\">val</b><c xmlns=\"urn:defaults\">aa</c>";
+ data_trim = "<b xmlns=\"urn:defaults\">val</b><c xmlns=\"urn:defaults\">aa</c>";
+ data_all = "<a xmlns=\"urn:defaults\" xmlns:d=\"urn:defaults\">/d:b</a><b xmlns=\"urn:defaults\">val</b><c xmlns=\"urn:defaults\">aa</c>";
+ data_all_tag = "<a xmlns=\"urn:defaults\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\""
+ " ncwd:default=\"true\" xmlns:d=\"urn:defaults\">/d:b</a>"
+ "<b xmlns=\"urn:defaults\">val</b>"
+ "<c xmlns=\"urn:defaults\">aa</c>";
+ data_impl_tag = "<a xmlns=\"urn:defaults\" xmlns:d=\"urn:defaults\">/d:b</a><b xmlns=\"urn:defaults\">val</b><c xmlns=\"urn:defaults\">aa</c>";
+
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ CHECK_LYD_STRING(tree, LYD_PRINT_WD_TRIM | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data_trim);
+ CHECK_LYD_STRING(tree, LYD_PRINT_WD_ALL | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data_all);
+ CHECK_LYD_STRING(tree, LYD_PRINT_WD_ALL_TAG | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data_all_tag);
+ CHECK_LYD_STRING(tree, LYD_PRINT_WD_IMPL_TAG | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data_impl_tag);
+ lyd_free_all(tree);
+}
+
+#if 0
+
+static void
+test_rpc(void **state)
+{
+ struct state_s *s = (struct state_s *)(*state);
+ struct lyd_node *tree1;
+ struct lyd_node *tree2;
+ const struct lyd_node **trees;
+ const char *request;
+ const char *reply, *result;
+ char *printed;
+ ssize_t len;
+ struct ly_out *out;
+
+ s->func = test_rpc;
+ assert_non_null(out = ly_out_new_memory(&printed, 0));
+
+ request = "<sum xmlns=\"urn:tests:types\"><x>10</x><y>20</y></sum>";
+ reply = "<result xmlns=\"urn:tests:types\">30</result>";
+ result = "<sum xmlns=\"urn:tests:types\"><result>30</result></sum>";
+ assert_non_null(tree1 = lyd_parse_mem(s->ctx, request, LYD_XML, LYD_OPT_RPC, NULL));
+ assert_true((len = lyd_print_tree(out, tree1, LYD_XML, LYD_PRINT_SHRINK)) >= 0);
+ assert_int_equal(len, strlen(printed));
+ assert_string_equal(printed, request);
+ ly_out_reset(out);
+ assert_non_null(trees = lyd_trees_new(1, tree1));
+ assert_non_null(tree2 = lyd_parse_mem(s->ctx, reply, LYD_XML, LYD_OPT_RPCREPLY, trees));
+ assert_true((len = lyd_print_tree(out, tree2, LYD_XML, LYD_PRINT_SHRINK)) >= 0);
+ assert_int_equal(len, strlen(printed));
+ assert_string_equal(printed, result);
+ ly_out_reset(out);
+ lyd_trees_free(trees, 0);
+ lyd_free_all(tree1);
+ lyd_free_all(tree2);
+
+ /* no arguments */
+ request = "<sum xmlns=\"urn:tests:types\"/>";
+ reply = "";
+ result = "<sum xmlns=\"urn:tests:types\"/>";
+ assert_non_null(tree1 = lyd_parse_mem(s->ctx, request, LYD_XML, LYD_OPT_RPC, NULL));
+ assert_true((len = lyd_print_tree(out, tree1, LYD_XML, LYD_PRINT_SHRINK)) >= 0);
+ assert_int_equal(len, strlen(printed));
+ assert_string_equal(printed, request);
+ ly_out_reset(out);
+ assert_non_null(trees = lyd_trees_new(1, tree1));
+ assert_non_null(tree2 = lyd_parse_mem(s->ctx, reply, LYD_XML, LYD_OPT_RPCREPLY, trees));
+ assert_true((len = lyd_print_tree(out, tree2, LYD_XML, LYD_PRINT_SHRINK)) >= 0);
+ assert_int_equal(len, strlen(printed));
+ assert_string_equal(printed, result);
+ ly_out_reset(out);
+ lyd_trees_free(trees, 0);
+ lyd_free_all(tree1);
+ lyd_free_all(tree2);
+
+ /* action
+ * "container cont {leaf leaftarget {type empty;}"
+ "list listtarget {key id; max-elements 5;leaf id {type uint8;} leaf value {type string;}"
+ "action test {input {leaf a {type string;}} output {leaf b {type string;}}}}"
+ "leaf-list leaflisttarget {type uint8; max-elements 5;}}"
+ */
+ request = "<cont xmlns=\"urn:tests:types\"><listtarget><id>10</id><test><a>test</a></test></listtarget></cont>";
+ reply = "<b xmlns=\"urn:tests:types\">test-reply</b>";
+ result = "<cont xmlns=\"urn:tests:types\"><listtarget><id>10</id><test><b>test-reply</b></test></listtarget></cont>";
+ assert_non_null(tree1 = lyd_parse_mem(s->ctx, request, LYD_XML, LYD_OPT_RPC, NULL));
+ assert_true((len = lyd_print_tree(out, tree1, LYD_XML, LYD_PRINT_SHRINK)) >= 0);
+ assert_int_equal(len, strlen(printed));
+ assert_string_equal(printed, request);
+ ly_out_reset(out);
+ assert_non_null(trees = lyd_trees_new(1, tree1));
+ assert_non_null(tree2 = lyd_parse_mem(s->ctx, reply, LYD_XML, LYD_OPT_RPCREPLY, trees));
+ assert_true((len = lyd_print_tree(out, tree2, LYD_XML, LYD_PRINT_SHRINK)) >= 0);
+ assert_int_equal(len, strlen(printed));
+ assert_string_equal(printed, result);
+ ly_out_reset(out);
+ lyd_trees_free(trees, 0);
+ lyd_free_all(tree1);
+ lyd_free_all(tree2);
+
+ ly_out_free(out, NULL, 1);
+ s->func = NULL;
+}
+
+#endif
+
+int
+main(void)
+{
+ const struct CMUnitTest tests[] = {
+ UTEST(test_anydata, setup),
+ UTEST(test_defaults, setup),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/tests/utests/data/test_tree_data.c b/tests/utests/data/test_tree_data.c
new file mode 100644
index 0000000..27dba42
--- /dev/null
+++ b/tests/utests/data/test_tree_data.c
@@ -0,0 +1,597 @@
+/**
+ * @file test_tree_data.c
+ * @author: Radek Krejci <rkrejci@cesnet.cz>
+ * @brief unit tests for functions from tress_data.c
+ *
+ * Copyright (c) 2018-2019 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.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ */
+#define _UTEST_MAIN_
+#include "utests.h"
+
+#include "common.h"
+#include "libyang.h"
+#include "path.h"
+#include "xpath.h"
+
+static int
+setup(void **state)
+{
+ const char *schema1 = "module a {namespace urn:tests:a;prefix a;yang-version 1.1;"
+ "revision 2014-05-08;"
+ "leaf bar {type string;}"
+ "list l1 { key \"a b\"; leaf a {type string;} leaf b {type string;} leaf c {type string;}}"
+ "leaf foo { type string;}"
+ "leaf-list ll { type string;}"
+ "container c {leaf-list x {type string;}}"
+ "anydata any {config false;}"
+ "list l2 {config false;"
+ " container c{leaf x {type string;} leaf-list d {type string;}}"
+ "}}";
+
+ const char *schema2 = "module b {namespace urn:tests:b;prefix b;yang-version 1.1;"
+ "revision 2014-05-08;"
+ "list l2 {config false;"
+ " container c{leaf x {type string;}}}"
+ "anydata any {config false;}"
+ "}";
+
+ const char *schema3 = "module c {yang-version 1.1; namespace \"http://example.com/main\";prefix m;"
+ "import \"ietf-inet-types\" {prefix inet;}"
+ "typedef optional-ip-address {type union {"
+ " type inet:ip-address;"
+ " type string;"
+ "}}"
+ "container cont {"
+ " list nexthop {min-elements 1; key \"gateway\";"
+ " leaf gateway {type optional-ip-address;}"
+ " }"
+ " leaf-list pref {type inet:ipv6-prefix;}"
+ "}}";
+
+ UTEST_SETUP;
+
+ UTEST_ADD_MODULE(schema1, LYS_IN_YANG, NULL, NULL);
+ UTEST_ADD_MODULE(schema2, LYS_IN_YANG, NULL, NULL);
+ UTEST_ADD_MODULE(schema3, LYS_IN_YANG, NULL, NULL);
+
+ return 0;
+}
+
+#define CHECK_PARSE_LYD(INPUT, PARSE_OPTION, VALIDATE_OPTION, TREE) \
+ CHECK_PARSE_LYD_PARAM(INPUT, LYD_XML, PARSE_OPTION, VALIDATE_OPTION, LY_SUCCESS, TREE)
+
+#define CHECK_PARSE_LYD_PARAM_CTX(CTX, INPUT, PARSE_OPTION, OUT_NODE) \
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(CTX, INPUT, LYD_XML, PARSE_OPTION, LYD_VALIDATE_PRESENT, &OUT_NODE)); \
+ assert_non_null(OUT_NODE);
+
+#define RECREATE_CTX_WITH_MODULE(CTX, MODULE) \
+ ly_ctx_destroy(CTX); \
+ assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &CTX)); \
+ assert_int_equal(LY_SUCCESS, ly_in_new_memory(MODULE, &_UC->in)); \
+ assert_int_equal(LY_SUCCESS, lys_parse(CTX, _UC->in, LYS_IN_YANG, NULL, NULL)); \
+ ly_in_free(_UC->in, 0);
+
+static void
+test_compare(void **state)
+{
+ struct lyd_node *tree1, *tree2;
+ const char *data1;
+ const char *data2;
+
+ assert_int_equal(LY_SUCCESS, lyd_compare_single(NULL, NULL, 0));
+
+ data1 = "<l1 xmlns=\"urn:tests:a\"><a>a</a><b>b</b><c>x</c></l1>";
+ data2 = "<l1 xmlns=\"urn:tests:a\"><a>a</a><b>b</b><c>y</c></l1>";
+ 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, 0));
+ assert_int_equal(LY_ENOT, lyd_compare_single(tree1, tree2, LYD_COMPARE_FULL_RECURSION));
+ assert_int_equal(LY_ENOT, lyd_compare_single(((struct lyd_node_inner *)tree1)->child, tree2, 0));
+ lyd_free_all(tree1);
+ lyd_free_all(tree2);
+
+ data1 = "<l2 xmlns=\"urn:tests:a\"><c><x>a</x></c></l2><l2 xmlns=\"urn:tests:a\"><c><x>b</x></c></l2>";
+ 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_SUCCESS, lyd_compare_single(tree1->next->next, tree2->next, 0));
+ lyd_free_all(tree1);
+ lyd_free_all(tree2);
+
+ data1 = "<ll xmlns=\"urn:tests:a\">a</ll><ll xmlns=\"urn:tests:a\">b</ll>";
+ data2 = "<ll xmlns=\"urn:tests:a\">b</ll>";
+ 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, tree2, 0));
+ assert_int_equal(LY_ENOT, lyd_compare_single(NULL, tree2, 0));
+ assert_int_equal(LY_ENOT, lyd_compare_single(tree1, NULL, 0));
+ assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1->next, tree2, 0));
+ lyd_free_all(tree1);
+ lyd_free_all(tree2);
+
+ data1 = "<c xmlns=\"urn:tests:a\"><x>x</x></c>";
+ data2 = "<c xmlns=\"urn:tests:a\"><x>y</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, 0));
+ assert_int_equal(LY_ENOT, lyd_compare_single(tree1, tree2, LYD_COMPARE_FULL_RECURSION));
+ lyd_free_all(tree1);
+ lyd_free_all(tree2);
+
+ data1 = "<c xmlns=\"urn:tests:a\"><x>x</x></c>";
+ data2 = "<c xmlns=\"urn:tests:a\"><x>x</x><x>y</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, 0));
+ assert_int_equal(LY_ENOT, lyd_compare_single(tree1, tree2, LYD_COMPARE_FULL_RECURSION));
+ lyd_free_all(tree1);
+ lyd_free_all(tree2);
+
+ data1 = "<any xmlns=\"urn:tests:a\"><x>x</x></any>";
+ data2 = "<any xmlns=\"urn:tests:a\"><x>x</x><x>y</x></any>";
+ 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));
+ lyd_free_all(tree1);
+ data1 = "<any xmlns=\"urn:tests:a\"><x>x</x><x>y</x></any>";
+ CHECK_PARSE_LYD(data1, 0, LYD_VALIDATE_PRESENT, tree1);
+ assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, 0));
+ lyd_free_all(tree1);
+ lyd_free_all(tree2);
+}
+
+static void
+test_compare_diff_ctx(void **state)
+{
+ struct lyd_node *tree1, *tree2;
+ const char *data1, *data2;
+ struct ly_ctx *ctx2 = NULL;
+ const char *module;
+
+ /* create second context with the same schema */
+ module = "module b {namespace urn:tests:b;prefix b;yang-version 1.1;"
+ "revision 2014-05-08;"
+ "list l2 {config false;"
+ " container c{leaf x {type string;}}"
+ "}}";
+ RECREATE_CTX_WITH_MODULE(ctx2, module);
+ data1 = "<l2 xmlns=\"urn:tests:b\"><c><x>b</x></c></l2>";
+ 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_SUCCESS, lyd_compare_single(tree1, tree2, LYD_COMPARE_FULL_RECURSION));
+ lyd_free_all(tree1);
+ lyd_free_all(tree2);
+
+ /* recreate second context with schema that has a different name */
+ module = "module c {namespace urn:tests:c;prefix c;yang-version 1.1;"
+ "revision 2014-05-08;"
+ "list l2 {config false;"
+ " container c{leaf x {type string;}}"
+ "}}";
+ RECREATE_CTX_WITH_MODULE(ctx2, module);
+ data1 = "<l2 xmlns=\"urn:tests:b\"><c><x>b</x></c></l2>";
+ data2 = "<l2 xmlns=\"urn:tests:c\"><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));
+ lyd_free_all(tree1);
+ lyd_free_all(tree2);
+
+ /* recreate second context with schema that has a different revision */
+ module = "module b {namespace urn:tests:b;prefix b;yang-version 1.1;"
+ "revision 2015-05-08;"
+ "list l2 {config false;"
+ " container c{leaf x {type string;}}"
+ "}}";
+ RECREATE_CTX_WITH_MODULE(ctx2, module);
+ data1 = "<l2 xmlns=\"urn:tests:b\"><c><x>b</x></c></l2>";
+ 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));
+ lyd_free_all(tree1);
+ lyd_free_all(tree2);
+
+ /* recreate second context with schema that has no revision */
+ module = "module b {namespace urn:tests:b;prefix b;yang-version 1.1;"
+ "list l2 {config false;"
+ " container c{leaf x {type string;}}"
+ "}}";
+ RECREATE_CTX_WITH_MODULE(ctx2, module);
+ data1 = "<l2 xmlns=\"urn:tests:b\"><c><x>b</x></c></l2>";
+ 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));
+ lyd_free_all(tree1);
+ lyd_free_all(tree2);
+
+ /* recreate second context with schema that has a different parent nodetype */
+ module = "module b {namespace urn:tests:b;prefix b;yang-version 1.1;"
+ "revision 2014-05-08;"
+ "container l2 {config false;"
+ " container c{leaf x {type string;}}"
+ "}}";
+ RECREATE_CTX_WITH_MODULE(ctx2, module);
+ data1 = "<l2 xmlns=\"urn:tests:b\"><c><x>b</x></c></l2>";
+ 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(lyd_child(lyd_child(tree1)), lyd_child(lyd_child(tree2)), 0));
+ lyd_free_all(tree1);
+ lyd_free_all(tree2);
+
+ /* recreate second context with the same opaq data nodes */
+ module = "module b {namespace urn:tests:b;prefix b;yang-version 1.1;"
+ "revision 2014-05-08;"
+ "anydata any {config false;}"
+ "}";
+ RECREATE_CTX_WITH_MODULE(ctx2, module);
+ data1 = "<any xmlns=\"urn:tests:b\" xmlns:aa=\"urn:tests:b\"><x>aa:x</x></any>";
+ data2 = "<any xmlns=\"urn:tests:b\" xmlns:bb=\"urn:tests:b\"><x>bb:x</x></any>";
+ CHECK_PARSE_LYD_PARAM_CTX(UTEST_LYCTX, data1, LYD_PARSE_ONLY, tree1);
+ CHECK_PARSE_LYD_PARAM_CTX(ctx2, data2, LYD_PARSE_ONLY, tree2);
+ assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, 0));
+ lyd_free_all(tree1);
+ lyd_free_all(tree2);
+
+ /* recreate second context with the different opaq data node value */
+ module = "module b {namespace urn:tests:b;prefix b;yang-version 1.1;"
+ "revision 2014-05-08;"
+ "anydata any {config false;}"
+ "}";
+ RECREATE_CTX_WITH_MODULE(ctx2, module);
+ data1 = "<any xmlns=\"urn:tests:b\" xmlns:aa=\"urn:tests:b\"><x>aa:x</x></any>";
+ data2 = "<any xmlns=\"urn:tests:b\" xmlns:bb=\"urn:tests:b\"><x>bb:y</x></any>";
+ CHECK_PARSE_LYD_PARAM_CTX(UTEST_LYCTX, data1, LYD_PARSE_ONLY, tree1);
+ CHECK_PARSE_LYD_PARAM_CTX(ctx2, data2, LYD_PARSE_ONLY, tree2);
+ assert_int_equal(LY_ENOT, lyd_compare_single(tree1, tree2, 0));
+ lyd_free_all(tree1);
+ lyd_free_all(tree2);
+
+ /* recreate second context with the wrong prefix in opaq data node value */
+ module = "module b {namespace urn:tests:b;prefix b;yang-version 1.1;"
+ "revision 2014-05-08;"
+ "anydata any {config false;}"
+ "}";
+ RECREATE_CTX_WITH_MODULE(ctx2, module);
+ data1 = "<any xmlns=\"urn:tests:b\" xmlns:aa=\"urn:tests:b\"><x>aa:x</x></any>";
+ data2 = "<any xmlns=\"urn:tests:b\" xmlns:bb=\"urn:tests:b\"><x>cc:x</x></any>";
+ CHECK_PARSE_LYD_PARAM_CTX(UTEST_LYCTX, data1, LYD_PARSE_ONLY, tree1);
+ CHECK_PARSE_LYD_PARAM_CTX(ctx2, data2, LYD_PARSE_ONLY, tree2);
+ assert_int_equal(LY_ENOT, lyd_compare_single(tree1, tree2, 0));
+ lyd_free_all(tree1);
+ lyd_free_all(tree2);
+
+ /* clean up */
+ ly_ctx_destroy(ctx2);
+ _UC->in = NULL;
+}
+
+static void
+test_dup(void **state)
+{
+ struct lyd_node *tree1, *tree2;
+ const char *result;
+ const char *data;
+
+ data = "<l1 xmlns=\"urn:tests:a\"><a>a</a><b>b</b><c>x</c></l1>";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree1);
+ assert_int_equal(LY_SUCCESS, lyd_dup_single(tree1, NULL, LYD_DUP_RECURSIVE, &tree2));
+ assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, LYD_COMPARE_FULL_RECURSION));
+ lyd_free_all(tree1);
+ lyd_free_all(tree2);
+
+ data = "<l1 xmlns=\"urn:tests:a\"><a>a</a><b>b</b><c>x</c></l1>";
+ result = "<l1 xmlns=\"urn:tests:a\"><a>a</a><b>b</b></l1>";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree1);
+ assert_int_equal(LY_SUCCESS, lyd_dup_single(tree1, NULL, 0, &tree2));
+ lyd_free_all(tree1);
+ CHECK_PARSE_LYD(result, 0, LYD_VALIDATE_PRESENT, tree1);
+ assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, LYD_COMPARE_FULL_RECURSION));
+ lyd_free_all(tree1);
+ lyd_free_all(tree2);
+
+ data = "<l2 xmlns=\"urn:tests:a\"><c><x>a</x></c></l2><l2 xmlns=\"urn:tests:a\"><c><x>b</x></c></l2>";
+ result = "<l2 xmlns=\"urn:tests:a\"><c><x>a</x></c></l2>";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree1);
+ assert_int_equal(LY_SUCCESS, lyd_dup_siblings(tree1, NULL, LYD_DUP_RECURSIVE, &tree2));
+ assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1->next, tree2->next, LYD_COMPARE_FULL_RECURSION));
+ lyd_free_all(tree2);
+ assert_int_equal(LY_SUCCESS, lyd_dup_single(tree1->next, NULL, LYD_DUP_RECURSIVE, &tree2));
+ lyd_free_all(tree1);
+ CHECK_PARSE_LYD(result, 0, LYD_VALIDATE_PRESENT, tree1);
+ assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1->next, tree2, LYD_COMPARE_FULL_RECURSION));
+ lyd_free_all(tree2);
+
+ assert_int_equal(LY_SUCCESS, lyd_dup_single(tree1->next, NULL, 0, &tree2));
+ lyd_free_all(tree1);
+ result = "<l2 xmlns=\"urn:tests:a\"/>";
+ CHECK_PARSE_LYD_PARAM(result, LYD_XML, LYD_PARSE_ONLY, 0, LY_SUCCESS, tree1);
+ assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, LYD_COMPARE_FULL_RECURSION));
+ lyd_free_all(tree1);
+ lyd_free_all(tree2);
+
+ data = "<any xmlns=\"urn:tests:a\"><c><a>a</a></c></any>";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree1);
+ assert_int_equal(LY_SUCCESS, lyd_dup_single(tree1, NULL, 0, &tree2));
+ assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, LYD_COMPARE_FULL_RECURSION));
+ lyd_free_all(tree1);
+ lyd_free_all(tree2);
+
+ 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));
+ 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);
+ assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1->next, (struct lyd_node *)tree2->parent->parent,
+ LYD_COMPARE_FULL_RECURSION));
+ lyd_free_all(tree1);
+ lyd_free_all(tree2);
+
+ data = "<l1 xmlns=\"urn:tests:a\"><a>a</a><b>b</b><c>c</c></l1>";
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree1);
+ assert_int_equal(LY_SUCCESS, lyd_dup_single(((struct lyd_node_inner *)tree1)->child->prev, NULL,
+ LYD_DUP_WITH_PARENTS, &tree2));
+ flag = LYS_CONFIG_W | LYS_SET_ENUM;
+ CHECK_LYSC_NODE(tree2->schema, NULL, 0, flag, 1, "c", 0, LYS_LEAF, 1, 0, NULL, 0);
+ assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, (struct lyd_node *)tree2->parent, LYD_COMPARE_FULL_RECURSION));
+ lyd_free_all(tree1);
+ lyd_free_all(tree2);
+
+ 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_compare_single(tree1->next, tree2, LYD_COMPARE_FULL_RECURSION));
+ lyd_free_all(tree1);
+ lyd_free_all(tree2);
+
+ /* invalid */
+ data = "<l1 xmlns=\"urn:tests:a\"><a>a</a><b>b</b><c>c</c></l1><l2 xmlns=\"urn:tests:a\"><c><x>b</x></c></l2>";
+ 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));
+ lyd_free_all(tree1);
+}
+
+static void
+test_target(void **state)
+{
+ const struct lyd_node_term *term;
+ struct lyd_node *tree;
+ struct lyxp_expr *exp;
+ struct ly_path *path;
+ const char *path_str = "/a:l2[2]/c/d[3]";
+ const char *data =
+ "<l2 xmlns=\"urn:tests:a\"><c>"
+ " <d>a</d>"
+ " </c></l2>"
+ "<l2 xmlns=\"urn:tests:a\"><c>"
+ " <d>a</d>"
+ " <d>b</d>"
+ " <d>b</d>"
+ " <d>c</d>"
+ "</c></l2>"
+ "<l2 xmlns=\"urn:tests:a\"><c>"
+ "</c></l2>";
+
+ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
+ assert_int_equal(LY_SUCCESS, ly_path_parse(UTEST_LYCTX, NULL, path_str, strlen(path_str), 0, LY_PATH_BEGIN_EITHER,
+ LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_SIMPLE, &exp));
+ assert_int_equal(LY_SUCCESS, ly_path_compile(UTEST_LYCTX, NULL, NULL, NULL, exp, LY_PATH_OPER_INPUT,
+ LY_PATH_TARGET_SINGLE, 1, LY_VALUE_JSON, NULL, &path));
+ term = lyd_target(path, tree);
+
+ const int unsigned flag = LYS_CONFIG_R | LYS_SET_ENUM | LYS_ORDBY_USER;
+
+ CHECK_LYSC_NODE(term->schema, NULL, 0, flag, 1, "d", 0, LYS_LEAFLIST, 1, 0, NULL, 0);
+ assert_string_equal(lyd_get_value(&term->node), "b");
+ assert_string_equal(lyd_get_value(term->prev), "b");
+
+ lyd_free_all(tree);
+ ly_path_free(UTEST_LYCTX, path);
+ lyxp_expr_free(UTEST_LYCTX, exp);
+}
+
+static void
+test_list_pos(void **state)
+{
+ const char *data;
+ struct lyd_node *tree;
+
+ data = "<bar xmlns=\"urn:tests:a\">test</bar>"
+ "<l1 xmlns=\"urn:tests:a\"><a>one</a><b>one</b></l1>"
+ "<l1 xmlns=\"urn:tests:a\"><a>two</a><b>two</b></l1>"
+ "<foo xmlns=\"urn:tests:a\">test</foo>";
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
+ assert_int_equal(0, lyd_list_pos(tree));
+ assert_int_equal(1, lyd_list_pos(tree->next));
+ assert_int_equal(2, lyd_list_pos(tree->next->next));
+ assert_int_equal(0, lyd_list_pos(tree->next->next->next));
+ lyd_free_all(tree);
+
+ data = "<ll xmlns=\"urn:tests:a\">one</ll>"
+ "<ll xmlns=\"urn:tests:a\">two</ll>"
+ "<ll xmlns=\"urn:tests:a\">three</ll>";
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
+ assert_int_equal(1, lyd_list_pos(tree));
+ assert_int_equal(2, lyd_list_pos(tree->next));
+ assert_int_equal(3, lyd_list_pos(tree->next->next));
+ lyd_free_all(tree);
+
+ data = "<ll xmlns=\"urn:tests:a\">one</ll>"
+ "<l1 xmlns=\"urn:tests:a\"><a>one</a><b>one</b></l1>"
+ "<ll xmlns=\"urn:tests:a\">two</ll>"
+ "<l1 xmlns=\"urn:tests:a\"><a>two</a><b>two</b></l1>"
+ "<ll xmlns=\"urn:tests:a\">three</ll>"
+ "<l1 xmlns=\"urn:tests:a\"><a>three</a><b>three</b></l1>";
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
+ assert_string_equal("l1", tree->schema->name);
+ assert_int_equal(1, lyd_list_pos(tree));
+ assert_int_equal(2, lyd_list_pos(tree->next));
+ assert_int_equal(3, lyd_list_pos(tree->next->next));
+ assert_string_equal("ll", tree->next->next->next->schema->name);
+ assert_int_equal(1, lyd_list_pos(tree->next->next->next));
+ assert_int_equal(2, lyd_list_pos(tree->next->next->next->next));
+ assert_int_equal(3, lyd_list_pos(tree->next->next->next->next->next));
+ lyd_free_all(tree);
+}
+
+static void
+test_first_sibling(void **state)
+{
+ const char *data;
+ struct lyd_node *tree;
+ struct lyd_node_inner *parent;
+
+ data = "<bar xmlns=\"urn:tests:a\">test</bar>"
+ "<l1 xmlns=\"urn:tests:a\"><a>one</a><b>one</b><c>one</c></l1>"
+ "<foo xmlns=\"urn:tests:a\">test</foo>";
+ assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
+ assert_ptr_equal(tree, lyd_first_sibling(tree->next));
+ assert_ptr_equal(tree, lyd_first_sibling(tree));
+ assert_ptr_equal(tree, lyd_first_sibling(tree->prev));
+ parent = (struct lyd_node_inner *)tree->next;
+ assert_int_equal(LYS_LIST, parent->schema->nodetype);
+ assert_ptr_equal(parent->child, lyd_first_sibling(parent->child->next));
+ assert_ptr_equal(parent->child, lyd_first_sibling(parent->child));
+ assert_ptr_equal(parent->child, lyd_first_sibling(parent->child->prev));
+ lyd_free_all(tree);
+}
+
+static void
+test_find_path(void **state)
+{
+ struct lyd_node *root;
+ const struct lys_module *mod;
+
+ mod = ly_ctx_get_module_implemented(UTEST_LYCTX, "c");
+ assert_non_null(mod);
+
+ assert_int_equal(LY_SUCCESS, lyd_new_inner(NULL, mod, "cont", 0, &root));
+ assert_int_equal(LY_SUCCESS, lyd_new_path(root, NULL, "/c:cont/nexthop[gateway='10.0.0.1']", NULL, LYD_NEW_PATH_UPDATE, NULL));
+ assert_int_equal(LY_SUCCESS, lyd_new_path(root, NULL, "/c:cont/nexthop[gateway='2100::1']", NULL, LYD_NEW_PATH_UPDATE, NULL));
+ assert_int_equal(LY_SUCCESS, lyd_new_path(root, NULL, "/c:cont/pref[.='fc00::/64']", NULL, 0, NULL));
+
+ 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));
+ lyd_free_all(root);
+}
+
+static void
+test_data_hash(void **state)
+{
+ struct lyd_node *tree;
+ const char *schema, *data;
+
+ schema =
+ "module test-data-hash {"
+ " yang-version 1.1;"
+ " namespace \"urn:tests:tdh\";"
+ " prefix t;"
+ " container c {"
+ " leaf-list ll {"
+ " type string;"
+ " }"
+ " }"
+ "}";
+
+ UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
+
+ /* The number of <ll/> must be greater or equal to LYD_HT_MIN_ITEMS
+ * for the correct test run. It should guarantee the creation of a hash table.
+ */
+ assert_true(LYD_HT_MIN_ITEMS <= 4);
+ data =
+ "<c xmlns='urn:tests:tdh'>"
+ " <ll/>"
+ " <ll/>"
+ " <ll/>"
+ " <ll/>"
+ "</c>";
+
+ /* 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);
+ lyd_free_all(tree);
+}
+
+static void
+test_lyxp_vars(void **UNUSED(state))
+{
+ struct lyxp_var *vars;
+
+ /* Test free. */
+ vars = NULL;
+ lyxp_vars_free(vars);
+
+ /* Bad arguments for lyxp_vars_add(). */
+ assert_int_equal(LY_EINVAL, lyxp_vars_set(NULL, "var1", "val1"));
+ assert_int_equal(LY_EINVAL, lyxp_vars_set(&vars, NULL, "val1"));
+ assert_int_equal(LY_EINVAL, lyxp_vars_set(&vars, "var1", NULL));
+ lyxp_vars_free(vars);
+ vars = NULL;
+
+ /* Add one item. */
+ assert_int_equal(LY_SUCCESS, lyxp_vars_set(&vars, "var1", "val1"));
+ assert_int_equal(LY_ARRAY_COUNT(vars), 1);
+ assert_string_equal(vars[0].name, "var1");
+ assert_string_equal(vars[0].value, "val1");
+ lyxp_vars_free(vars);
+ vars = NULL;
+
+ /* Add three items. */
+ assert_int_equal(LY_SUCCESS, lyxp_vars_set(&vars, "var1", "val1"));
+ assert_int_equal(LY_SUCCESS, lyxp_vars_set(&vars, "var2", "val2"));
+ assert_int_equal(LY_SUCCESS, lyxp_vars_set(&vars, "var3", "val3"));
+ assert_int_equal(LY_ARRAY_COUNT(vars), 3);
+ assert_string_equal(vars[0].name, "var1");
+ assert_string_equal(vars[0].value, "val1");
+ assert_string_equal(vars[1].name, "var2");
+ assert_string_equal(vars[1].value, "val2");
+ assert_string_equal(vars[2].name, "var3");
+ assert_string_equal(vars[2].value, "val3");
+ lyxp_vars_free(vars);
+ vars = NULL;
+
+ /* Change value of a variable. */
+ assert_int_equal(LY_SUCCESS, lyxp_vars_set(&vars, "var1", "val1"));
+ assert_int_equal(LY_SUCCESS, lyxp_vars_set(&vars, "var2", "val2"));
+ assert_int_equal(LY_SUCCESS, lyxp_vars_set(&vars, "var1", "new_value"));
+ assert_string_equal(vars[0].name, "var1");
+ assert_string_equal(vars[0].value, "new_value");
+ assert_string_equal(vars[1].name, "var2");
+ assert_string_equal(vars[1].value, "val2");
+ lyxp_vars_free(vars);
+ vars = NULL;
+}
+
+int
+main(void)
+{
+ const struct CMUnitTest tests[] = {
+ UTEST(test_compare, setup),
+ UTEST(test_compare_diff_ctx, setup),
+ UTEST(test_dup, setup),
+ UTEST(test_target, setup),
+ UTEST(test_list_pos, setup),
+ UTEST(test_first_sibling, setup),
+ UTEST(test_find_path, setup),
+ UTEST(test_data_hash, setup),
+ UTEST(test_lyxp_vars),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/tests/utests/data/test_validation.c b/tests/utests/data/test_validation.c
new file mode 100644
index 0000000..415e16a
--- /dev/null
+++ b/tests/utests/data/test_validation.c
@@ -0,0 +1,1460 @@
+/**
+ * @file test_validation.c
+ * @author: Radek Krejci <rkrejci@cesnet.cz>
+ * @brief unit tests for functions from validation.c
+ *
+ * Copyright (c) 2020 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.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ */
+#define _UTEST_MAIN_
+#include "utests.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "context.h"
+#include "in.h"
+#include "out.h"
+#include "parser_data.h"
+#include "printer_data.h"
+#include "tests_config.h"
+#include "tree_data_internal.h"
+#include "tree_schema.h"
+
+#define LYD_TREE_CREATE(INPUT, MODEL) \
+ CHECK_PARSE_LYD_PARAM(INPUT, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, MODEL)
+
+static void
+test_when(void **state)
+{
+ struct lyd_node *tree;
+ const char *schema =
+ "module a {\n"
+ " namespace urn:tests:a;\n"
+ " prefix a;\n"
+ " yang-version 1.1;\n"
+ "\n"
+ " container cont {\n"
+ " leaf a {\n"
+ " when \"../../c = 'val_c'\";\n"
+ " type string;\n"
+ " }\n"
+ " leaf b {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ " leaf c {\n"
+ " when \"/cont/b = 'val_b'\";\n"
+ " type string;\n"
+ " }\n"
+ "}";
+
+ UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
+
+ CHECK_PARSE_LYD_PARAM("<c xmlns=\"urn:tests:a\">hey</c>", LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
+ CHECK_LOG_CTX("When condition \"/cont/b = 'val_b'\" not satisfied.", "Data location \"/a:c\".");
+
+ LYD_TREE_CREATE("<cont xmlns=\"urn:tests:a\"><b>val_b</b></cont><c xmlns=\"urn:tests:a\">hey</c>", tree);
+ CHECK_LYSC_NODE(tree->next->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "c", 0, LYS_LEAF, 0, 0, NULL, 1);
+ assert_int_equal(LYD_WHEN_TRUE, tree->next->flags);
+ lyd_free_all(tree);
+
+ LYD_TREE_CREATE("<cont xmlns=\"urn:tests:a\"><a>val</a><b>val_b</b></cont><c xmlns=\"urn:tests:a\">val_c</c>", tree);
+ CHECK_LYSC_NODE(lyd_child(tree)->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "a", 1, LYS_LEAF, 1, 0, NULL, 1);
+ assert_int_equal(LYD_WHEN_TRUE, lyd_child(tree)->flags);
+ CHECK_LYSC_NODE(tree->next->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "c", 0, LYS_LEAF, 0, 0, NULL, 1);
+ assert_int_equal(LYD_WHEN_TRUE, tree->next->flags);
+ lyd_free_all(tree);
+}
+
+static void
+test_mandatory_when(void **state)
+{
+ struct lyd_node *tree;
+ const char *schema =
+ "module a {\n"
+ " namespace urn:tests:a;\n"
+ " prefix a;\n"
+ " yang-version 1.1;\n"
+ "\n"
+ " container cont {\n"
+ " leaf a {\n"
+ " type string;\n"
+ " }\n"
+ " leaf b {\n"
+ " when \"../a = 'val_a'\";\n"
+ " mandatory true;\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ " leaf c {\n"
+ " type string;\n"
+ " }\n"
+ " leaf d {\n"
+ " when \"../c = 'val_c'\";\n"
+ " mandatory true;\n"
+ " type string;\n"
+ " }\n"
+ "}";
+
+ UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
+
+ CHECK_PARSE_LYD_PARAM("<d xmlns=\"urn:tests:a\">hey</d>", LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
+ CHECK_LOG_CTX("When condition \"../c = 'val_c'\" not satisfied.", "Data location \"/a:d\".");
+
+ CHECK_PARSE_LYD_PARAM("<cont xmlns=\"urn:tests:a\"><b>hey</b></cont>", LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
+ CHECK_LOG_CTX("When condition \"../a = 'val_a'\" not satisfied.", "Data location \"/a:cont/b\".");
+
+ LYD_TREE_CREATE("<c xmlns=\"urn:tests:a\">val_c</c><d xmlns=\"urn:tests:a\">hey</d>", tree);
+ CHECK_LYSC_NODE(tree->next->next->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_MAND_TRUE, 1, "d", 0, LYS_LEAF, 0, 0, NULL, 1);
+ assert_int_equal(LYD_WHEN_TRUE, tree->next->next->flags);
+ lyd_free_all(tree);
+
+ LYD_TREE_CREATE("<cont xmlns=\"urn:tests:a\"><a>val_a</a><b>hey</b></cont>", tree);
+ CHECK_LYSC_NODE(lyd_child(tree)->next->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_MAND_TRUE, 1, "b", 0, LYS_LEAF, tree->schema, 0, NULL, 1);
+ assert_int_equal(LYD_WHEN_TRUE, lyd_child(tree)->next->flags);
+ lyd_free_all(tree);
+}
+
+static void
+test_type_incomplete_when(void **state)
+{
+ struct lys_module *mod;
+ struct lyd_node *tree;
+ const char *schema =
+ "module a {\n"
+ " namespace urn:tests:a;\n"
+ " prefix a;\n"
+ " yang-version 1.1;\n"
+ "\n"
+ " container cont {\n"
+ " when \"../c = 'val_c'\";\n"
+ " leaf a {\n"
+ " type leafref {\n"
+ " path \"/a:c\";\n"
+ " }\n"
+ " }\n"
+ " leaf b {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ " leaf c {\n"
+ " type string;\n"
+ " }\n"
+ "}";
+
+ UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
+
+ LYD_TREE_CREATE("<cont xmlns=\"urn:tests:a\"><a>val_c</a><b>val</b></cont><c xmlns=\"urn:tests:a\">val_c</c>", tree);
+
+ /* make the when false */
+ assert_int_equal(LY_SUCCESS, lyd_change_term(tree->next, "wrong-val"));
+
+ /* autodelete when with a leafref */
+ assert_int_equal(LY_SUCCESS, lyd_validate_module(&tree, mod, 0, NULL));
+ assert_string_equal(LYD_NAME(tree), "c");
+ assert_null(tree->next);
+
+ lyd_free_all(tree);
+}
+
+static void
+test_mandatory(void **state)
+{
+ struct lyd_node *tree;
+ const char *schema =
+ "module b {\n"
+ " namespace urn:tests:b;\n"
+ " prefix b;\n"
+ " yang-version 1.1;\n"
+ "\n"
+ " choice choic {\n"
+ " mandatory true;\n"
+ " leaf a {\n"
+ " type string;\n"
+ " }\n"
+ " case b {\n"
+ " leaf l {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " leaf c {\n"
+ " mandatory true;\n"
+ " type string;\n"
+ " }\n"
+ " leaf d {\n"
+ " type empty;\n"
+ " }\n"
+ "}";
+
+ UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
+
+ CHECK_PARSE_LYD_PARAM("<d xmlns=\"urn:tests:b\"/>", LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
+ CHECK_LOG_CTX_APPTAG("Mandatory choice \"choic\" data do not exist.", "Schema location \"/b:choic\".", "missing-choice");
+
+ CHECK_PARSE_LYD_PARAM("<l xmlns=\"urn:tests:b\">string</l><d xmlns=\"urn:tests:b\"/>", LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
+ CHECK_LOG_CTX("Mandatory node \"c\" instance does not exist.", "Schema location \"/b:c\".");
+
+ CHECK_PARSE_LYD_PARAM("<a xmlns=\"urn:tests:b\">string</a>", LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
+ CHECK_LOG_CTX("Mandatory node \"c\" instance does not exist.", "Schema location \"/b:c\".");
+
+ LYD_TREE_CREATE("<a xmlns=\"urn:tests:b\">string</a><c xmlns=\"urn:tests:b\">string2</c>", tree);
+ lyd_free_siblings(tree);
+}
+
+static void
+test_minmax(void **state)
+{
+ struct lyd_node *tree;
+ const char *schema =
+ "module c {\n"
+ " namespace urn:tests:c;\n"
+ " prefix c;\n"
+ " yang-version 1.1;\n"
+ "\n"
+ " choice choic {\n"
+ " leaf a {\n"
+ " type string;\n"
+ " }\n"
+ " case b {\n"
+ " leaf-list l {\n"
+ " min-elements 3;\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " list lt {\n"
+ " max-elements 4;\n"
+ " key \"k\";\n"
+ " leaf k {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ " leaf d {\n"
+ " type empty;\n"
+ " }\n"
+ "}";
+
+ UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
+
+ CHECK_PARSE_LYD_PARAM("<l xmlns=\"urn:tests:c\">mate</l>"
+ "<d xmlns=\"urn:tests:c\"/>",
+ LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
+ CHECK_LOG_CTX_APPTAG("Too few \"l\" instances.", "Schema location \"/c:choic/b/l\".", "too-few-elements");
+
+ CHECK_PARSE_LYD_PARAM("<l xmlns=\"urn:tests:c\">val1</l>"
+ "<l xmlns=\"urn:tests:c\">val2</l>",
+ LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
+ CHECK_LOG_CTX_APPTAG("Too few \"l\" instances.", "Schema location \"/c:choic/b/l\".", "too-few-elements");
+
+ LYD_TREE_CREATE("<l xmlns=\"urn:tests:c\">val1</l>"
+ "<l xmlns=\"urn:tests:c\">val2</l>"
+ "<l xmlns=\"urn:tests:c\">val3</l>", tree);
+ lyd_free_all(tree);
+
+ CHECK_PARSE_LYD_PARAM("<l xmlns=\"urn:tests:c\">val1</l>"
+ "<l xmlns=\"urn:tests:c\">val2</l>"
+ "<l xmlns=\"urn:tests:c\">val3</l>"
+ "<lt xmlns=\"urn:tests:c\"><k>val1</k></lt>"
+ "<lt xmlns=\"urn:tests:c\"><k>val2</k></lt>"
+ "<lt xmlns=\"urn:tests:c\"><k>val3</k></lt>"
+ "<lt xmlns=\"urn:tests:c\"><k>val4</k></lt>"
+ "<lt xmlns=\"urn:tests:c\"><k>val5</k></lt>"
+ "<lt xmlns=\"urn:tests:c\"><k>val6</k></lt>", LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
+ CHECK_LOG_CTX_APPTAG("Too many \"lt\" instances.", "Data location \"/c:lt[k='val5']\".",
+ "too-many-elements");
+}
+
+const char *schema_d =
+ "module d {\n"
+ " namespace urn:tests:d;\n"
+ " prefix d;\n"
+ " yang-version 1.1;\n"
+ "\n"
+ " list lt {\n"
+ " key \"k\";\n"
+ " unique \"l1\";\n"
+ " leaf k {\n"
+ " type string;\n"
+ " }\n"
+ " leaf l1 {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ " list lt2 {\n"
+ " key \"k\";\n"
+ " unique \"cont/l2 l4\";\n"
+ " unique \"l5 l6\";\n"
+ " leaf k {\n"
+ " type string;\n"
+ " }\n"
+ " container cont {\n"
+ " leaf l2 {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ " leaf l4 {\n"
+ " type string;\n"
+ " }\n"
+ " leaf l5 {\n"
+ " type string;\n"
+ " }\n"
+ " leaf l6 {\n"
+ " type string;\n"
+ " }\n"
+ " list lt3 {\n"
+ " key \"kk\";\n"
+ " unique \"l3\";\n"
+ " leaf kk {\n"
+ " type string;\n"
+ " }\n"
+ " leaf l3 {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ "}";
+
+static void
+test_unique(void **state)
+{
+ struct lyd_node *tree;
+
+ UTEST_ADD_MODULE(schema_d, LYS_IN_YANG, NULL, NULL);
+
+ LYD_TREE_CREATE("<lt xmlns=\"urn:tests:d\">\n"
+ " <k>val1</k>\n"
+ " <l1>same</l1>\n"
+ "</lt>\n"
+ "<lt xmlns=\"urn:tests:d\">\n"
+ " <k>val2</k>\n"
+ "</lt>", tree);
+ lyd_free_all(tree);
+
+ LYD_TREE_CREATE("<lt xmlns=\"urn:tests:d\">\n"
+ " <k>val1</k>\n"
+ " <l1>same</l1>\n"
+ "</lt>\n"
+ "<lt xmlns=\"urn:tests:d\">\n"
+ " <k>val2</k>\n"
+ " <l1>not-same</l1>\n"
+ "</lt>", tree);
+ lyd_free_all(tree);
+
+ CHECK_PARSE_LYD_PARAM("<lt xmlns=\"urn:tests:d\">\n"
+ " <k>val1</k>\n"
+ " <l1>same</l1>\n"
+ "</lt>\n"
+ "<lt xmlns=\"urn:tests:d\">\n"
+ " <k>val2</k>\n"
+ " <l1>same</l1>\n"
+ "</lt>", LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
+ CHECK_LOG_CTX_APPTAG("Unique data leaf(s) \"l1\" not satisfied in \"/d:lt[k='val1']\" and \"/d:lt[k='val2']\".",
+ "Data location \"/d:lt[k='val2']\".", "data-not-unique");
+
+ /* now try with more instances */
+ LYD_TREE_CREATE("<lt xmlns=\"urn:tests:d\">\n"
+ " <k>val1</k>\n"
+ " <l1>1</l1>\n"
+ "</lt>\n"
+ "<lt xmlns=\"urn:tests:d\">\n"
+ " <k>val2</k>\n"
+ " <l1>2</l1>\n"
+ "</lt>\n"
+ "<lt xmlns=\"urn:tests:d\">\n"
+ " <k>val3</k>\n"
+ " <l1>3</l1>\n"
+ "</lt>\n"
+ "<lt xmlns=\"urn:tests:d\">\n"
+ " <k>val4</k>\n"
+ " <l1>4</l1>\n"
+ "</lt>\n"
+ "<lt xmlns=\"urn:tests:d\">\n"
+ " <k>val5</k>\n"
+ " <l1>5</l1>\n"
+ "</lt>\n"
+ "<lt xmlns=\"urn:tests:d\">\n"
+ " <k>val6</k>\n"
+ " <l1>6</l1>\n"
+ "</lt>\n"
+ "<lt xmlns=\"urn:tests:d\">\n"
+ " <k>val7</k>\n"
+ " <l1>7</l1>\n"
+ "</lt>\n"
+ "<lt xmlns=\"urn:tests:d\">\n"
+ " <k>val8</k>\n"
+ " <l1>8</l1>\n"
+ "</lt>", tree);
+ lyd_free_all(tree);
+
+ LYD_TREE_CREATE("<lt xmlns=\"urn:tests:d\">\n"
+ " <k>val1</k>\n"
+ " <l1>1</l1>\n"
+ "</lt>\n"
+ "<lt xmlns=\"urn:tests:d\">\n"
+ " <k>val2</k>\n"
+ " <l1>2</l1>\n"
+ "</lt>\n"
+ "<lt xmlns=\"urn:tests:d\">\n"
+ " <k>val3</k>\n"
+ " <l1>3</l1>\n"
+ "</lt>\n"
+ "<lt xmlns=\"urn:tests:d\">\n"
+ " <k>val4</k>\n"
+ "</lt>\n"
+ "<lt xmlns=\"urn:tests:d\">\n"
+ " <k>val5</k>\n"
+ " <l1>5</l1>\n"
+ "</lt>\n"
+ "<lt xmlns=\"urn:tests:d\">\n"
+ " <k>val6</k>\n"
+ " <l1>6</l1>\n"
+ "</lt>\n"
+ "<lt xmlns=\"urn:tests:d\">\n"
+ " <k>val7</k>\n"
+ "</lt>\n"
+ "<lt xmlns=\"urn:tests:d\">\n"
+ " <k>val8</k>\n"
+ "</lt>", tree);
+ lyd_free_all(tree);
+
+ CHECK_PARSE_LYD_PARAM("<lt xmlns=\"urn:tests:d\">\n"
+ " <k>val1</k>\n"
+ " <l1>1</l1>\n"
+ "</lt>\n"
+ "<lt xmlns=\"urn:tests:d\">\n"
+ " <k>val2</k>\n"
+ " <l1>2</l1>\n"
+ "</lt>\n"
+ "<lt xmlns=\"urn:tests:d\">\n"
+ " <k>val3</k>\n"
+ "</lt>\n"
+ "<lt xmlns=\"urn:tests:d\">\n"
+ " <k>val4</k>\n"
+ " <l1>4</l1>\n"
+ "</lt>\n"
+ "<lt xmlns=\"urn:tests:d\">\n"
+ " <k>val5</k>\n"
+ "</lt>\n"
+ "<lt xmlns=\"urn:tests:d\">\n"
+ " <k>val6</k>\n"
+ "</lt>\n"
+ "<lt xmlns=\"urn:tests:d\">\n"
+ " <k>val7</k>\n"
+ " <l1>2</l1>\n"
+ "</lt>\n"
+ "<lt xmlns=\"urn:tests:d\">\n"
+ " <k>val8</k>\n"
+ " <l1>8</l1>\n"
+ "</lt>", LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
+ CHECK_LOG_CTX_APPTAG("Unique data leaf(s) \"l1\" not satisfied in \"/d:lt[k='val7']\" and \"/d:lt[k='val2']\".",
+ "Data location \"/d:lt[k='val2']\".", "data-not-unique");
+}
+
+static void
+test_unique_nested(void **state)
+{
+ struct lyd_node *tree;
+
+ UTEST_ADD_MODULE(schema_d, LYS_IN_YANG, NULL, NULL);
+
+ /* nested list uniquest are compared only with instances in the same parent list instance */
+ LYD_TREE_CREATE("<lt2 xmlns=\"urn:tests:d\">\n"
+ " <k>val1</k>\n"
+ " <cont>\n"
+ " <l2>1</l2>\n"
+ " </cont>\n"
+ " <l4>1</l4>\n"
+ "</lt2>\n"
+ "<lt2 xmlns=\"urn:tests:d\">\n"
+ " <k>val2</k>\n"
+ " <cont>\n"
+ " <l2>2</l2>\n"
+ " </cont>\n"
+ " <l4>2</l4>\n"
+ " <lt3>\n"
+ " <kk>val1</kk>\n"
+ " <l3>1</l3>\n"
+ " </lt3>\n"
+ " <lt3>\n"
+ " <kk>val2</kk>\n"
+ " <l3>2</l3>\n"
+ " </lt3>\n"
+ "</lt2>\n"
+ "<lt2 xmlns=\"urn:tests:d\">\n"
+ " <k>val3</k>\n"
+ " <cont>\n"
+ " <l2>3</l2>\n"
+ " </cont>\n"
+ " <l4>3</l4>\n"
+ " <lt3>\n"
+ " <kk>val1</kk>\n"
+ " <l3>2</l3>\n"
+ " </lt3>\n"
+ "</lt2>\n"
+ "<lt2 xmlns=\"urn:tests:d\">\n"
+ " <k>val4</k>\n"
+ " <cont>\n"
+ " <l2>4</l2>\n"
+ " </cont>\n"
+ " <l4>4</l4>\n"
+ " <lt3>\n"
+ " <kk>val1</kk>\n"
+ " <l3>3</l3>\n"
+ " </lt3>\n"
+ "</lt2>\n"
+ "<lt2 xmlns=\"urn:tests:d\">\n"
+ " <k>val5</k>\n"
+ " <cont>\n"
+ " <l2>5</l2>\n"
+ " </cont>\n"
+ " <l4>5</l4>\n"
+ " <lt3>\n"
+ " <kk>val1</kk>\n"
+ " <l3>3</l3>\n"
+ " </lt3>\n"
+ "</lt2>", tree);
+ lyd_free_all(tree);
+
+ CHECK_PARSE_LYD_PARAM("<lt2 xmlns=\"urn:tests:d\">\n"
+ " <k>val1</k>\n"
+ " <cont>\n"
+ " <l2>1</l2>\n"
+ " </cont>\n"
+ " <l4>1</l4>\n"
+ "</lt2>\n"
+ "<lt2 xmlns=\"urn:tests:d\">\n"
+ " <k>val2</k>\n"
+ " <cont>\n"
+ " <l2>2</l2>\n"
+ " </cont>\n"
+ " <lt3>\n"
+ " <kk>val1</kk>\n"
+ " <l3>1</l3>\n"
+ " </lt3>\n"
+ " <lt3>\n"
+ " <kk>val2</kk>\n"
+ " <l3>2</l3>\n"
+ " </lt3>\n"
+ " <lt3>\n"
+ " <kk>val3</kk>\n"
+ " <l3>1</l3>\n"
+ " </lt3>\n"
+ "</lt2>\n"
+ "<lt2 xmlns=\"urn:tests:d\">\n"
+ " <k>val3</k>\n"
+ " <cont>\n"
+ " <l2>3</l2>\n"
+ " </cont>\n"
+ " <l4>1</l4>\n"
+ " <lt3>\n"
+ " <kk>val1</kk>\n"
+ " <l3>2</l3>\n"
+ " </lt3>\n"
+ "</lt2>\n"
+ "<lt2 xmlns=\"urn:tests:d\">\n"
+ " <k>val4</k>\n"
+ " <cont>\n"
+ " <l2>4</l2>\n"
+ " </cont>\n"
+ " <lt3>\n"
+ " <kk>val1</kk>\n"
+ " <l3>3</l3>\n"
+ " </lt3>\n"
+ "</lt2>\n"
+ "<lt2 xmlns=\"urn:tests:d\">\n"
+ " <k>val5</k>\n"
+ " <cont>\n"
+ " <l2>5</l2>\n"
+ " </cont>\n"
+ " <lt3>\n"
+ " <kk>val1</kk>\n"
+ " <l3>3</l3>\n"
+ " </lt3>\n"
+ "</lt2>", LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
+ CHECK_LOG_CTX_APPTAG("Unique data leaf(s) \"l3\" not satisfied in \"/d:lt2[k='val2']/lt3[kk='val3']\" and "
+ "\"/d:lt2[k='val2']/lt3[kk='val1']\".",
+ "Data location \"/d:lt2[k='val2']/lt3[kk='val1']\".", "data-not-unique");
+
+ CHECK_PARSE_LYD_PARAM("<lt2 xmlns=\"urn:tests:d\">\n"
+ " <k>val1</k>\n"
+ " <cont>\n"
+ " <l2>1</l2>\n"
+ " </cont>\n"
+ " <l4>1</l4>\n"
+ "</lt2>\n"
+ "<lt2 xmlns=\"urn:tests:d\">\n"
+ " <k>val2</k>\n"
+ " <cont>\n"
+ " <l2>2</l2>\n"
+ " </cont>\n"
+ " <l4>2</l4>\n"
+ "</lt2>\n"
+ "<lt2 xmlns=\"urn:tests:d\">\n"
+ " <k>val3</k>\n"
+ " <cont>\n"
+ " <l2>3</l2>\n"
+ " </cont>\n"
+ " <l4>3</l4>\n"
+ "</lt2>\n"
+ "<lt2 xmlns=\"urn:tests:d\">\n"
+ " <k>val4</k>\n"
+ " <cont>\n"
+ " <l2>2</l2>\n"
+ " </cont>\n"
+ " <l4>2</l4>\n"
+ "</lt2>\n"
+ "<lt2 xmlns=\"urn:tests:d\">\n"
+ " <k>val5</k>\n"
+ " <cont>\n"
+ " <l2>5</l2>\n"
+ " </cont>\n"
+ " <l4>5</l4>\n"
+ "</lt2>", LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
+ CHECK_LOG_CTX_APPTAG("Unique data leaf(s) \"cont/l2 l4\" not satisfied in \"/d:lt2[k='val4']\" and \"/d:lt2[k='val2']\".",
+ "Data location \"/d:lt2[k='val2']\".", "data-not-unique");
+
+ CHECK_PARSE_LYD_PARAM("<lt2 xmlns=\"urn:tests:d\">\n"
+ " <k>val1</k>\n"
+ " <cont>\n"
+ " <l2>1</l2>\n"
+ " </cont>\n"
+ " <l4>1</l4>\n"
+ " <l5>1</l5>\n"
+ " <l6>1</l6>\n"
+ "</lt2>\n"
+ "<lt2 xmlns=\"urn:tests:d\">\n"
+ " <k>val2</k>\n"
+ " <cont>\n"
+ " <l2>2</l2>\n"
+ " </cont>\n"
+ " <l4>1</l4>\n"
+ " <l5>1</l5>\n"
+ "</lt2>\n"
+ "<lt2 xmlns=\"urn:tests:d\">\n"
+ " <k>val3</k>\n"
+ " <cont>\n"
+ " <l2>3</l2>\n"
+ " </cont>\n"
+ " <l4>1</l4>\n"
+ " <l5>3</l5>\n"
+ " <l6>3</l6>\n"
+ "</lt2>\n"
+ "<lt2 xmlns=\"urn:tests:d\">\n"
+ " <k>val4</k>\n"
+ " <cont>\n"
+ " <l2>4</l2>\n"
+ " </cont>\n"
+ " <l4>1</l4>\n"
+ " <l6>1</l6>\n"
+ "</lt2>\n"
+ "<lt2 xmlns=\"urn:tests:d\">\n"
+ " <k>val5</k>\n"
+ " <cont>\n"
+ " <l2>5</l2>\n"
+ " </cont>\n"
+ " <l4>1</l4>\n"
+ " <l5>3</l5>\n"
+ " <l6>3</l6>\n"
+ "</lt2>", LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
+ CHECK_LOG_CTX_APPTAG("Unique data leaf(s) \"l5 l6\" not satisfied in \"/d:lt2[k='val5']\" and \"/d:lt2[k='val3']\".",
+ "Data location \"/d:lt2[k='val3']\".", "data-not-unique");
+}
+
+static void
+test_dup(void **state)
+{
+ struct lyd_node *tree;
+ const char *schema =
+ "module e {\n"
+ " namespace urn:tests:e;\n"
+ " prefix e;\n"
+ " yang-version 1.1;\n"
+ "\n"
+ " choice choic {\n"
+ " leaf a {\n"
+ " type string;\n"
+ " }\n"
+ " case b {\n"
+ " leaf-list l {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " list lt {\n"
+ " key \"k\";\n"
+ " leaf k {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ " leaf d {\n"
+ " type uint32;\n"
+ " }\n"
+ " leaf-list ll {\n"
+ " type string;\n"
+ " }\n"
+ " container cont {\n"
+ " list lt {\n"
+ " key \"k\";\n"
+ " leaf k {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ " leaf d {\n"
+ " type uint32;\n"
+ " }\n"
+ " leaf-list ll {\n"
+ " type string;\n"
+ " }\n"
+ " leaf-list ll2 {\n"
+ " type enumeration {\n"
+ " enum one;\n"
+ " enum two;\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ "}";
+
+ UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
+
+ CHECK_PARSE_LYD_PARAM("<d xmlns=\"urn:tests:e\">25</d><d xmlns=\"urn:tests:e\">50</d>",
+ LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
+ CHECK_LOG_CTX("Duplicate instance of \"d\".", "Data location \"/e:d\".");
+
+ CHECK_PARSE_LYD_PARAM("<lt xmlns=\"urn:tests:e\"><k>A</k></lt>"
+ "<lt xmlns=\"urn:tests:e\"><k>B</k></lt>"
+ "<lt xmlns=\"urn:tests:e\"><k>A</k></lt>",
+ LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
+ CHECK_LOG_CTX("Duplicate instance of \"lt\".", "Data location \"/e:lt[k='A']\".");
+
+ CHECK_PARSE_LYD_PARAM("<ll xmlns=\"urn:tests:e\">A</ll>"
+ "<ll xmlns=\"urn:tests:e\">B</ll>"
+ "<ll xmlns=\"urn:tests:e\">B</ll>",
+ LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
+ CHECK_LOG_CTX("Duplicate instance of \"ll\".", "Data location \"/e:ll[.='B']\".");
+
+ CHECK_PARSE_LYD_PARAM("<cont xmlns=\"urn:tests:e\"></cont><cont xmlns=\"urn:tests:e\"/>",
+ LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
+ CHECK_LOG_CTX("Duplicate instance of \"cont\".", "Data location \"/e:cont\".");
+
+ /* same tests again but using hashes */
+ CHECK_PARSE_LYD_PARAM("<cont xmlns=\"urn:tests:e\"><d>25</d><d>50</d><ll>1</ll><ll>2</ll><ll>3</ll><ll>4</ll></cont>",
+ LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
+ CHECK_LOG_CTX("Duplicate instance of \"d\".", "Data location \"/e:cont/d\", line number 1.");
+
+ CHECK_PARSE_LYD_PARAM("<cont xmlns=\"urn:tests:e\"><ll>1</ll><ll>2</ll><ll>3</ll><ll>4</ll>"
+ "<lt><k>a</k></lt>"
+ "<lt><k>b</k></lt>"
+ "<lt><k>c</k></lt>"
+ "<lt><k>d</k></lt>"
+ "<lt><k>c</k></lt></cont>",
+ LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
+ CHECK_LOG_CTX("Duplicate instance of \"lt\".", "Data location \"/e:cont/lt[k='c']\", line number 1.");
+
+ CHECK_PARSE_LYD_PARAM("<cont xmlns=\"urn:tests:e\"><ll>1</ll><ll>2</ll><ll>3</ll><ll>4</ll>"
+ "<ll>a</ll><ll>b</ll><ll>c</ll><ll>d</ll><ll>d</ll></cont>",
+ LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
+ CHECK_LOG_CTX("Duplicate instance of \"ll\".", "Data location \"/e:cont/ll[.='d']\", line number 1.");
+
+ /* cases */
+ CHECK_PARSE_LYD_PARAM("<l xmlns=\"urn:tests:e\">a</l>"
+ "<l xmlns=\"urn:tests:e\">b</l>"
+ "<l xmlns=\"urn:tests:e\">c</l>"
+ "<l xmlns=\"urn:tests:e\">b</l>",
+ LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
+ CHECK_LOG_CTX("Duplicate instance of \"l\".", "Data location \"/e:l[.='b']\".");
+
+ CHECK_PARSE_LYD_PARAM("<l xmlns=\"urn:tests:e\">a</l><l xmlns=\"urn:tests:e\">b</l>"
+ "<l xmlns=\"urn:tests:e\">c</l>"
+ "<a xmlns=\"urn:tests:e\">aa</a>",
+ LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
+ CHECK_LOG_CTX("Data for both cases \"a\" and \"b\" exist.", "Schema location \"/e:choic\".");
+}
+
+static void
+test_defaults(void **state)
+{
+ struct lyd_node *tree, *node, *diff;
+ struct lys_module *mod;
+ const char *schema =
+ "module f {\n"
+ " namespace urn:tests:f;\n"
+ " prefix f;\n"
+ " yang-version 1.1;\n"
+ "\n"
+ " choice choic {\n"
+ " default \"c\";\n"
+ " leaf a {\n"
+ " type string;\n"
+ " }\n"
+ " case b {\n"
+ " leaf l {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ " case c {\n"
+ " leaf-list ll1 {\n"
+ " type string;\n"
+ " default \"def1\";\n"
+ " default \"def2\";\n"
+ " default \"def3\";\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " leaf d {\n"
+ " type uint32;\n"
+ " default 15;\n"
+ " }\n"
+ " leaf dd {\n"
+ " type uint32;\n"
+ " when '../d = 666';\n"
+ " default 15;\n"
+ " }\n"
+ " leaf-list ll2 {\n"
+ " type string;\n"
+ " default \"dflt1\";\n"
+ " default \"dflt2\";\n"
+ " }\n"
+ " container cont {\n"
+ " choice choic {\n"
+ " default \"c\";\n"
+ " leaf a {\n"
+ " type string;\n"
+ " }\n"
+ " case b {\n"
+ " leaf l {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ " case c {\n"
+ " leaf-list ll1 {\n"
+ " type string;\n"
+ " default \"def1\";\n"
+ " default \"def2\";\n"
+ " default \"def3\";\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " leaf d {\n"
+ " type uint32;\n"
+ " default 15;\n"
+ " }\n"
+ " leaf dd {\n"
+ " type uint32;\n"
+ " when '../d = 666';\n"
+ " default 15;\n"
+ " }\n"
+ " leaf-list ll2 {\n"
+ " type string;\n"
+ " default \"dflt1\";\n"
+ " default \"dflt2\";\n"
+ " }\n"
+ " }\n"
+ "}";
+
+ UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
+
+ assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_DIR_MODULES_YANG));
+ assert_non_null(ly_ctx_load_module(UTEST_LYCTX, "ietf-netconf-with-defaults", "2011-06-01", NULL));\
+
+ /* get defaults */
+ tree = NULL;
+ assert_int_equal(lyd_validate_module(&tree, mod, 0, &diff), LY_SUCCESS);
+ assert_non_null(tree);
+ assert_non_null(diff);
+
+ /* check all defaults exist */
+ CHECK_LYD_STRING_PARAM(tree,
+ "<ll1 xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def1</ll1>\n"
+ "<ll1 xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def2</ll1>\n"
+ "<ll1 xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def3</ll1>\n"
+ "<d xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">15</d>\n"
+ "<ll2 xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">dflt1</ll2>\n"
+ "<ll2 xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">dflt2</ll2>\n"
+ "<cont xmlns=\"urn:tests:f\">\n"
+ " <ll1 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def1</ll1>\n"
+ " <ll1 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def2</ll1>\n"
+ " <ll1 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def3</ll1>\n"
+ " <d xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">15</d>\n"
+ " <ll2 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">dflt1</ll2>\n"
+ " <ll2 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">dflt2</ll2>\n"
+ "</cont>\n",
+ LYD_XML, LYD_PRINT_WD_IMPL_TAG | LYD_PRINT_WITHSIBLINGS);
+
+ /* check diff */
+ CHECK_LYD_STRING_PARAM(diff,
+ "<ll1 xmlns=\"urn:tests:f\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"create\">def1</ll1>\n"
+ "<ll1 xmlns=\"urn:tests:f\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"create\">def2</ll1>\n"
+ "<ll1 xmlns=\"urn:tests:f\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"create\">def3</ll1>\n"
+ "<d xmlns=\"urn:tests:f\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"create\">15</d>\n"
+ "<ll2 xmlns=\"urn:tests:f\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"create\">dflt1</ll2>\n"
+ "<ll2 xmlns=\"urn:tests:f\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"create\">dflt2</ll2>\n"
+ "<cont xmlns=\"urn:tests:f\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"create\">\n"
+ " <ll1 yang:operation=\"create\">def1</ll1>\n"
+ " <ll1 yang:operation=\"create\">def2</ll1>\n"
+ " <ll1 yang:operation=\"create\">def3</ll1>\n"
+ " <d yang:operation=\"create\">15</d>\n"
+ " <ll2 yang:operation=\"create\">dflt1</ll2>\n"
+ " <ll2 yang:operation=\"create\">dflt2</ll2>\n"
+ "</cont>\n",
+ LYD_XML, LYD_PRINT_WD_ALL | LYD_PRINT_WITHSIBLINGS);
+ lyd_free_all(diff);
+
+ /* create another explicit case and validate */
+ assert_int_equal(lyd_new_term(NULL, mod, "l", "value", 0, &node), LY_SUCCESS);
+ assert_int_equal(lyd_insert_sibling(tree, node, &tree), LY_SUCCESS);
+ assert_int_equal(lyd_validate_all(&tree, UTEST_LYCTX, LYD_VALIDATE_PRESENT, &diff), LY_SUCCESS);
+
+ /* check data tree */
+ CHECK_LYD_STRING_PARAM(tree,
+ "<l xmlns=\"urn:tests:f\">value</l>\n"
+ "<d xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">15</d>\n"
+ "<ll2 xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">dflt1</ll2>\n"
+ "<ll2 xmlns=\"urn:tests:f\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">dflt2</ll2>\n"
+ "<cont xmlns=\"urn:tests:f\">\n"
+ " <ll1 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def1</ll1>\n"
+ " <ll1 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def2</ll1>\n"
+ " <ll1 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def3</ll1>\n"
+ " <d xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">15</d>\n"
+ " <ll2 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">dflt1</ll2>\n"
+ " <ll2 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">dflt2</ll2>\n"
+ "</cont>\n",
+ LYD_XML, LYD_PRINT_WD_IMPL_TAG | LYD_PRINT_WITHSIBLINGS);
+
+ /* check diff */
+ CHECK_LYD_STRING_PARAM(diff,
+ "<ll1 xmlns=\"urn:tests:f\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"delete\">def1</ll1>\n"
+ "<ll1 xmlns=\"urn:tests:f\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"delete\">def2</ll1>\n"
+ "<ll1 xmlns=\"urn:tests:f\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"delete\">def3</ll1>\n",
+ LYD_XML, LYD_PRINT_WD_ALL | LYD_PRINT_WITHSIBLINGS);
+ lyd_free_all(diff);
+
+ /* create explicit leaf-list and leaf and validate */
+ assert_int_equal(lyd_new_term(NULL, mod, "d", "15", 0, &node), LY_SUCCESS);
+ assert_int_equal(lyd_insert_sibling(tree, node, &tree), LY_SUCCESS);
+ assert_int_equal(lyd_new_term(NULL, mod, "ll2", "dflt2", 0, &node), LY_SUCCESS);
+ assert_int_equal(lyd_insert_sibling(tree, node, &tree), LY_SUCCESS);
+ assert_int_equal(lyd_validate_all(&tree, UTEST_LYCTX, LYD_VALIDATE_PRESENT, &diff), LY_SUCCESS);
+
+ /* check data tree */
+ CHECK_LYD_STRING_PARAM(tree,
+ "<l xmlns=\"urn:tests:f\">value</l>\n"
+ "<d xmlns=\"urn:tests:f\">15</d>\n"
+ "<ll2 xmlns=\"urn:tests:f\">dflt2</ll2>\n"
+ "<cont xmlns=\"urn:tests:f\">\n"
+ " <ll1 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def1</ll1>\n"
+ " <ll1 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def2</ll1>\n"
+ " <ll1 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def3</ll1>\n"
+ " <d xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">15</d>\n"
+ " <ll2 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">dflt1</ll2>\n"
+ " <ll2 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">dflt2</ll2>\n"
+ "</cont>\n",
+ LYD_XML, LYD_PRINT_WD_IMPL_TAG | LYD_PRINT_WITHSIBLINGS);
+
+ /* check diff */
+ CHECK_LYD_STRING_PARAM(diff,
+ "<d xmlns=\"urn:tests:f\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"delete\">15</d>\n"
+ "<ll2 xmlns=\"urn:tests:f\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"delete\">dflt1</ll2>\n"
+ "<ll2 xmlns=\"urn:tests:f\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"delete\">dflt2</ll2>\n",
+ LYD_XML, LYD_PRINT_WD_ALL | LYD_PRINT_WITHSIBLINGS);
+ lyd_free_all(diff);
+
+ /* create first explicit container, which should become implicit */
+ assert_int_equal(lyd_new_inner(NULL, mod, "cont", 0, &node), LY_SUCCESS);
+ assert_int_equal(lyd_insert_sibling(tree, node, &tree), LY_SUCCESS);
+ assert_int_equal(lyd_validate_all(&tree, UTEST_LYCTX, LYD_VALIDATE_PRESENT, &diff), LY_SUCCESS);
+
+ /* check data tree */
+ CHECK_LYD_STRING_PARAM(tree,
+ "<l xmlns=\"urn:tests:f\">value</l>\n"
+ "<d xmlns=\"urn:tests:f\">15</d>\n"
+ "<ll2 xmlns=\"urn:tests:f\">dflt2</ll2>\n"
+ "<cont xmlns=\"urn:tests:f\">\n"
+ " <ll1 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def1</ll1>\n"
+ " <ll1 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def2</ll1>\n"
+ " <ll1 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def3</ll1>\n"
+ " <d xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">15</d>\n"
+ " <ll2 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">dflt1</ll2>\n"
+ " <ll2 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">dflt2</ll2>\n"
+ "</cont>\n",
+ LYD_XML, LYD_PRINT_WD_IMPL_TAG | LYD_PRINT_WITHSIBLINGS);
+ /* check diff */
+ assert_null(diff);
+
+ /* create second explicit container, which should become implicit, so the first tree node should be removed */
+ assert_int_equal(lyd_new_inner(NULL, mod, "cont", 0, &node), LY_SUCCESS);
+ assert_int_equal(lyd_insert_sibling(tree, node, &tree), LY_SUCCESS);
+ assert_int_equal(lyd_validate_all(&tree, UTEST_LYCTX, LYD_VALIDATE_PRESENT, &diff), LY_SUCCESS);
+
+ /* check data tree */
+ CHECK_LYD_STRING_PARAM(tree,
+ "<l xmlns=\"urn:tests:f\">value</l>\n"
+ "<d xmlns=\"urn:tests:f\">15</d>\n"
+ "<ll2 xmlns=\"urn:tests:f\">dflt2</ll2>\n"
+ "<cont xmlns=\"urn:tests:f\">\n"
+ " <ll1 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def1</ll1>\n"
+ " <ll1 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def2</ll1>\n"
+ " <ll1 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">def3</ll1>\n"
+ " <d xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">15</d>\n"
+ " <ll2 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">dflt1</ll2>\n"
+ " <ll2 xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\" ncwd:default=\"true\">dflt2</ll2>\n"
+ "</cont>\n",
+ LYD_XML, LYD_PRINT_WD_IMPL_TAG | LYD_PRINT_WITHSIBLINGS);
+ /* check diff */
+ assert_null(diff);
+
+ /* similar changes for nested defaults */
+ assert_int_equal(lyd_new_term(tree->prev, NULL, "ll1", "def3", 0, NULL), LY_SUCCESS);
+ assert_int_equal(lyd_new_term(tree->prev, NULL, "d", "5", 0, NULL), LY_SUCCESS);
+ assert_int_equal(lyd_new_term(tree->prev, NULL, "ll2", "non-dflt", 0, NULL), LY_SUCCESS);
+ assert_int_equal(lyd_validate_all(&tree, UTEST_LYCTX, LYD_VALIDATE_PRESENT, &diff), LY_SUCCESS);
+
+ /* check data tree */
+ CHECK_LYD_STRING_PARAM(tree,
+ "<l xmlns=\"urn:tests:f\">value</l>\n"
+ "<d xmlns=\"urn:tests:f\">15</d>\n"
+ "<ll2 xmlns=\"urn:tests:f\">dflt2</ll2>\n"
+ "<cont xmlns=\"urn:tests:f\">\n"
+ " <ll1>def3</ll1>\n"
+ " <d>5</d>\n"
+ " <ll2>non-dflt</ll2>\n"
+ "</cont>\n",
+ LYD_XML, LYD_PRINT_WITHSIBLINGS);
+
+ /* check diff */
+ CHECK_LYD_STRING_PARAM(diff,
+ "<cont xmlns=\"urn:tests:f\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">\n"
+ " <ll1 yang:operation=\"delete\">def1</ll1>\n"
+ " <ll1 yang:operation=\"delete\">def2</ll1>\n"
+ " <ll1 yang:operation=\"delete\">def3</ll1>\n"
+ " <d yang:operation=\"delete\">15</d>\n"
+ " <ll2 yang:operation=\"delete\">dflt1</ll2>\n"
+ " <ll2 yang:operation=\"delete\">dflt2</ll2>\n"
+ "</cont>\n",
+ LYD_XML, LYD_PRINT_WD_ALL | LYD_PRINT_WITHSIBLINGS);
+ lyd_free_all(diff);
+ lyd_free_all(tree);
+
+ /* check data tree - when enabled node */
+ CHECK_PARSE_LYD_PARAM("<d xmlns=\"urn:tests:f\">666</d><cont xmlns=\"urn:tests:f\"><d>666</d></cont>",
+ LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
+ CHECK_LYD_STRING_PARAM(tree,
+ "<ll1 xmlns=\"urn:tests:f\">def1</ll1>\n"
+ "<ll1 xmlns=\"urn:tests:f\">def2</ll1>\n"
+ "<ll1 xmlns=\"urn:tests:f\">def3</ll1>\n"
+ "<d xmlns=\"urn:tests:f\">666</d>\n"
+ "<dd xmlns=\"urn:tests:f\">15</dd>\n"
+ "<ll2 xmlns=\"urn:tests:f\">dflt1</ll2>\n"
+ "<ll2 xmlns=\"urn:tests:f\">dflt2</ll2>\n"
+ "<cont xmlns=\"urn:tests:f\">\n"
+ " <ll1>def1</ll1>\n"
+ " <ll1>def2</ll1>\n"
+ " <ll1>def3</ll1>\n"
+ " <d>666</d>\n"
+ " <dd>15</dd>\n"
+ " <ll2>dflt1</ll2>\n"
+ " <ll2>dflt2</ll2>\n"
+ "</cont>\n",
+ LYD_XML, LYD_PRINT_WD_ALL | LYD_PRINT_WITHSIBLINGS);
+ lyd_free_all(tree);
+}
+
+static void
+test_state(void **state)
+{
+ const char *data;
+ struct lyd_node *tree;
+ const char *schema =
+ "module h {\n"
+ " namespace urn:tests:h;\n"
+ " prefix h;\n"
+ " yang-version 1.1;\n"
+ "\n"
+ " container cont {\n"
+ " container cont2 {\n"
+ " config false;\n"
+ " leaf l {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ "}";
+
+ UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
+
+ data = "<cont xmlns=\"urn:tests:h\">\n"
+ " <cont2>\n"
+ " <l>val</l>\n"
+ " </cont2>\n"
+ "</cont>\n";
+ CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_NO_STATE, 0, LY_EVALID, tree);
+ CHECK_LOG_CTX("Unexpected data state node \"cont2\" found.",
+ "Data location \"/h:cont/cont2\", line number 3.");
+
+ CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_ONLY, 0, LY_SUCCESS, tree);
+ assert_int_equal(LY_EVALID, lyd_validate_all(&tree, NULL, LYD_VALIDATE_PRESENT | LYD_VALIDATE_NO_STATE, NULL));
+ CHECK_LOG_CTX("Unexpected data state node \"cont2\" found.",
+ "Data location \"/h:cont/cont2\".");
+ lyd_free_all(tree);
+}
+
+static void
+test_must(void **state)
+{
+ struct lyd_node *tree;
+ const char *schema =
+ "module i {\n"
+ " namespace urn:tests:i;\n"
+ " prefix i;\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"
+ " }\n"
+ "}";
+
+ UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
+
+ CHECK_PARSE_LYD_PARAM("<cont xmlns=\"urn:tests:i\">\n"
+ " <l>wrong</l>\n"
+ " <l2>val</l2>\n"
+ "</cont>\n", LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
+ CHECK_LOG_CTX_APPTAG("Must condition \"../l = 'right'\" not satisfied.",
+ "Data location \"/i:cont/l2\".", "must-violation");
+
+ LYD_TREE_CREATE("<cont xmlns=\"urn:tests:i\">\n"
+ " <l>right</l>\n"
+ " <l2>val</l2>\n"
+ "</cont>\n", tree);
+ lyd_free_all(tree);
+
+ CHECK_PARSE_LYD_PARAM("<cont xmlns=\"urn:tests:i\">\n"
+ " <l>wrong</l>\n"
+ " <l3>val</l3>\n"
+ "</cont>\n", LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
+ CHECK_LOG_CTX_APPTAG("l leaf is not left", "Data location \"/i:cont/l3\".", "not-left");
+}
+
+const char *schema_j =
+ "module j {\n"
+ " namespace urn:tests:j;\n"
+ " prefix j;\n"
+ " yang-version 1.1;\n"
+ "\n"
+ " feature feat1;\n"
+ "\n"
+ " container cont {\n"
+ " must \"false()\";\n"
+ " list l1 {\n"
+ " key \"k\";\n"
+ " leaf k {\n"
+ " type string;\n"
+ " }\n"
+ " action act {\n"
+ " if-feature feat1;\n"
+ " input {\n"
+ " must \"../../lf1 = 'true'\";\n"
+ " leaf lf2 {\n"
+ " type leafref {\n"
+ " path /lf3;\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " output {\n"
+ " must \"../../lf1 = 'true2'\";\n"
+ " leaf lf2 {\n"
+ " type leafref {\n"
+ " path /lf4;\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ "\n"
+ " leaf lf1 {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ "\n"
+ " leaf lf3 {\n"
+ " type string;\n"
+ " }\n"
+ "\n"
+ " leaf lf4 {\n"
+ " type string;\n"
+ " }\n"
+ "}";
+const char *feats_j[] = {"feat1", NULL};
+
+static void
+test_action(void **state)
+{
+ struct ly_in *in;
+ struct lyd_node *tree, *op_tree;
+
+ UTEST_ADD_MODULE(schema_j, LYS_IN_YANG, feats_j, NULL);
+
+ assert_int_equal(LY_SUCCESS, ly_in_new_memory(
+ "<cont xmlns=\"urn:tests:j\">\n"
+ " <l1>\n"
+ " <k>val1</k>\n"
+ " <act>\n"
+ " <lf2>target</lf2>\n"
+ " </act>\n"
+ " </l1>\n"
+ "</cont>\n", &in));
+ assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_XML, LYD_TYPE_RPC_YANG, &op_tree, NULL));
+ assert_non_null(op_tree);
+
+ /* missing leafref */
+ assert_int_equal(LY_EVALID, lyd_validate_op(op_tree, NULL, LYD_TYPE_RPC_YANG, NULL));
+ CHECK_LOG_CTX("Invalid leafref value \"target\" - no target instance \"/lf3\" with the same value.",
+ "Data location \"/j:cont/l1[k='val1']/act/lf2\".");
+ ly_in_free(in, 0);
+
+ CHECK_PARSE_LYD_PARAM("<cont xmlns=\"urn:tests:j\">\n"
+ " <lf1>not true</lf1>\n"
+ "</cont>\n"
+ "<lf3 xmlns=\"urn:tests:j\">target</lf3>\n",
+ LYD_XML, LYD_PARSE_ONLY, 0, LY_SUCCESS, tree);
+
+ /* input must false */
+ assert_int_equal(LY_EVALID, lyd_validate_op(op_tree, tree, LYD_TYPE_RPC_YANG, NULL));
+ CHECK_LOG_CTX("Must condition \"../../lf1 = 'true'\" not satisfied.",
+ "Data location \"/j:cont/l1[k='val1']/act\".");
+
+ lyd_free_all(tree);
+ CHECK_PARSE_LYD_PARAM("<cont xmlns=\"urn:tests:j\">\n"
+ " <lf1>true</lf1>\n"
+ "</cont>\n"
+ "<lf3 xmlns=\"urn:tests:j\">target</lf3>\n",
+ LYD_XML, LYD_PARSE_ONLY, 0, LY_SUCCESS, tree);
+
+ /* success */
+ assert_int_equal(LY_SUCCESS, lyd_validate_op(op_tree, tree, LYD_TYPE_RPC_YANG, NULL));
+
+ lyd_free_tree(op_tree);
+ lyd_free_siblings(tree);
+}
+
+static void
+test_rpc(void **state)
+{
+ const char *schema, *data;
+ struct ly_in *in;
+ struct lyd_node *tree;
+
+ /* Testing constraint violation in RPC. */
+ schema =
+ "module val-str {\n"
+ " namespace \"urn:vstr\";\n"
+ " prefix v;\n"
+ "\n"
+ " rpc modify-user-password {\n"
+ " input {\n"
+ " leaf old-password {\n"
+ " type string {\n"
+ " length \"4..8\";\n"
+ " }\n"
+ " }\n"
+ " leaf new-password {\n"
+ " type string {\n"
+ " length \"4..8\";\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ "}\n";
+ UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
+ data =
+ "<modify-user-password xmlns=\"urn:vstr\">\n"
+ " <old-password>12345</old-password>\n"
+ " <new-password>123</new-password>\n"
+ "</modify-user-password>";
+ 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_YANG, &tree, NULL));
+ CHECK_LOG_CTX("Unsatisfied length - string \"123\" length is not allowed.",
+ "Data location \"/val-str:modify-user-password/new-password\", line number 3.");
+ ly_in_free(in, 0);
+}
+
+static void
+test_reply(void **state)
+{
+ struct ly_in *in;
+ struct lyd_node *tree, *op_tree;
+
+ UTEST_ADD_MODULE(schema_j, LYS_IN_YANG, feats_j, NULL);
+
+ assert_int_equal(LY_SUCCESS, ly_in_new_memory(
+ "<cont xmlns=\"urn:tests:j\">\n"
+ " <l1>\n"
+ " <k>val1</k>\n"
+ " <act>\n"
+ " <lf2>target</lf2>\n"
+ " </act>\n"
+ " </l1>\n"
+ "</cont>\n", &in));
+ assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_XML, LYD_TYPE_REPLY_YANG, &op_tree, NULL));
+ assert_non_null(op_tree);
+ ly_in_free(in, 0);
+
+ /* missing leafref */
+ assert_int_equal(LY_EVALID, lyd_validate_op(op_tree, NULL, LYD_TYPE_REPLY_YANG, NULL));
+ CHECK_LOG_CTX("Invalid leafref value \"target\" - no target instance \"/lf4\" with the same value.",
+ "Data location \"/j:cont/l1[k='val1']/act/lf2\".");
+
+ CHECK_PARSE_LYD_PARAM("<cont xmlns=\"urn:tests:j\">\n"
+ " <lf1>not true</lf1>\n"
+ "</cont>\n"
+ "<lf4 xmlns=\"urn:tests:j\">target</lf4>\n",
+ LYD_XML, LYD_PARSE_ONLY, 0, LY_SUCCESS, tree);
+
+ /* input must false */
+ assert_int_equal(LY_EVALID, lyd_validate_op(op_tree, tree, LYD_TYPE_REPLY_YANG, NULL));
+ CHECK_LOG_CTX("Must condition \"../../lf1 = 'true2'\" not satisfied.", "Data location \"/j:cont/l1[k='val1']/act\".");
+
+ lyd_free_all(tree);
+ CHECK_PARSE_LYD_PARAM("<cont xmlns=\"urn:tests:j\">\n"
+ " <lf1>true2</lf1>\n"
+ "</cont>\n"
+ "<lf4 xmlns=\"urn:tests:j\">target</lf4>\n",
+ LYD_XML, LYD_PARSE_ONLY, 0, LY_SUCCESS, tree);
+
+ /* success */
+ assert_int_equal(LY_SUCCESS, lyd_validate_op(op_tree, tree, LYD_TYPE_REPLY_YANG, NULL));
+
+ lyd_free_tree(op_tree);
+ lyd_free_all(tree);
+}
+
+static void
+test_case(void **state)
+{
+ struct lyd_node *tree;
+ const char *schema =
+ "module k {\n"
+ " namespace urn:tests:k;\n"
+ " prefix k;\n"
+ " yang-version 1.1;\n"
+ "\n"
+ " container ch {\n"
+ " choice a0 {\n"
+ " case v0 {\n"
+ " leaf g0 {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ " case v1 {\n"
+ " choice a1 {\n"
+ " case r0 {\n"
+ " leaf g1 {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ " case r1 {\n"
+ " leaf g2 {\n"
+ " type string;\n"
+ " }\n"
+ " leaf g3 {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ " case r2 {\n"
+ " leaf g4 {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " case v2 {\n"
+ " choice a2 {\n"
+ " case y0 {\n"
+ " leaf g5 {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ " case y1 {\n"
+ " leaf g6 {\n"
+ " type string;\n"
+ " }\n"
+ " leaf g7 {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ " case y2 {\n"
+ " leaf g8 {\n"
+ " type string;\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ "}";
+
+ UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
+
+ CHECK_PARSE_LYD_PARAM(
+ "{\n"
+ " \"k:ch\": {\n"
+ " \"g0\": \"value_g0\",\n"
+ " \"g7\": \"value_g7\"\n"
+ " }\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.");
+
+ CHECK_PARSE_LYD_PARAM(
+ "{\n"
+ " \"k:ch\": {\n"
+ " \"g7\": \"value_g7\",\n"
+ " \"g0\": \"value_g0\"\n"
+ " }\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.");
+}
+
+int
+main(void)
+{
+ const struct CMUnitTest tests[] = {
+ UTEST(test_when),
+ UTEST(test_mandatory),
+ UTEST(test_mandatory_when),
+ UTEST(test_type_incomplete_when),
+ UTEST(test_minmax),
+ UTEST(test_unique),
+ UTEST(test_unique_nested),
+ UTEST(test_dup),
+ UTEST(test_defaults),
+ UTEST(test_state),
+ UTEST(test_must),
+ UTEST(test_action),
+ UTEST(test_rpc),
+ UTEST(test_reply),
+ UTEST(test_case),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}