summaryrefslogtreecommitdiffstats
path: root/tests/utests/data/test_diff.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/utests/data/test_diff.c')
-rw-r--r--tests/utests/data/test_diff.c1221
1 files changed, 1221 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);
+}