data tree FEATURE support for lists with duplicate instances
Changes mainly in diff processing.
Refs #1483
diff --git a/tests/utests/data/test_diff.c b/tests/utests/data/test_diff.c
index 6964764..81850f8 100644
--- a/tests/utests/data/test_diff.c
+++ b/tests/utests/data/test_diff.c
@@ -38,13 +38,13 @@
CHECK_PARSE_LYD(XML_2, model_2);\
CHECK_PARSE_LYD(XML_3, model_3);\
/* diff1 */ \
- struct lyd_node * diff1;\
+ struct lyd_node *diff1;\
CHECK_PARSE_LYD_DIFF(model_1, model_2, diff1); \
CHECK_LYD_STRING(diff1, DIFF_1); \
assert_int_equal(lyd_diff_apply_all(&model_1, diff1), LY_SUCCESS); \
CHECK_LYD(model_1, model_2); \
/* diff2 */ \
- struct lyd_node * diff2;\
+ struct lyd_node *diff2;\
CHECK_PARSE_LYD_DIFF(model_2, model_3, diff2); \
CHECK_LYD_STRING(diff2, DIFF_2); \
assert_int_equal(lyd_diff_apply_all(&model_2, diff2), LY_SUCCESS);\
@@ -108,6 +108,18 @@
" ordered-by user;\n"
" }\n"
"\n"
+ " list ul {\n"
+ " key \"l1\";\n"
+ " ordered-by user;\n"
+ " leaf l1 {\n"
+ " type string;\n"
+ " }\n"
+ "\n"
+ " leaf l2 {\n"
+ " type int32;\n"
+ " }\n"
+ " }\n"
+ "\n"
" leaf-list dllist {\n"
" type uint8;\n"
" default \"1\";\n"
@@ -190,6 +202,21 @@
" }\n"
" }\n"
" }\n"
+ " list kl {\n"
+ " config \"false\";\n"
+ " leaf l1 {\n"
+ " type string;\n"
+ " }\n"
+ "\n"
+ " leaf l2 {\n"
+ " type int32;\n"
+ " }\n"
+ " }\n"
+ "\n"
+ " leaf-list kll {\n"
+ " config \"false\";\n"
+ " type string;\n"
+ " }\n"
" }\n"
"\n"
" container hidden {\n"
@@ -691,6 +718,265 @@
}
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_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;
@@ -787,6 +1073,9 @@
UTEST(test_userord_llist, setup),
UTEST(test_userord_llist2, setup),
UTEST(test_userord_mix, setup),
+ UTEST(test_userord_list, setup),
+ UTEST(test_keyless_list, setup),
+ UTEST(test_state_llist, setup),
UTEST(test_wd, setup),
};
diff --git a/tests/utests/data/test_new.c b/tests/utests/data/test_new.c
index 314bed4..eee02f0 100644
--- a/tests/utests/data/test_new.c
+++ b/tests/utests/data/test_new.c
@@ -40,12 +40,16 @@
" }\n"
" container c {\n"
" leaf-list x {\n"
- " type string;\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"
@@ -54,6 +58,17 @@
" }\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"
@@ -185,8 +200,10 @@
{
LY_ERR ret;
struct lyd_node *root, *node, *parent;
+ const struct lys_module *mod;
+ char *str;
- UTEST_ADD_MODULE(schema_a, LYS_IN_YANG, NULL, NULL);
+ 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, &root, &node);
@@ -236,27 +253,95 @@
lyd_free_tree(root);
- /* try LYD_NEWOPT_UPDATE */
- ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:l2[1]/c/x", "val", 0, 0, &root, &node);
+ /* key-less list */
+ ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:c2/l3/x", "val1", 0, 0, &root, &node);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(root);
assert_string_equal(node->schema->name, "x");
- assert_string_equal("val", LYD_CANON_VALUE(node));
+ assert_string_equal("val1", LYD_CANON_VALUE(node));
- ret = lyd_new_path2(root, NULL, "/a:l2[1]/c/x", "val", 0, 0, NULL, &node);
+ ret = lyd_new_path2(root, NULL, "/a:c2/l3[1]", NULL, 0, 0, NULL, &node);
assert_int_equal(ret, LY_EEXIST);
- ret = lyd_new_path2(root, NULL, "/a:l2[1]/c/x", "val", 0, LYD_NEW_PATH_UPDATE, NULL, &node);
+ ret = lyd_new_path2(root, NULL, "/a:c2/l3[2]/x", "val2", 0, 0, NULL, &node);
assert_int_equal(ret, LY_SUCCESS);
- assert_null(node);
- ret = lyd_new_path2(root, NULL, "/a:l2[1]/c/x", "val2", 0, LYD_NEW_PATH_UPDATE, NULL, &node);
+ ret = lyd_new_path2(root, NULL, "/a:c2/l3/x", "val3", 0, 0, NULL, &node);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(node);
- assert_string_equal(node->schema->name, "x");
- assert_string_equal("val2", LYD_CANON_VALUE(node));
- lyd_free_tree(root);
+ ret = lyd_new_path2(root, NULL, "/a:c2/l3[4]/x", "empty", 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, 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, 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, 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, &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_CANON_VALUE(node));
+
+ ret = lyd_new_path2(root, NULL, "/a:ll2[1]", "", 0, 0, NULL, &node);
+ assert_int_equal(ret, LY_EEXIST);
+
+ ret = lyd_new_path2(root, NULL, "/a:ll2[2]", "val2", 0, 0, NULL, &node);
+ assert_int_equal(ret, LY_SUCCESS);
+
+ ret = lyd_new_path2(root, NULL, "/a:ll2[1]", "val", 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, 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, 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);
}
static void
diff --git a/tests/utests/data/test_tree_data.c b/tests/utests/data/test_tree_data.c
index 5dbdbe9..b3fe51c 100644
--- a/tests/utests/data/test_tree_data.c
+++ b/tests/utests/data/test_tree_data.c
@@ -380,7 +380,7 @@
LY_PATH_TARGET_SINGLE, LY_PREF_JSON, NULL, NULL, &path));
term = lyd_target(path, tree);
- const int unsigned flag = LYS_CONFIG_R | LYS_SET_ENUM | LYS_ORDBY_SYSTEM;
+ 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_CANON_VALUE(term), "b");