Skip to content

Commit 2b51f7e

Browse files
validation BUGFIX when-false review fixes
Address review findings on the LYD_WHEN_FALSE handling. - Initialize the return code before skipping a when-false node in lyd_validate_final_r so a when-false first sibling no longer reads an uninitialized value. - Clear a stale LYD_WHEN_FALSE mark when a when later resolves to true so XPath no longer treats a now-valid node as non-existent on revalidation. - Skip container default handling for when-false nodes in addition to their child validation. - Add a nested when-in-when regression test confirming the node_when descendant cleanup suppresses the spurious child when error.
1 parent 5219b0b commit 2b51f7e

2 files changed

Lines changed: 54 additions & 14 deletions

File tree

src/validation.c

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,9 @@ lyd_validate_unres_when(struct lyd_node **tree, const struct lys_module *mod, st
479479
LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
480480
}
481481
} else {
482-
/* when true */
482+
/* when true; clear any stale when-false mark from a previous validation run
483+
* so XPath no longer treats the node as non-existent */
484+
node->flags &= ~LYD_WHEN_FALSE;
483485
node->flags |= LYD_WHEN_TRUE;
484486
}
485487

@@ -1814,6 +1816,7 @@ lyd_validate_final_r(struct lyd_node *first, const struct lyd_node *parent, cons
18141816
/* skip further validation for when-false nodes: the node is logically non-existent,
18151817
* so its own must constraints and obsolete checks must not run */
18161818
if (node->flags & LYD_WHEN_FALSE) {
1819+
r = LY_SUCCESS;
18171820
goto next_iter;
18181821
}
18191822

@@ -1846,20 +1849,17 @@ lyd_validate_final_r(struct lyd_node *first, const struct lyd_node *parent, cons
18461849
break;
18471850
}
18481851

1849-
/* skip when-false nodes: they are logically non-existent, so their children must not be validated */
1850-
if (node->flags & LYD_WHEN_FALSE) {
1851-
goto skip_children;
1852-
}
1853-
1854-
/* validate all children recursively */
1855-
r = lyd_validate_final_r(lyd_child(node), node, node->schema, NULL, ext, val_opts,
1856-
int_opts & ~LYD_INTOPT_SKIP_SIBLINGS, must_xp_opts, getnext_ht);
1857-
LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
1858-
1859-
skip_children:
1852+
/* skip when-false nodes: they are logically non-existent, so neither their children
1853+
* nor their container-default handling must run */
1854+
if (!(node->flags & LYD_WHEN_FALSE)) {
1855+
/* validate all children recursively */
1856+
r = lyd_validate_final_r(lyd_child(node), node, node->schema, NULL, ext, val_opts,
1857+
int_opts & ~LYD_INTOPT_SKIP_SIBLINGS, must_xp_opts, getnext_ht);
1858+
LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
18601859

1861-
/* set default for containers */
1862-
lyd_np_cont_dflt_set(node);
1860+
/* set default for containers */
1861+
lyd_np_cont_dflt_set(node);
1862+
}
18631863

18641864
if (int_opts & LYD_INTOPT_SKIP_SIBLINGS) {
18651865
break;

tests/utests/data/test_validation.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1832,6 +1832,46 @@ test_when_must_cross_ref(void **state)
18321832
LYD_VALIDATE_PRESENT | LYD_VALIDATE_MULTI_ERROR, LY_EVALID, tree);
18331833
CHECK_LOG_CTX_APPTAG("checker requires item[a]/value=expected", "/twm4:top/checker", 0, "checker-bad");
18341834
CHECK_LOG_CTX("When condition \"../flag = 'true'\" not satisfied.", "/twm4:top/item[name='a']", 0);
1835+
1836+
/* Regression: a when-false node with a descendant that also carries a when
1837+
* must NOT emit a spurious when error for the descendant. The descendant's
1838+
* when references its when-gated ancestor, so its evaluation returns
1839+
* LY_EINCOMPLETE and it stays queued in node_when until the ancestor is
1840+
* resolved to false. The node_when descendant cleanup in
1841+
* lyd_validate_unres_when then removes it before it can be (re-)evaluated.
1842+
* Without that cleanup, the descendant's own when is evaluated against the
1843+
* logically non-existent subtree and a second, spurious when error is
1844+
* reported. Only the ancestor's when error is expected. */
1845+
const char *schema5 =
1846+
"module twm5 {\n"
1847+
" namespace urn:tests:twm5;\n"
1848+
" prefix twm5;\n"
1849+
" yang-version 1.1;\n"
1850+
"\n"
1851+
" container top {\n"
1852+
" leaf flag {\n"
1853+
" type boolean;\n"
1854+
" }\n"
1855+
" container outer {\n"
1856+
" when \"../flag = 'true'\";\n"
1857+
" leaf inner {\n"
1858+
" when \"../../flag = 'true'\";\n"
1859+
" type string;\n"
1860+
" }\n"
1861+
" }\n"
1862+
" }\n"
1863+
"}";
1864+
const char *data5 =
1865+
"<top xmlns=\"urn:tests:twm5\">\n"
1866+
" <flag>false</flag>\n"
1867+
" <outer><inner>x</inner></outer>\n"
1868+
"</top>\n";
1869+
1870+
UTEST_ADD_MODULE(schema5, LYS_IN_YANG, NULL, NULL);
1871+
1872+
CHECK_PARSE_LYD_PARAM(data5, LYD_XML, 0,
1873+
LYD_VALIDATE_PRESENT | LYD_VALIDATE_MULTI_ERROR, LY_EVALID, tree);
1874+
CHECK_LOG_CTX("When condition \"../flag = 'true'\" not satisfied.", "/twm5:top/outer", 0);
18351875
}
18361876

18371877
int

0 commit comments

Comments
 (0)