Skip to content

Commit 2d6dbc3

Browse files
committed
schema compile UPDATE deviate ext inst support
Refs #2496
1 parent e1e8840 commit 2d6dbc3

File tree

2 files changed

+145
-10
lines changed

2 files changed

+145
-10
lines changed

src/schema_compile_amend.c

Lines changed: 97 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* @author Michal Vasko <mvasko@cesnet.cz>
55
* @brief Schema compilation of augments, deviations, and refines.
66
*
7-
* Copyright (c) 2015 - 2024 CESNET, z.s.p.o.
7+
* Copyright (c) 2015 - 2026 CESNET, z.s.p.o.
88
*
99
* This source code is licensed under BSD 3-Clause License (the "License").
1010
* You may not use this file except in compliance with the License.
@@ -1275,10 +1275,59 @@ lys_apply_deviate_add(struct lysc_ctx *ctx, struct lysp_deviate_add *d, struct l
12751275
*num = d->max;
12761276
}
12771277

1278+
/* *ext-inst */
1279+
DUP_EXTS(ctx->ctx, ctx->pmod, target, lyplg_ext_nodetype2stmt(target->nodetype), d->exts, target->exts, lysp_ext_dup);
1280+
12781281
cleanup:
12791282
return ret;
12801283
}
12811284

1285+
/**
1286+
* @brief Find a matching parsed ext instance.
1287+
*
1288+
* @param[in] ctx Context to use.
1289+
* @param[in] pmod Current parsed module.
1290+
* @param[in] ext_def1 Ext inst definition to match.
1291+
* @param[in] ext_arg1 Ext inst argument to match.
1292+
* @param[in] exts2 Ext inst array to search in.
1293+
* @param[out] v Index of the matching ext inst in @p exts2.
1294+
* @return LY_ERR value.
1295+
*/
1296+
static LY_ERR
1297+
lys_apply_deviate_ext_inst_find(const struct ly_ctx *ctx, const struct lysp_module *pmod,
1298+
const struct lysp_ext *ext_def1, const char *ext_arg1, const struct lysp_ext_instance *exts2, LY_ARRAY_COUNT_TYPE *v)
1299+
{
1300+
struct lysp_ext *ext_def2;
1301+
1302+
LY_ARRAY_FOR(exts2, *v) {
1303+
if (!(exts2[*v].parent_stmt & LY_STMT_NODE_MASK)) {
1304+
/* match only node ext instances */
1305+
continue;
1306+
}
1307+
1308+
lysp_ext_find_definition(ctx, pmod, &exts2[*v], NULL, &ext_def2);
1309+
assert(ext_def2);
1310+
if (ext_def1 != ext_def2) {
1311+
/* definition mismatch */
1312+
continue;
1313+
}
1314+
1315+
if ((ext_arg1 && !exts2[*v].argument) || (!ext_arg1 && exts2[*v].argument) ||
1316+
(ext_arg1 && exts2[*v].argument && strcmp(ext_arg1, exts2[*v].argument))) {
1317+
/* argument mismatch */
1318+
continue;
1319+
}
1320+
1321+
/* match */
1322+
break;
1323+
}
1324+
1325+
if (LY_ARRAY_COUNT(exts2) == *v) {
1326+
return LY_ENOTFOUND;
1327+
}
1328+
return LY_SUCCESS;
1329+
}
1330+
12821331
/**
12831332
* @brief Apply deviate delete.
12841333
*
@@ -1294,6 +1343,7 @@ lys_apply_deviate_delete(struct lysc_ctx *ctx, struct lysp_deviate_del *d, struc
12941343
struct lysp_restr **musts;
12951344
LY_ARRAY_COUNT_TYPE u, v;
12961345
struct lysp_qname **uniques, **dflts;
1346+
struct lysp_ext *ext_def;
12971347

12981348
#define DEV_DEL_ARRAY(DEV_ARRAY, ORIG_ARRAY, DEV_MEMBER, ORIG_MEMBER, FREE_FUNC, FREE_CTX, PROPERTY) \
12991349
LY_ARRAY_FOR(d->DEV_ARRAY, u) { \
@@ -1396,6 +1446,30 @@ lys_apply_deviate_delete(struct lysc_ctx *ctx, struct lysp_deviate_del *d, struc
13961446
}
13971447
}
13981448

1449+
/* *ext-inst */
1450+
LY_ARRAY_FOR(d->exts, u) {
1451+
lysp_ext_find_definition(ctx->ctx, ctx->pmod, &d->exts[u], NULL, &ext_def);
1452+
assert(ext_def);
1453+
1454+
if (lys_apply_deviate_ext_inst_find(ctx->ctx, ctx->pmod, ext_def, d->exts[u].argument, target->exts, &v)) {
1455+
LOGVAL(ctx->ctx, NULL, LYVE_REFERENCE, "Invalid deviation deleting \"ext-inst\" property \"%s%s%s\" "
1456+
"which does not match any of the target's property values.", d->exts[u].name,
1457+
d->exts[u].argument ? " " : "", d->exts[u].argument ? d->exts[u].argument : "");
1458+
ret = LY_EVALID;
1459+
goto cleanup;
1460+
}
1461+
1462+
LY_ARRAY_DECREMENT(target->exts);
1463+
lysp_ext_instance_free(ctx->ctx, &target->exts[v]);
1464+
if (v < LY_ARRAY_COUNT(target->exts)) {
1465+
memmove(&target->exts[v], &target->exts[v + 1], (LY_ARRAY_COUNT(target->exts) - v) * sizeof *target->exts);
1466+
}
1467+
}
1468+
if (!LY_ARRAY_COUNT(target->exts)) {
1469+
LY_ARRAY_FREE(target->exts);
1470+
target->exts = NULL;
1471+
}
1472+
13991473
cleanup:
14001474
return ret;
14011475
}
@@ -1412,7 +1486,10 @@ static LY_ERR
14121486
lys_apply_deviate_replace(struct lysc_ctx *ctx, struct lysp_deviate_rpl *d, struct lysp_node *target)
14131487
{
14141488
LY_ERR ret = LY_SUCCESS;
1489+
LY_ARRAY_COUNT_TYPE u, v;
14151490
uint32_t *num;
1491+
struct lysp_ext *ext_def;
1492+
enum ly_stmt parent_stmt;
14161493

14171494
#define DEV_CHECK_PRESENCE(TYPE, MEMBER, DEVTYPE, PROPERTY, VALUE) \
14181495
if (!((TYPE)target)->MEMBER) { \
@@ -1537,6 +1614,25 @@ lys_apply_deviate_replace(struct lysc_ctx *ctx, struct lysp_deviate_rpl *d, stru
15371614
*num = d->max;
15381615
}
15391616

1617+
/* *ext-inst */
1618+
LY_ARRAY_FOR(d->exts, u) {
1619+
lysp_ext_find_definition(ctx->ctx, ctx->pmod, &d->exts[u], NULL, &ext_def);
1620+
assert(ext_def);
1621+
1622+
if (lys_apply_deviate_ext_inst_find(ctx->ctx, ctx->pmod, ext_def, d->exts[u].argument, target->exts, &v)) {
1623+
LOGVAL(ctx->ctx, NULL, LYVE_REFERENCE, "Invalid deviation replacing \"ext-inst\" property \"%s%s%s\" "
1624+
"which is not present.", d->exts[u].name, d->exts[u].argument ? " " : "",
1625+
d->exts[u].argument ? d->exts[u].argument : "");
1626+
ret = LY_EVALID;
1627+
goto cleanup;
1628+
}
1629+
1630+
parent_stmt = target->exts[v].parent_stmt;
1631+
lysp_ext_instance_free(ctx->ctx, &target->exts[v]);
1632+
memset(&target->exts[v], 0, sizeof target->exts[v]);
1633+
LY_CHECK_GOTO(ret = lysp_ext_dup(ctx->ctx, ctx->pmod, target, parent_stmt, &d->exts[u], &target->exts[v]), cleanup);
1634+
}
1635+
15401636
cleanup:
15411637
return ret;
15421638
}
@@ -1588,9 +1684,6 @@ lys_apply_deviation(struct lysc_ctx *ctx, struct lysp_deviation *dev, const stru
15881684
LY_CHECK_GOTO(ret, cleanup);
15891685
}
15901686

1591-
/* deviation extension instances */
1592-
DUP_EXTS(ctx->ctx, dev_pmod, target, lyplg_ext_nodetype2stmt(target->nodetype), dev->exts, target->exts, lysp_ext_dup);
1593-
15941687
cleanup:
15951688
ctx->cur_mod = orig_mod;
15961689
ctx->pmod = orig_pmod;

tests/utests/schema/test_tree_schema_compile.c

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3400,13 +3400,45 @@ test_deviation(void **state)
34003400
assert_null(node->next);
34013401

34023402
/* extension */
3403-
assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module mod-a {namespace urn:mod-a;prefix a;"
3403+
assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module amod-a {namespace urn:amod-a;prefix a;"
34043404
"container cont {leaf l {type string;} leaf l2 {type string;}}}", LYS_IN_YANG, NULL));
3405-
assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module mod-b {namespace urn:mod-b;prefix b;"
3405+
assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module amod-b {namespace urn:amod-b;prefix b;"
34063406
"extension ext1; extension ext2;}", LYS_IN_YANG, NULL));
3407-
assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module mod-c {namespace urn:mod-c;prefix c;"
3408-
"import mod-a {prefix a;} import mod-b {prefix b;}"
3407+
assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module amod-c {namespace urn:amod-c;prefix c;"
3408+
"import amod-a {prefix a;} import amod-b {prefix b;}"
34093409
"deviation \"/a:cont/a:l\" {deviate add {b:ext1;}}}", LYS_IN_YANG, NULL));
3410+
assert_non_null((mod = ly_ctx_get_module_implemented(UTEST_LYCTX, "amod-a")));
3411+
node = mod->compiled->data;
3412+
assert_string_equal(node->name, "cont");
3413+
assert_non_null(node = lysc_node_child(node));
3414+
assert_string_equal(node->name, "l");
3415+
assert_non_null(node->exts);
3416+
3417+
assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module bmod-a {namespace urn:bmod-a;prefix a;"
3418+
"extension ext1;"
3419+
"container cont {leaf l {type string; a:ext1;}}}", LYS_IN_YANG, NULL));
3420+
assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module bmod-b {namespace urn:bmod-b;prefix b;"
3421+
"import bmod-a {prefix a;}"
3422+
"deviation \"/a:cont/a:l\" {deviate delete {a:ext1;}}}", LYS_IN_YANG, NULL));
3423+
assert_non_null((mod = ly_ctx_get_module_implemented(UTEST_LYCTX, "bmod-a")));
3424+
node = mod->compiled->data;
3425+
assert_string_equal(node->name, "cont");
3426+
assert_non_null(node = lysc_node_child(node));
3427+
assert_string_equal(node->name, "l");
3428+
assert_null(node->exts);
3429+
3430+
assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module cmod-a {namespace urn:cmod-a;prefix a;"
3431+
"extension ext1;"
3432+
"container cont {leaf l {type string; a:ext1;}}}", LYS_IN_YANG, NULL));
3433+
assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module cmod-b {namespace urn:cmod-b;prefix b;"
3434+
"import cmod-a {prefix a;}"
3435+
"deviation \"/a:cont/a:l\" {deviate replace {a:ext1;}}}", LYS_IN_YANG, NULL));
3436+
assert_non_null((mod = ly_ctx_get_module_implemented(UTEST_LYCTX, "cmod-a")));
3437+
node = mod->compiled->data;
3438+
assert_string_equal(node->name, "cont");
3439+
assert_non_null(node = lysc_node_child(node));
3440+
assert_string_equal(node->name, "l");
3441+
assert_non_null(node->exts);
34103442

34113443
/* default identity referencing deprecated */
34123444
ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, "module a1-imp {namespace urn:a1-imp;prefix a1i;"
@@ -3665,7 +3697,8 @@ test_deviation(void **state)
36653697
"deviation /x {deviate replace {type uint8;}}}", LYS_IN_YANG, &mod));
36663698
CHECK_LOG_CTX("Invalid default - value does not fit the type "
36673699
"(Value \"300\" is out of type uint8 min/max bounds.).", "/oo1:x", 0);
3668-
assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module oo2 {yang-version 1.1;namespace urn:oo2;prefix oo2; leaf-list x {type uint16; default 10; default 300;}"
3700+
assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module oo2 {yang-version 1.1;namespace urn:oo2;prefix oo2;"
3701+
"leaf-list x {type uint16; default 10; default 300;}"
36693702
"deviation /x {deviate replace {type uint8;}}}", LYS_IN_YANG, &mod));
36703703
CHECK_LOG_CTX("Invalid default - value does not fit the type "
36713704
"(Value \"300\" is out of type uint8 min/max bounds.).", "/oo2:x", 0);
@@ -3674,12 +3707,21 @@ test_deviation(void **state)
36743707
CHECK_LOG_CTX("Invalid default - value does not fit the type "
36753708
"(Value \"300\" is out of type uint8 min/max bounds.).", "/oo3:x", 0);
36763709

3677-
assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module pp {namespace urn:pp;prefix pp; leaf l { type leafref {path /c/x;}}"
3710+
assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module pp {namespace urn:pp;prefix pp;"
3711+
"leaf l { type leafref {path /c/x;}}"
36783712
"container c {leaf x {type string;} leaf y {type string;}}}", LYS_IN_YANG, &mod));
36793713
assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module pp1 {namespace urn:pp1;prefix pp1; import pp {prefix pp;}"
36803714
"deviation /pp:c/pp:x {deviate not-supported;}}", LYS_IN_YANG, &mod));
36813715
CHECK_LOG_CTX("Target of leafref \"l\" cannot be referenced because it is disabled.", "/pp:l", 0);
36823716
CHECK_LOG_CTX("Not found node \"x\" in path.", "/pp:l", 0);
3717+
3718+
assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module emod-a {namespace urn:emod-a;prefix a;"
3719+
"extension ext1; extension ext2 {argument arg;}"
3720+
"container cont {leaf l {type string; a:ext2 my-arg;}}}", LYS_IN_YANG, NULL));
3721+
assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module emod-b {namespace urn:emod-b;prefix b;"
3722+
"import emod-a {prefix a;}"
3723+
"deviation \"/a:cont/a:l\" {deviate delete {a:ext2 not-arg;}}}", LYS_IN_YANG, NULL));
3724+
CHECK_LOG_CTX("Invalid deviation deleting \"ext-inst\" property \"a:ext2 not-arg\" which does not match any of the target's property values.", "/emod-b:{deviation='/a:cont/a:l'}", 0);
36833725
}
36843726

36853727
static void

0 commit comments

Comments
 (0)