From df9b93fdfc0dcc456223ef0df399cfdbb27d2262 Mon Sep 17 00:00:00 2001 From: Stefan Gula Date: Tue, 23 Sep 2025 13:35:15 +0200 Subject: [PATCH] plugin types BUGFIX correct handling of union type This bugfix corrects the behavior or union type plugin when used with LYPLG_TYPE_STORE_ONLY flag --- src/plugins_types/union.c | 16 +++++++---- tests/utests/types/union.c | 56 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 6 deletions(-) diff --git a/src/plugins_types/union.c b/src/plugins_types/union.c index 2e5c693fa..ad2a7b968 100644 --- a/src/plugins_types/union.c +++ b/src/plugins_types/union.c @@ -486,9 +486,6 @@ lyplg_type_store_union(const struct ly_ctx *ctx, const struct lysc_type *type, c ret = lyb_fill_subvalue(ctx, type_u, value, value_size_bits, prefix_data, subvalue, &options, unres, err); LY_CHECK_GOTO((ret != LY_SUCCESS) && (ret != LY_EINCOMPLETE), cleanup); } else { - /* to correctly resolve the union type, we need to always validate the value */ - options &= ~LYPLG_TYPE_STORE_ONLY; - /* store value to subvalue */ ret = union_subvalue_assignment(value, value_size_bits, &subvalue->original, &subvalue->orig_size_bits, &options); LY_CHECK_GOTO(ret, cleanup); @@ -498,9 +495,16 @@ lyplg_type_store_union(const struct ly_ctx *ctx, const struct lysc_type *type, c &subvalue->format, &subvalue->prefix_data); LY_CHECK_GOTO(ret, cleanup); - /* use the first usable subtype to store the value */ - ret = union_find_type(ctx, type_u, subvalue, options, 0, NULL, NULL, NULL, NULL, unres, err); - LY_CHECK_GOTO((ret != LY_SUCCESS) && (ret != LY_EINCOMPLETE), cleanup); + /* use the first usable and valid subtype to store the value */ + ret = union_find_type(ctx, type_u, subvalue, options & ~LYPLG_TYPE_STORE_ONLY, 0, NULL, NULL, NULL, NULL, unres, + err); + if (ret && (ret != LY_EINCOMPLETE) && (options & LYPLG_TYPE_STORE_ONLY)) { + /* we tried to find the actual type by validating the value but no type matched, so try to find any type */ + ly_err_free(*err); + *err = NULL; + ret = union_find_type(ctx, type_u, subvalue, options, 0, NULL, NULL, NULL, NULL, unres, err); + } + LY_CHECK_GOTO(ret && (ret != LY_EINCOMPLETE), cleanup); } /* store canonical value, if any (use the specific type value) */ diff --git a/tests/utests/types/union.c b/tests/utests/types/union.c index ff4f21bd7..03fb2fc17 100644 --- a/tests/utests/types/union.c +++ b/tests/utests/types/union.c @@ -301,6 +301,61 @@ test_validation(void **state) lyd_free_all(tree); } +static void +test_validation_store_only(void **state) +{ + const char *val_text = NULL; + struct ly_err_item *err = NULL; + struct lys_module *mod; + struct lyd_value value = {0}; + struct lyplg_type *type = lysc_get_type_plugin(lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_UNION])); + struct lysc_type *lysc_type; + const char *schema; + + schema = MODULE_CREATE_YANG("base", + "leaf l1 {\n" + " type union {\n" + " type string {\n" + " pattern \"[A-Z]\";\n" + " }\n" + " type int8 {\n" + " range 1..5;\n" + " }\n" + " }\n" + "}\n"); + UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod); + lysc_type = ((struct lysc_node_leaf *)mod->compiled->data)->type; + + /* check proper type */ + assert_string_equal("ly2 union", type->id); + + /* with LYPLG_TYPE_STORE_ONLY and correct validation */ + err = NULL; + val_text = "1"; + assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, val_text, strlen(val_text) * 8, + LYPLG_TYPE_STORE_ONLY, LY_VALUE_CANON, NULL, LYD_VALHINT_STRING | LYD_VALHINT_DECNUM, NULL, NULL, &value, NULL, &err)); + assert_int_equal(value.subvalue->value.realtype->basetype, LY_TYPE_INT8); + type->free(UTEST_LYCTX, &value); + ly_err_free(err); + + /* with LYPLG_TYPE_STORE_ONLY and incorrect validation */ + err = NULL; + val_text = "6"; + assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, val_text, strlen(val_text) * 8, + LYPLG_TYPE_STORE_ONLY, LY_VALUE_CANON, NULL, LYD_VALHINT_STRING | LYD_VALHINT_DECNUM, NULL, NULL, &value, NULL, &err)); + assert_int_equal(value.subvalue->value.realtype->basetype, LY_TYPE_STRING); + type->free(UTEST_LYCTX, &value); + ly_err_free(err); + + /* without LYPLG_TYPE_STORE_ONLY and incorrect validation */ + err = NULL; + val_text = "10"; + assert_int_equal(LY_EVALID, type->store(UTEST_LYCTX, lysc_type, val_text, strlen(val_text) * 8, + 0, LY_VALUE_CANON, NULL, LYD_VALHINT_STRING | LYD_VALHINT_DECNUM, NULL, NULL, &value, NULL, &err)); + ly_err_free(err); + UTEST_LOG_CTX_CLEAN; +} + int main(void) { @@ -310,6 +365,7 @@ main(void) UTEST(test_plugin_lyb), UTEST(test_plugin_sort), UTEST(test_validation), + UTEST(test_validation_store_only), }; return cmocka_run_group_tests(tests, NULL, NULL);