tree data UPDATE support for milti-target leafref links (#2161)
* Adding support for multiple leafref target nodes
diff --git a/src/plugins_types.c b/src/plugins_types.c
index 6b2fa39..6fd4228 100644
--- a/src/plugins_types.c
+++ b/src/plugins_types.c
@@ -988,7 +988,7 @@
LIBYANG_API_DEF LY_ERR
lyplg_type_resolve_leafref(const struct lysc_type_leafref *lref, const struct lyd_node *node, struct lyd_value *value,
- const struct lyd_node *tree, struct lyd_node **target, char **errmsg)
+ const struct lyd_node *tree, struct ly_set **targets, char **errmsg)
{
LY_ERR rc = LY_SUCCESS;
struct lyxp_expr *target_path = NULL;
@@ -999,10 +999,10 @@
LY_CHECK_ARG_RET(NULL, lref, node, value, errmsg, LY_EINVAL);
- if (target) {
- *target = NULL;
- }
*errmsg = NULL;
+ if (targets) {
+ *targets = NULL;
+ }
/* get the canonical value */
val_str = lyd_value_get_canonical(LYD_CTX(node), value);
@@ -1070,8 +1070,21 @@
}
goto cleanup;
}
- if (target) {
- *target = set.val.nodes[i].node;
+ if (targets) {
+ LY_CHECK_GOTO(rc = ly_set_new(targets), cleanup);
+ for (i = 0; i < set.used; ++i) {
+ if (set.val.nodes[i].type != LYXP_NODE_ELEM) {
+ continue;
+ }
+ if (((struct lyd_node_term *)set.val.nodes[i].node)->value.realtype != value->realtype) {
+ continue;
+ }
+
+ if (!lref->plugin->compare(&((struct lyd_node_term *)set.val.nodes[i].node)->value, value)) {
+ rc = ly_set_add(*targets, set.val.nodes[i].node, 0, NULL);
+ LY_CHECK_GOTO(rc, cleanup);
+ }
+ }
}
cleanup:
diff --git a/src/plugins_types.h b/src/plugins_types.h
index b4ecd43..e3b9545 100644
--- a/src/plugins_types.h
+++ b/src/plugins_types.h
@@ -21,6 +21,7 @@
#include "config.h"
#include "log.h"
#include "plugins.h"
+#include "set.h"
#include "tree.h"
#include "tree_edit.h"
@@ -1199,12 +1200,12 @@
* @param[in] node Context node.
* @param[in] value Target value.
* @param[in] tree Full data tree to search in.
- * @param[out] target Optional found target.
+ * @param[out] target Pointer to set of target nodes, optional.
* @param[out] errmsg Error message in case of error.
* @return LY_ERR value.
*/
LIBYANG_API_DECL LY_ERR lyplg_type_resolve_leafref(const struct lysc_type_leafref *lref, const struct lyd_node *node,
- struct lyd_value *value, const struct lyd_node *tree, struct lyd_node **target, char **errmsg);
+ struct lyd_value *value, const struct lyd_node *tree, struct ly_set **targets, char **errmsg);
/** @} pluginsTypes */
diff --git a/src/plugins_types/leafref.c b/src/plugins_types/leafref.c
index 8e60f98..f4e24ca 100644
--- a/src/plugins_types/leafref.c
+++ b/src/plugins_types/leafref.c
@@ -70,7 +70,8 @@
LY_ERR ret;
struct lysc_type_leafref *type_lr = (struct lysc_type_leafref *)type;
char *errmsg = NULL, *path;
- struct lyd_node *target = NULL;
+ struct ly_set *targets = NULL;
+ uint32_t i;
*err = NULL;
@@ -79,19 +80,24 @@
return LY_SUCCESS;
}
- /* check leafref target existence */
- if (lyplg_type_resolve_leafref(type_lr, ctx_node, storage, tree, &target, &errmsg)) {
+ ret = lyplg_type_resolve_leafref(type_lr, ctx_node, storage, tree, (ly_ctx_get_options(ctx) & LY_CTX_LEAFREF_LINKING) ? &targets : NULL, &errmsg);
+ if (ret != LY_SUCCESS) {
path = lyd_path(ctx_node, LYD_PATH_STD, NULL, 0);
ret = ly_err_new(err, LY_EVALID, LYVE_DATA, path, strdup("instance-required"), "%s", errmsg);
free(errmsg);
- return ret;
+ goto cleanup;
}
if (ly_ctx_get_options(ctx) & LY_CTX_LEAFREF_LINKING) {
- return lyd_link_leafref_node((struct lyd_node_term *)target, (struct lyd_node_term *)ctx_node);
+ for (i = 0; i < targets->count; ++i) {
+ ret = lyd_link_leafref_node((struct lyd_node_term *)targets->dnodes[i], (struct lyd_node_term *)ctx_node);
+ LY_CHECK_GOTO(ret, cleanup);
+ }
}
- return LY_SUCCESS;
+cleanup:
+ ly_set_free(targets, NULL);
+ return ret;
}
LIBYANG_API_DEF LY_ERR
diff --git a/src/tree_data.c b/src/tree_data.c
index ebe7eaf..8a6de8a 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -3316,9 +3316,9 @@
LY_ERR
lyd_link_leafref_node(const struct lyd_node_term *node, const struct lyd_node_term *leafref_node)
{
- LY_ARRAY_COUNT_TYPE u;
const struct lyd_node_term **item = NULL;
struct lyd_leafref_links_rec *rec;
+ LY_ARRAY_COUNT_TYPE u;
assert(node);
assert(leafref_node);
@@ -3327,6 +3327,7 @@
return LY_EDENIED;
}
+ /* add leafref node into the list of target node */
LY_CHECK_RET(lyd_get_or_create_leafref_links_record(node, &rec, 1));
LY_ARRAY_FOR(rec->leafref_nodes, u) {
if (rec->leafref_nodes[u] == leafref_node) {
@@ -3336,8 +3337,18 @@
LY_ARRAY_NEW_RET(LYD_CTX(node), rec->leafref_nodes, item, LY_EMEM);
*item = leafref_node;
+
+ /* add target node into the list of leafref node*/
LY_CHECK_RET(lyd_get_or_create_leafref_links_record(leafref_node, &rec, 1));
- rec->target_node = node;
+ LY_ARRAY_FOR(rec->target_nodes, u) {
+ if (rec->target_nodes[u] == node) {
+ return LY_SUCCESS;
+ }
+ }
+
+ LY_ARRAY_NEW_RET(LYD_CTX(node), rec->target_nodes, item, LY_EMEM);
+ *item = node;
+
return LY_SUCCESS;
}
@@ -3345,11 +3356,13 @@
lyd_leafref_link_node_tree(const struct lyd_node *tree)
{
const struct lyd_node *sibling, *elem;
- struct lyd_node *target;
+ struct ly_set *targets = NULL;
char *errmsg;
struct lyd_node_term *leafref_node;
struct lysc_node_leaf *leaf_schema;
struct lysc_type_leafref *lref;
+ LY_ERR ret = LY_SUCCESS;
+ uint32_t i;
LY_CHECK_ARG_RET(NULL, tree, LY_EINVAL);
@@ -3365,12 +3378,18 @@
if (leaf_schema->type->basetype == LY_TYPE_LEAFREF) {
lref = (struct lysc_type_leafref *)leaf_schema->type;
- if (lyplg_type_resolve_leafref(lref, elem, &leafref_node->value, tree, &target, &errmsg)) {
+ ly_set_free(targets, NULL);
+ if (lyplg_type_resolve_leafref(lref, elem, &leafref_node->value, tree, &targets, &errmsg)) {
/* leafref target not found */
free(errmsg);
} else {
/* leafref target found, link it */
- LY_CHECK_RET(lyd_link_leafref_node((struct lyd_node_term *)target, leafref_node));
+ for (i = 0; i < targets->count; ++i) {
+ if (targets->dnodes[i]->schema->nodetype & LYD_NODE_TERM) {
+ ret = lyd_link_leafref_node((struct lyd_node_term *)targets->dnodes[i], leafref_node);
+ LY_CHECK_GOTO(ret, cleanup);
+ }
+ }
}
}
}
@@ -3378,7 +3397,9 @@
}
}
- return LY_SUCCESS;
+cleanup:
+ ly_set_free(targets, NULL);
+ return ret;
}
LY_ERR
@@ -3394,20 +3415,22 @@
return LY_EDENIED;
}
+ /* remove link from target node to leafref node */
ret = lyd_get_or_create_leafref_links_record(node, &rec, 0);
if (ret == LY_SUCCESS) {
LY_ARRAY_REMOVE_VALUE(rec->leafref_nodes, leafref_node);
- if ((LY_ARRAY_COUNT(rec->leafref_nodes) == 0) && (rec->target_node == NULL)) {
+ if ((LY_ARRAY_COUNT(rec->leafref_nodes) == 0) && (LY_ARRAY_COUNT(rec->target_nodes) == 0)) {
lyd_free_leafref_nodes(node);
}
} else if (ret != LY_ENOTFOUND) {
return ret;
}
+ /* remove link from leafref node to target node */
ret = lyd_get_or_create_leafref_links_record(leafref_node, &rec, 0);
if (ret == LY_SUCCESS) {
- rec->target_node = NULL;
- if ((LY_ARRAY_COUNT(rec->leafref_nodes) == 0) && (rec->target_node == NULL)) {
+ LY_ARRAY_REMOVE_VALUE(rec->target_nodes, node);
+ if ((LY_ARRAY_COUNT(rec->leafref_nodes) == 0) && (LY_ARRAY_COUNT(rec->target_nodes) == 0)) {
lyd_free_leafref_nodes(leafref_node);
}
} else if (ret != LY_ENOTFOUND) {
diff --git a/src/tree_data.h b/src/tree_data.h
index 0cce979..745496d 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -1008,9 +1008,9 @@
It can also be populated based on manual request using
[link api](@ref lyd_leafref_link_node_tree). Freeing of the resources is
automatic. */
- const struct lyd_node_term *target_node; /** pointer to leafref target data node, by default is NULL. The logic
- is the same as for [leafref_nodes](@ref leafref_nodes) and is filled only
- for leafrefs */
+ const struct lyd_node_term **target_nodes; /** list of leafref target data nodes [sized array](@ref sizedarrays)). Byt default
+ it is empty. The logic is the same as for [leafref_nodes](@ref leafref_nodes) and
+ is filled only for leafrefs */
};
/**
diff --git a/src/tree_data_free.c b/src/tree_data_free.c
index ce4e526..80a02f2 100644
--- a/src/tree_data_free.c
+++ b/src/tree_data_free.c
@@ -142,15 +142,15 @@
lyd_free_leafref_links_rec(struct lyd_leafref_links_rec *rec)
{
LY_ARRAY_COUNT_TYPE u;
- struct lyd_leafref_links_rec *leafref_rec;
+ struct lyd_leafref_links_rec *rec2;
assert(rec);
- /* remove stored leafref nodes */
+ /* remove links of leafref nodes */
LY_ARRAY_FOR(rec->leafref_nodes, u) {
- if (lyd_get_or_create_leafref_links_record(rec->leafref_nodes[u], &leafref_rec, 0) == LY_SUCCESS) {
- leafref_rec->target_node = NULL;
- if (!LY_ARRAY_COUNT(leafref_rec->leafref_nodes) && !leafref_rec->target_node) {
+ if (lyd_get_or_create_leafref_links_record(rec->leafref_nodes[u], &rec2, 0) == LY_SUCCESS) {
+ LY_ARRAY_REMOVE_VALUE(rec2->target_nodes, rec->node);
+ if ((LY_ARRAY_COUNT(rec2->leafref_nodes) == 0) && (LY_ARRAY_COUNT(rec2->target_nodes) == 0)) {
lyd_free_leafref_nodes(rec->leafref_nodes[u]);
}
}
@@ -158,10 +158,17 @@
LY_ARRAY_FREE(rec->leafref_nodes);
rec->leafref_nodes = NULL;
- /* remove stored target node */
- if (rec->target_node) {
- lyd_unlink_leafref_node(rec->target_node, rec->node);
+ /* remove links of target nodes */
+ LY_ARRAY_FOR(rec->target_nodes, u) {
+ if (lyd_get_or_create_leafref_links_record(rec->target_nodes[u], &rec2, 0) == LY_SUCCESS) {
+ LY_ARRAY_REMOVE_VALUE(rec2->leafref_nodes, rec->node);
+ if ((LY_ARRAY_COUNT(rec2->leafref_nodes) == 0) && (LY_ARRAY_COUNT(rec2->target_nodes) == 0)) {
+ lyd_free_leafref_nodes(rec->target_nodes[u]);
+ }
+ }
}
+ LY_ARRAY_FREE(rec->target_nodes);
+ rec->target_nodes = NULL;
}
void
diff --git a/src/tree_data_internal.h b/src/tree_data_internal.h
index d639591..4df6d60 100644
--- a/src/tree_data_internal.h
+++ b/src/tree_data_internal.h
@@ -617,7 +617,7 @@
LY_ERR lyd_get_or_create_leafref_links_record(const struct lyd_node_term *node, struct lyd_leafref_links_rec **record, ly_bool create);
/**
- * @brief Adds links between leafref adn data node.
+ * @brief Adds links between leafref and data node.
*
* If the links were already added, it will not be added again.
* This API requires usage of LY_CTX_LEAFREF_LINKING context flag.
@@ -630,7 +630,7 @@
LY_ERR lyd_link_leafref_node(const struct lyd_node_term *node, const struct lyd_node_term *leafref_node);
/**
- * @brief Removes links between leafref adn data node.
+ * @brief Removes links between leafref and data node.
*
* If the links were never added, it will be silently ignored.
* This API requires usage of LY_CTX_LEAFREF_LINKING context flag.
diff --git a/src/tree_edit.h b/src/tree_edit.h
index 113c9e3..af13fd4 100644
--- a/src/tree_edit.h
+++ b/src/tree_edit.h
@@ -241,9 +241,9 @@
{ \
LY_ARRAY_COUNT_TYPE index__; \
LY_ARRAY_FOR(ARRAY, index__) { \
- if (ARRAY[index__] == VALUE) { \
+ if ((ARRAY)[index__] == VALUE) { \
if (index__ != LY_ARRAY_COUNT(ARRAY) - 1) { \
- memmove(&(ARRAY[index__]), &(ARRAY[LY_ARRAY_COUNT(ARRAY) - 1]), sizeof *(ARRAY)); \
+ memmove(&((ARRAY)[index__]), &((ARRAY)[LY_ARRAY_COUNT(ARRAY) - 1]), sizeof *(ARRAY)); \
} \
LY_ARRAY_DECREMENT(ARRAY); \
break; \
diff --git a/src/xpath.c b/src/xpath.c
index bc5f695..0f0869e 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -4017,6 +4017,9 @@
char *errmsg = NULL;
uint8_t oper;
LY_ERR r;
+ LY_ERR ret = LY_SUCCESS;
+ struct ly_set *targets = NULL;
+ uint32_t i;
if (options & LYXP_SCNODE_ALL) {
if (args[0]->type != LYXP_SET_SCNODE_SET) {
@@ -4048,12 +4051,14 @@
} /* else the target was found before but is disabled so it was removed */
}
- return LY_SUCCESS;
+ ret = LY_SUCCESS;
+ goto cleanup;
}
if (args[0]->type != LYXP_SET_NODE_SET) {
LOGVAL(set->ctx, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "deref(node-set)");
- return LY_EVALID;
+ ret = LY_EVALID;
+ goto cleanup;
}
lyxp_set_free_content(set);
@@ -4063,27 +4068,37 @@
if (sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
if (sleaf->type->basetype == LY_TYPE_LEAFREF) {
/* find leafref target */
- if (lyplg_type_resolve_leafref((struct lysc_type_leafref *)sleaf->type, &leaf->node, &leaf->value, set->tree,
- &node, &errmsg)) {
+ r = lyplg_type_resolve_leafref((struct lysc_type_leafref *)sleaf->type, &leaf->node, &leaf->value, set->tree,
+ &targets, &errmsg);
+ if (r) {
LOGERR(set->ctx, LY_EVALID, "%s", errmsg);
free(errmsg);
- return LY_EVALID;
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+
+ /* insert nodes into set */
+ for (i = 0; i < targets->count; ++i) {
+ set_insert_node(set, targets->dnodes[i], 0, LYXP_NODE_ELEM, 0);
}
} else {
assert(sleaf->type->basetype == LY_TYPE_INST);
if (ly_path_eval(leaf->value.target, set->tree, NULL, &node)) {
LOGERR(set->ctx, LY_EVALID, "Invalid instance-identifier \"%s\" value - required instance not found.",
lyd_get_value(&leaf->node));
- return LY_EVALID;
+ ret = LY_EVALID;
+ goto cleanup;
}
- }
- /* insert it */
- set_insert_node(set, node, 0, LYXP_NODE_ELEM, 0);
+ /* insert it */
+ set_insert_node(set, node, 0, LYXP_NODE_ELEM, 0);
+ }
}
}
- return LY_SUCCESS;
+cleanup:
+ ly_set_free(targets, NULL);
+ return ret;
}
static LY_ERR
diff --git a/tests/utests/data/test_tree_data.c b/tests/utests/data/test_tree_data.c
index f022e3c..478a931 100644
--- a/tests/utests/data/test_tree_data.c
+++ b/tests/utests/data/test_tree_data.c
@@ -651,8 +651,10 @@
/* verify state after leafref plugin validation */
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(target_node, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->leafref_nodes));
+ assert_ptr_equal(rec->leafref_nodes[0], leafref_node);
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(leafref_node, &rec));
- assert_ptr_equal(rec->target_node, target_node);
+ assert_int_equal(1, LY_ARRAY_COUNT(rec->target_nodes));
+ assert_ptr_equal(rec->target_nodes[0], target_node);
/* value modification of target */
assert_int_equal(LY_SUCCESS, lyd_change_term((struct lyd_node *)target_node, "ASD"));
assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(target_node, &rec));
@@ -665,8 +667,10 @@
assert_int_equal(LY_SUCCESS, lyd_leafref_link_node_tree(tree));
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(target_node, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->leafref_nodes));
+ assert_ptr_equal(rec->leafref_nodes[0], leafref_node);
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(leafref_node, &rec));
- assert_ptr_equal(rec->target_node, target_node);
+ assert_int_equal(1, LY_ARRAY_COUNT(rec->target_nodes));
+ assert_ptr_equal(rec->target_nodes[0], target_node);
/* value modification of leafref */
assert_int_equal(LY_SUCCESS, lyd_change_term((struct lyd_node *)leafref_node, "qwe"));
assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(target_node, &rec));
@@ -678,8 +682,122 @@
assert_int_equal(LY_SUCCESS, lyd_leafref_link_node_tree(tree));
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(target_node, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->leafref_nodes));
+ assert_ptr_equal(rec->leafref_nodes[0], leafref_node);
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(leafref_node, &rec));
- assert_ptr_equal(rec->target_node, target_node);
+ assert_int_equal(1, LY_ARRAY_COUNT(rec->target_nodes));
+ assert_ptr_equal(rec->target_nodes[0], target_node);
+ /* freeing whole tree */
+ lyd_free_all(tree);
+}
+
+static void
+test_data_leafref_nodes2(void **state)
+{
+ struct lyd_node *tree, *iter;
+ const char *schema, *data;
+ struct lyd_node_term *leafref_node;
+ const struct lyd_node_term *target_node1, *target_node2;
+ const struct lyd_leafref_links_rec *rec;
+
+ ly_ctx_set_options(UTEST_LYCTX, LY_CTX_LEAFREF_LINKING);
+
+ schema =
+ "module test-data-hash {"
+ " yang-version 1.1;"
+ " namespace \"urn:tests:tdh\";"
+ " prefix t;"
+ " list l1 {"
+ " key \"l1 l2\";"
+ " leaf l1 {"
+ " type string;"
+ " }"
+ " leaf l2 {"
+ " type string;"
+ " }"
+ " }"
+ " leaf ref1 {"
+ " type leafref {"
+ " path \"../l1/l1\";"
+ " }"
+ " }"
+ " leaf-list ll1 {"
+ " type string;"
+ " config false;"
+ " }"
+ " leaf ref2 {"
+ " type leafref {"
+ " path \"../ll1\";"
+ " }"
+ " config false;"
+ " }"
+ "}";
+
+ UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
+
+ data =
+ "{"
+ " \"test-data-hash:l1\": ["
+ " {\"l1\": \"A\", \"l2\": \"B\"},"
+ " {\"l1\": \"A\", \"l2\": \"C\"}"
+ " ],"
+ " \"test-data-hash:ref1\": \"A\","
+ " \"test-data-hash:ll1\": [\"asd\", \"qwe\", \"asd\"],"
+ " \"test-data-hash:ref2\": \"asd\""
+ "}";
+
+ /* The run must not crash due to the assert that checks the hash. */
+ CHECK_PARSE_LYD_PARAM(data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
+ LY_LIST_FOR(tree, iter) {
+ if (strcmp(iter->schema->name, "ref1") == 0) {
+ leafref_node = (struct lyd_node_term *)iter;
+ }
+ }
+
+ /* verify state after leafref plugin validation */
+ assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(leafref_node, &rec));
+ assert_int_equal(2, LY_ARRAY_COUNT(rec->target_nodes));
+ target_node1 = rec->target_nodes[0];
+ target_node2 = rec->target_nodes[1];
+ assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(target_node1, &rec));
+ assert_int_equal(1, LY_ARRAY_COUNT(rec->leafref_nodes));
+ assert_ptr_equal(rec->leafref_nodes[0], leafref_node);
+ assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(target_node2, &rec));
+ assert_int_equal(1, LY_ARRAY_COUNT(rec->leafref_nodes));
+ assert_ptr_equal(rec->leafref_nodes[0], leafref_node);
+ /* value modification of leafref to remove all links*/
+ assert_int_equal(LY_SUCCESS, lyd_change_term((struct lyd_node *)leafref_node, "qwe"));
+ assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(leafref_node, &rec));
+ assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(target_node1, &rec));
+ assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(target_node2, &rec));
+ /* linking the whole tree again */
+ assert_int_equal(LY_SUCCESS, lyd_change_term((struct lyd_node *)leafref_node, "A"));
+ assert_int_equal(LY_SUCCESS, lyd_leafref_link_node_tree(tree));
+ assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(leafref_node, &rec));
+ assert_int_equal(2, LY_ARRAY_COUNT(rec->target_nodes));
+ assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(target_node1, &rec));
+ assert_int_equal(1, LY_ARRAY_COUNT(rec->leafref_nodes));
+ assert_ptr_equal(rec->leafref_nodes[0], leafref_node);
+ assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(target_node2, &rec));
+ assert_int_equal(1, LY_ARRAY_COUNT(rec->leafref_nodes));
+ assert_ptr_equal(rec->leafref_nodes[0], leafref_node);
+
+ /* verify duplicated value in leaf-list */
+ LY_LIST_FOR(tree, iter) {
+ if (strcmp(iter->schema->name, "ref2") == 0) {
+ leafref_node = (struct lyd_node_term *)iter;
+ }
+ }
+
+ assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(leafref_node, &rec));
+ assert_int_equal(2, LY_ARRAY_COUNT(rec->target_nodes));
+ target_node1 = rec->target_nodes[0];
+ target_node2 = rec->target_nodes[1];
+ assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(target_node1, &rec));
+ assert_int_equal(1, LY_ARRAY_COUNT(rec->leafref_nodes));
+ assert_ptr_equal(rec->leafref_nodes[0], leafref_node);
+ assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(target_node2, &rec));
+ assert_int_equal(1, LY_ARRAY_COUNT(rec->leafref_nodes));
+ assert_ptr_equal(rec->leafref_nodes[0], leafref_node);
/* freeing whole tree */
lyd_free_all(tree);
}
@@ -698,6 +816,7 @@
UTEST(test_data_hash, setup),
UTEST(test_lyxp_vars),
UTEST(test_data_leafref_nodes),
+ UTEST(test_data_leafref_nodes2),
};
return cmocka_run_group_tests(tests, NULL, NULL);