schema BUGFIX several tests and bugfixes of lys_getnext()
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 21fc337..cabccb2 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -53,7 +53,7 @@
next = last = (const struct lysc_node*)&((struct lysc_node_choice*)parent)->cases[0];
} else {
snode = lysc_node_children_p(parent, (options & LYS_GETNEXT_OUTPUT) ? LYS_CONFIG_R : LYS_CONFIG_W);
- /* do not return anything if the augment does not have any children */
+ /* do not return anything if the node does not have any children */
if (!snode || !(*snode)) {
return NULL;
}
@@ -66,15 +66,12 @@
if (!next) {
/* try to get action or notification */
goto repeat;
- } else if (!(options & LYS_GETNEXT_NOSTATECHECK)) {
- if (!lys_is_disabled(next, 0)) {
- return next;
- }
- /* continue to find next available node */
- } else {
- return next;
}
+ /* test if the next can be returned */
+ goto check;
+
} else if (last->nodetype == LYS_ACTION) {
+ action_flag = 1;
if (last->parent) {
actions = lysc_node_actions(last->parent);
} else {
@@ -90,6 +87,7 @@
}
goto repeat;
} else if (last->nodetype == LYS_NOTIF) {
+ action_flag = notif_flag = 1;
if (last->parent) {
notifs = lysc_node_notifs(last->parent);
} else {
@@ -115,7 +113,7 @@
}
if (!next) {
/* possibly go back to parent */
- if (last->parent != parent) {
+ if (last && last->parent != parent) {
last = last->parent;
next = last->next;
} else if (!action_flag) {
@@ -129,6 +127,7 @@
}
goto repeat;
}
+check:
switch (next->nodetype) {
case LYS_ACTION:
case LYS_NOTIF:
@@ -158,7 +157,7 @@
} else {
/* go into */
if (options & LYS_GETNEXT_WITHCASE) {
- next = (struct lysc_node*)&((struct lysc_node_choice *)next)->cases;
+ next = (struct lysc_node*)((struct lysc_node_choice *)next)->cases;
} else {
next = ((struct lysc_node_choice *)next)->cases->child;
}
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index c2a6a54..bbf0d9b 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -3082,6 +3082,12 @@
struct lysp_node *child_p;
unsigned int u;
+ if (options & LYSC_OPT_RPC_MASK) {
+ LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+ "Action \"%s\" is placed inside another RPC/action.", action_p->name);
+ return LY_EVALID;
+ }
+
action->nodetype = LYS_ACTION;
action->module = ctx->mod;
action->parent = parent;
@@ -3104,14 +3110,14 @@
COMPILE_ARRAY_GOTO(ctx, action_p->input.musts, action->input.musts, options, u, lys_compile_must, ret, cleanup);
COMPILE_ARRAY_GOTO(ctx, action_p->input.exts, action->input.exts, options, u, lys_compile_ext, ret, cleanup);
LY_LIST_FOR(action_p->input.data, child_p) {
- LY_CHECK_RET(lys_compile_node(ctx, child_p, options & LYSC_OPT_RPC_INPUT, (struct lysc_node*)action, uses_status));
+ LY_CHECK_RET(lys_compile_node(ctx, child_p, options | LYSC_OPT_RPC_INPUT, (struct lysc_node*)action, uses_status));
}
/* output */
COMPILE_ARRAY_GOTO(ctx, action_p->output.musts, action->output.musts, options, u, lys_compile_must, ret, cleanup);
COMPILE_ARRAY_GOTO(ctx, action_p->output.exts, action->output.exts, options, u, lys_compile_ext, ret, cleanup);
LY_LIST_FOR(action_p->output.data, child_p) {
- LY_CHECK_RET(lys_compile_node(ctx, child_p, options & LYSC_OPT_RPC_OUTPUT, (struct lysc_node*)action, uses_status));
+ LY_CHECK_RET(lys_compile_node(ctx, child_p, options | LYSC_OPT_RPC_OUTPUT, (struct lysc_node*)action, uses_status));
}
cleanup:
@@ -3728,17 +3734,18 @@
* @param[in] parent Parent node holding the children list, in case of node from a choice's case,
* the choice itself is expected instead of a specific case node.
* @param[in] node Schema node to connect into the list.
+ * @param[in] options Compile options to distinguish input/output when placing node into RPC/action.
* @return LY_ERR value - LY_SUCCESS or LY_EEXIST.
*/
static LY_ERR
-lys_compile_node_connect(struct lysc_ctx *ctx, struct lysc_node *parent, struct lysc_node *node)
+lys_compile_node_connect(struct lysc_ctx *ctx, struct lysc_node *parent, struct lysc_node *node, int options)
{
struct lysc_node **children;
if (node->nodetype == LYS_CASE) {
children = (struct lysc_node**)&((struct lysc_node_choice*)parent)->cases;
} else {
- children = lysc_node_children_p(parent, node->flags);
+ children = lysc_node_children_p(parent, options);
}
if (children) {
if (!(*children)) {
@@ -3848,7 +3855,7 @@
cs->module = ctx->mod;
cs->prev = (struct lysc_node*)cs;
cs->nodetype = LYS_CASE;
- lys_compile_node_connect(ctx, (struct lysc_node*)ch, (struct lysc_node*)cs);
+ lys_compile_node_connect(ctx, (struct lysc_node*)ch, (struct lysc_node*)cs, options);
cs->parent = (struct lysc_node*)ch;
cs->child = child;
@@ -4094,10 +4101,10 @@
/* compile the children */
if (node_p->nodetype != LYS_CASE) {
- LY_CHECK_RET(lys_compile_node(ctx, node_p, options, target, 0));
+ LY_CHECK_RET(lys_compile_node(ctx, node_p, options | flags, target, 0));
} else {
LY_LIST_FOR(((struct lysp_node_case *)node_p)->child, case_node_p) {
- LY_CHECK_RET(lys_compile_node(ctx, case_node_p, options, target, 0));
+ LY_CHECK_RET(lys_compile_node(ctx, case_node_p, options | flags, target, 0));
}
}
@@ -4140,13 +4147,13 @@
switch (target->nodetype) {
case LYS_CONTAINER:
- COMPILE_ARRAY1_GOTO(ctx, aug_p->actions, ((struct lysc_node_container*)node)->actions, target,
- options, u, lys_compile_action, 0, ret, error);
+ COMPILE_ARRAY1_GOTO(ctx, aug_p->actions, ((struct lysc_node_container*)target)->actions, target,
+ options | flags, u, lys_compile_action, 0, ret, error);
/* TODO notifications */
break;
case LYS_LIST:
- COMPILE_ARRAY1_GOTO(ctx, aug_p->actions, ((struct lysc_node_list*)node)->actions, target,
- options, u, lys_compile_action, 0, ret, error);
+ COMPILE_ARRAY1_GOTO(ctx, aug_p->actions, ((struct lysc_node_list*)target)->actions, target,
+ options | flags, u, lys_compile_action, 0, ret, error);
/* TODO notifications */
break;
default:
@@ -4753,7 +4760,7 @@
} else { /* other than choice */
node->parent = parent;
}
- LY_CHECK_RET(lys_compile_node_connect(ctx, parent->nodetype == LYS_CASE ? parent->parent : parent, node), LY_EVALID);
+ LY_CHECK_RET(lys_compile_node_connect(ctx, parent->nodetype == LYS_CASE ? parent->parent : parent, node, options), LY_EVALID);
} else {
/* top-level element */
if (!ctx->mod->compiled->data) {
diff --git a/src/tree_schema_helpers.c b/src/tree_schema_helpers.c
index 6b89cb3..f5b9174 100644
--- a/src/tree_schema_helpers.c
+++ b/src/tree_schema_helpers.c
@@ -95,6 +95,7 @@
const struct lys_module *mod;
const char *nodeid_type;
int getnext_extra_flag = 0;
+ int current_nodetype = 0;
assert(nodeid);
assert(target);
@@ -147,11 +148,15 @@
/* move through input/output manually */
if (!strncmp("input", name, name_len)) {
(*result_flag) |= LYSC_OPT_RPC_INPUT;
- } else if (!strncmp("input", name, name_len)) {
+ } else if (!strncmp("output", name, name_len)) {
(*result_flag) |= LYSC_OPT_RPC_OUTPUT;
getnext_extra_flag = LYS_GETNEXT_OUTPUT;
+ } else {
+ goto getnext;
}
+ current_nodetype = LYS_INOUT;
} else {
+getnext:
context_node = lys_child(context_node, mod, name, name_len, 0,
getnext_extra_flag | LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE);
if (!context_node) {
@@ -160,8 +165,9 @@
return LY_ENOTFOUND;
}
getnext_extra_flag = 0;
+ current_nodetype = context_node->nodetype;
- if (context_node->nodetype == LYS_NOTIF) {
+ if (current_nodetype == LYS_NOTIF) {
(*result_flag) |= LYSC_OPT_NOTIFICATION;
}
}
@@ -179,7 +185,10 @@
if (ret == LY_SUCCESS) {
*target = context_node;
- if (nodetype && !(context_node->nodetype & nodetype)) {
+ if (nodetype & LYS_INOUT) {
+ /* instead of input/output nodes, the RPC/action node is actually returned */
+ }
+ if (nodetype && !(current_nodetype & nodetype)) {
return LY_EDENIED;
}
} else {
diff --git a/tests/src/test_tree_schema.c b/tests/src/test_tree_schema.c
index 7efa2bd..b2a6dda 100644
--- a/tests/src/test_tree_schema.c
+++ b/tests/src/test_tree_schema.c
@@ -98,6 +98,10 @@
struct ly_ctx *ctx;
struct lys_module *mod;
+ const struct lysc_node *node = NULL, *four;
+ const struct lysc_node_container *cont;
+ const struct lysc_action *rpc;
+
assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIRS, &ctx));
assert_non_null(mod = lys_parse_mem(ctx, "module a {yang-version 1.1; namespace urn:a;prefix a;"
@@ -109,6 +113,78 @@
"choice x { leaf e {type string;} case y {leaf f {type string;}}} anyxml g;"
"rpc h {input {leaf h-input {type string;}} output {leaf h-output {type string;}}}"
"notification i {leaf i-data {type string;}}}", LYS_IN_YANG));
+ assert_non_null(node = lys_getnext(node, NULL, mod->compiled, 0));
+ assert_string_equal("a", node->name);
+ cont = (const struct lysc_node_container*)node;
+ assert_non_null(node = lys_getnext(node, NULL, mod->compiled, 0));
+ assert_string_equal("b", node->name);
+ assert_non_null(node = lys_getnext(node, NULL, mod->compiled, 0));
+ assert_string_equal("c", node->name);
+ assert_non_null(node = lys_getnext(node, NULL, mod->compiled, 0));
+ assert_string_equal("d", node->name);
+ assert_non_null(node = lys_getnext(node, NULL, mod->compiled, 0));
+ assert_string_equal("e", node->name);
+ assert_non_null(node = lys_getnext(node, NULL, mod->compiled, 0));
+ assert_string_equal("f", node->name);
+ assert_non_null(node = lys_getnext(node, NULL, mod->compiled, 0));
+ assert_string_equal("g", node->name);
+ assert_non_null(node = lys_getnext(node, NULL, mod->compiled, 0));
+ assert_string_equal("h", node->name);
+ rpc = (const struct lysc_action*)node;
+ /* TODO Notifications
+ assert_non_null(node = lys_getnext(node, NULL, mod->compiled, 0));
+ assert_string_equal("i", node->name);
+ */
+ assert_null(node = lys_getnext(node, NULL, mod->compiled, 0));
+ /* Inside container */
+ assert_non_null(node = lys_getnext(node, (const struct lysc_node*)cont, mod->compiled, 0));
+ assert_string_equal("one", node->name);
+ assert_non_null(node = lys_getnext(node, (const struct lysc_node*)cont, mod->compiled, 0));
+ assert_string_equal("two", node->name);
+ assert_non_null(node = lys_getnext(node, (const struct lysc_node*)cont, mod->compiled, 0));
+ assert_string_equal("three", node->name);
+ assert_non_null(node = four = lys_getnext(node, (const struct lysc_node*)cont, mod->compiled, 0));
+ assert_string_equal("four", node->name);
+ assert_non_null(node = lys_getnext(node, (const struct lysc_node*)cont, mod->compiled, 0));
+ assert_string_equal("five", node->name);
+ assert_non_null(node = lys_getnext(node, (const struct lysc_node*)cont, mod->compiled, 0));
+ assert_string_equal("six", node->name);
+ assert_non_null(node = lys_getnext(node, (const struct lysc_node*)cont, mod->compiled, 0));
+ assert_string_equal("seven", node->name);
+ assert_non_null(node = lys_getnext(node, (const struct lysc_node*)cont, mod->compiled, 0));
+ assert_string_equal("eight", node->name);
+ /* TODO Notifications
+ assert_non_null(node = lys_getnext(node, (const struct lysc_node*)cont, mod->compiled, 0));
+ assert_string_equal("nine", node->name);
+ */
+ assert_null(node = lys_getnext(node, (const struct lysc_node*)cont, mod->compiled, 0));
+ /* Inside RPC */
+ assert_non_null(node = lys_getnext(node, (const struct lysc_node*)rpc, mod->compiled, 0));
+ assert_string_equal("h-input", node->name);
+ assert_null(node = lys_getnext(node, (const struct lysc_node*)rpc, mod->compiled, 0));
+
+ /* options */
+ assert_non_null(node = lys_getnext(four, (const struct lysc_node*)cont, mod->compiled, LYS_GETNEXT_WITHCHOICE));
+ assert_string_equal("x", node->name);
+ assert_non_null(node = lys_getnext(node, (const struct lysc_node*)cont, mod->compiled, LYS_GETNEXT_WITHCHOICE));
+ assert_string_equal("seven", node->name);
+
+ assert_non_null(node = lys_getnext(four, (const struct lysc_node*)cont, mod->compiled, LYS_GETNEXT_NOCHOICE));
+ assert_string_equal("seven", node->name);
+
+ assert_non_null(node = lys_getnext(four, (const struct lysc_node*)cont, mod->compiled, LYS_GETNEXT_WITHCASE));
+ assert_string_equal("five", node->name);
+ assert_non_null(node = lys_getnext(node, (const struct lysc_node*)cont, mod->compiled, LYS_GETNEXT_WITHCASE));
+ assert_string_equal("y", node->name);
+ assert_non_null(node = lys_getnext(node, (const struct lysc_node*)cont, mod->compiled, LYS_GETNEXT_WITHCASE));
+ assert_string_equal("seven", node->name);
+
+ assert_non_null(node = lys_getnext(NULL, NULL, mod->compiled, LYS_GETNEXT_INTONPCONT));
+ assert_string_equal("one", node->name);
+
+ assert_non_null(node = lys_getnext(NULL, (const struct lysc_node*)rpc, mod->compiled, LYS_GETNEXT_OUTPUT));
+ assert_string_equal("h-output", node->name);
+ assert_null(node = lys_getnext(node, (const struct lysc_node*)rpc, mod->compiled, LYS_GETNEXT_OUTPUT));
*state = NULL;
ly_ctx_destroy(ctx, NULL);
diff --git a/tests/src/test_tree_schema_compile.c b/tests/src/test_tree_schema_compile.c
index babfd49..328f749 100644
--- a/tests/src/test_tree_schema_compile.c
+++ b/tests/src/test_tree_schema_compile.c
@@ -2944,6 +2944,10 @@
"deviation /x {deviate replace {type empty;}}}", LYS_IN_YANG));
logbuf_assert("Leaf-list of type \"empty\" is allowed only in YANG 1.1 modules.");
+ assert_null(lys_parse_mem(ctx, "module oo {yang-version 1.1; namespace urn:oo;prefix oo; rpc test {input {container a {leaf b {type string;}}}}"
+ "augment /test/input/a {action invalid {input {leaf x {type string;}}}}}", LYS_IN_YANG));
+ logbuf_assert("Action \"invalid\" is placed inside another RPC/action.");
+
*state = NULL;
ly_ctx_destroy(ctx, NULL);
}