diff BUGFIX delete merge lost changes
Fixes sysrepo/sysrepo#2624
diff --git a/src/diff.c b/src/diff.c
index 6680338..cd442fd 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -1438,7 +1438,7 @@
static LY_ERR
lyd_diff_merge_delete(struct lyd_node *diff_match, enum lyd_diff_op cur_op, const struct lyd_node *src_diff)
{
- struct lyd_node *next, *child;
+ struct lyd_node *child;
struct lyd_meta *meta;
const char *meta_name;
@@ -1462,7 +1462,7 @@
} /* else key-less list, for which all the descendants act as keys */
break;
case LYD_DIFF_OP_REPLACE:
- /* similar to none operation but also remove the redundant metadata */
+ /* remove the redundant metadata */
if (lysc_is_userordered(diff_match->schema)) {
if (lysc_is_dup_inst_list(diff_match->schema)) {
meta_name = "position";
@@ -1494,17 +1494,12 @@
}
lyd_diff_del_meta(diff_match, meta_name);
- /* fall through */
+ /* it was being changed, but should be deleted instead -> set DELETE operation */
+ LY_CHECK_RET(lyd_diff_change_op(diff_match, LYD_DIFF_OP_DELETE));
+ break;
case LYD_DIFF_OP_NONE:
/* it was not modified, but should be deleted -> set DELETE operation */
LY_CHECK_RET(lyd_diff_change_op(diff_match, LYD_DIFF_OP_DELETE));
-
- /* all descendants not in the diff will be deleted and redundant in the diff, so remove them */
- LY_LIST_FOR_SAFE(lyd_child_no_keys(diff_match), next, child) {
- if (lyd_find_sibling_first(lyd_child(src_diff), child, NULL) == LY_ENOTFOUND) {
- lyd_free_tree(child);
- }
- }
break;
default:
/* delete operation is not valid */
diff --git a/tests/utests/data/test_diff.c b/tests/utests/data/test_diff.c
index 7fee736..50954d7 100644
--- a/tests/utests/data/test_diff.c
+++ b/tests/utests/data/test_diff.c
@@ -60,7 +60,7 @@
lyd_free_all(diff2);\
}
-const char *schema =
+const char *schema1 =
"module defaults {\n"
" yang-version 1.1;\n"
" namespace \"urn:libyang:tests:defaults\";\n"
@@ -137,8 +137,17 @@
" type int32;\n"
" default \"42\";\n"
" }\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"
@@ -276,8 +285,17 @@
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;
}
@@ -450,6 +468,46 @@
}
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;
@@ -1068,6 +1126,7 @@
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),