diff options
Diffstat (limited to 'tests/utests/basic/test_context.c')
-rw-r--r-- | tests/utests/basic/test_context.c | 1103 |
1 files changed, 1103 insertions, 0 deletions
diff --git a/tests/utests/basic/test_context.c b/tests/utests/basic/test_context.c new file mode 100644 index 0000000..7feb65f --- /dev/null +++ b/tests/utests/basic/test_context.c @@ -0,0 +1,1103 @@ +/** + * @file test_context.c + * @author: Radek Krejci <rkrejci@cesnet.cz> + * @brief unit tests for functions from context.c + * + * Copyright (c) 2018 CESNET, z.s.p.o. + * + * This source code is licensed under BSD 3-Clause License (the "License"). + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + */ +#define _UTEST_MAIN_ +#include "utests.h" + +#include "context.h" +#include "in.h" +#include "ly_common.h" +#include "schema_compile.h" +#include "tests_config.h" +#include "tree_schema_internal.h" + +#ifdef _WIN32 + +static void +slashes_to_backslashes(char *path) +{ + while ((path = strchr(path, '/'))) { + *path++ = '\\'; + } +} + +static void +test_searchdirs(void **state) +{ + const char * const *list; + char *path1 = strdup(TESTS_BIN "/utests"); + char *path2 = strdup(TESTS_SRC); + + slashes_to_backslashes(path1); + slashes_to_backslashes(path2); + + assert_int_equal(LY_EINVAL, ly_ctx_set_searchdir(NULL, NULL)); + CHECK_LOG_LASTMSG("Invalid argument ctx (ly_ctx_set_searchdir())."); + assert_null(ly_ctx_get_searchdirs(NULL)); + CHECK_LOG_LASTMSG("Invalid argument ctx (ly_ctx_get_searchdirs())."); + assert_int_equal(LY_EINVAL, ly_ctx_unset_searchdir(NULL, NULL)); + CHECK_LOG_LASTMSG("Invalid argument ctx (ly_ctx_unset_searchdir())."); + + /* correct path */ + assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, path1)); + assert_int_equal(1, UTEST_LYCTX->search_paths.count); + assert_string_equal(path1, UTEST_LYCTX->search_paths.objs[0]); + + /* duplicated paths */ + assert_int_equal(LY_EEXIST, ly_ctx_set_searchdir(UTEST_LYCTX, path1)); + assert_int_equal(1, UTEST_LYCTX->search_paths.count); + assert_string_equal(path1, UTEST_LYCTX->search_paths.objs[0]); + + /* another path */ + assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, path2)); + assert_int_equal(2, UTEST_LYCTX->search_paths.count); + assert_string_equal(path2, UTEST_LYCTX->search_paths.objs[1]); + + /* get searchpaths */ + list = ly_ctx_get_searchdirs(UTEST_LYCTX); + assert_non_null(list); + assert_string_equal(path1, list[0]); + assert_string_equal(path2, list[1]); + assert_null(list[2]); + + /* removing searchpaths */ + /* nonexisting */ + assert_int_equal(LY_EINVAL, ly_ctx_unset_searchdir(UTEST_LYCTX, "/nonexistingfile")); + CHECK_LOG_CTX("Invalid argument value (ly_ctx_unset_searchdir()).", NULL, 0); + + /* first */ + assert_int_equal(LY_SUCCESS, ly_ctx_unset_searchdir(UTEST_LYCTX, path1)); + assert_int_equal(1, UTEST_LYCTX->search_paths.count); + assert_string_not_equal(path1, list[0]); + + /* second */ + assert_int_equal(LY_SUCCESS, ly_ctx_unset_searchdir(UTEST_LYCTX, path2)); + assert_int_equal(0, UTEST_LYCTX->search_paths.count); + + free(path1); + free(path2); +} + +#else + +static void +test_searchdirs(void **state) +{ + const char * const *list; + + /* invalid arguments */ + assert_int_equal(LY_EINVAL, ly_ctx_set_searchdir(NULL, NULL)); + CHECK_LOG_LASTMSG("Invalid argument ctx (ly_ctx_set_searchdir())."); + assert_null(ly_ctx_get_searchdirs(NULL)); + CHECK_LOG_LASTMSG("Invalid argument ctx (ly_ctx_get_searchdirs())."); + assert_int_equal(LY_EINVAL, ly_ctx_unset_searchdir(NULL, NULL)); + CHECK_LOG_LASTMSG("Invalid argument ctx (ly_ctx_unset_searchdir())."); + + /* readable and executable, but not a directory */ + assert_int_equal(LY_EINVAL, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_BIN "/utest_context")); + CHECK_LOG_CTX("Given search directory \""TESTS_BIN "/utest_context\" is not a directory.", NULL, 0); + /* not existing */ + assert_int_equal(LY_EINVAL, ly_ctx_set_searchdir(UTEST_LYCTX, "/nonexistingfile")); + CHECK_LOG_CTX("Unable to use search directory \"/nonexistingfile\" (No such file or directory).", NULL, 0); + + /* ly_set_add() fails */ + /* no change */ + assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, NULL)); + + /* correct path */ + assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_BIN "/utests")); + assert_int_equal(1, UTEST_LYCTX->search_paths.count); + assert_string_equal(TESTS_BIN "/utests", UTEST_LYCTX->search_paths.objs[0]); + + /* duplicated paths */ + assert_int_equal(LY_EEXIST, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_BIN "/utests")); + assert_int_equal(1, UTEST_LYCTX->search_paths.count); + assert_string_equal(TESTS_BIN "/utests", UTEST_LYCTX->search_paths.objs[0]); + + /* another paths - add 8 to fill the initial buffer of the searchpaths list */ + assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_BIN "/CMakeFiles")); + assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_SRC "/../src")); + assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_SRC "/../CMakeModules")); + assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_SRC "/../doc")); + assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_SRC)); + assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_BIN)); + assert_int_equal(7, UTEST_LYCTX->search_paths.count); + + /* get searchpaths */ + list = ly_ctx_get_searchdirs(UTEST_LYCTX); + assert_non_null(list); + assert_string_equal(TESTS_BIN "/utests", list[0]); + assert_string_equal(TESTS_BIN "/CMakeFiles", list[1]); + assert_string_equal(TESTS_SRC, list[5]); + assert_string_equal(TESTS_BIN, list[6]); + assert_null(list[7]); + + /* removing searchpaths */ + /* nonexisting */ + assert_int_equal(LY_EINVAL, ly_ctx_unset_searchdir(UTEST_LYCTX, "/nonexistingfile")); + CHECK_LOG_CTX("Invalid argument value (ly_ctx_unset_searchdir()).", NULL, 0); + /* first */ + assert_int_equal(LY_SUCCESS, ly_ctx_unset_searchdir(UTEST_LYCTX, TESTS_BIN "/utests")); + assert_string_not_equal(TESTS_BIN "/utests", list[0]); + assert_int_equal(6, UTEST_LYCTX->search_paths.count); + /* middle */ + assert_int_equal(LY_SUCCESS, ly_ctx_unset_searchdir(UTEST_LYCTX, TESTS_SRC)); + assert_int_equal(5, UTEST_LYCTX->search_paths.count); + /* last */ + assert_int_equal(LY_SUCCESS, ly_ctx_unset_searchdir(UTEST_LYCTX, TESTS_BIN)); + assert_int_equal(4, UTEST_LYCTX->search_paths.count); + /* all */ + assert_int_equal(LY_SUCCESS, ly_ctx_unset_searchdir(UTEST_LYCTX, NULL)); + assert_int_equal(0, UTEST_LYCTX->search_paths.count); + + /* again - no change */ + assert_int_equal(LY_SUCCESS, ly_ctx_unset_searchdir(UTEST_LYCTX, NULL)); + + /* cleanup */ + ly_ctx_destroy(UTEST_LYCTX); + + /* test searchdir list in ly_ctx_new() */ + assert_int_equal(LY_EINVAL, ly_ctx_new("/nonexistingfile", 0, &UTEST_LYCTX)); + CHECK_LOG_LASTMSG("Unable to use search directory \"/nonexistingfile\" (No such file or directory)."); + assert_int_equal(LY_SUCCESS, + ly_ctx_new(TESTS_SRC PATH_SEPARATOR TESTS_BIN PATH_SEPARATOR TESTS_BIN PATH_SEPARATOR TESTS_SRC, + LY_CTX_DISABLE_SEARCHDIRS, &UTEST_LYCTX)); + assert_int_equal(2, UTEST_LYCTX->search_paths.count); + assert_string_equal(TESTS_SRC, UTEST_LYCTX->search_paths.objs[0]); + assert_string_equal(TESTS_BIN, UTEST_LYCTX->search_paths.objs[1]); +} + +#endif + +static void +test_options(void **state) +{ + /* use own context with extra flags */ + ly_ctx_destroy(UTEST_LYCTX); + + assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0xffff, &UTEST_LYCTX)); + + /* invalid arguments */ + assert_int_equal(0, ly_ctx_get_options(NULL)); + CHECK_LOG_LASTMSG("Invalid argument ctx (ly_ctx_get_options())."); + + assert_int_equal(LY_EINVAL, ly_ctx_set_options(NULL, 0)); + CHECK_LOG_LASTMSG("Invalid argument ctx (ly_ctx_set_options())."); + assert_int_equal(LY_EINVAL, ly_ctx_unset_options(NULL, 0)); + CHECK_LOG_LASTMSG("Invalid argument ctx (ly_ctx_unset_options())."); + + /* unset */ + /* LY_CTX_ALL_IMPLEMENTED */ + assert_int_not_equal(0, UTEST_LYCTX->flags & LY_CTX_ALL_IMPLEMENTED); + assert_int_equal(LY_SUCCESS, ly_ctx_unset_options(UTEST_LYCTX, LY_CTX_ALL_IMPLEMENTED)); + assert_int_equal(0, UTEST_LYCTX->flags & LY_CTX_ALL_IMPLEMENTED); + + /* LY_CTX_REF_IMPLEMENTED */ + assert_int_not_equal(0, UTEST_LYCTX->flags & LY_CTX_REF_IMPLEMENTED); + assert_int_equal(LY_SUCCESS, ly_ctx_unset_options(UTEST_LYCTX, LY_CTX_REF_IMPLEMENTED)); + assert_int_equal(0, UTEST_LYCTX->flags & LY_CTX_REF_IMPLEMENTED); + + /* LY_CTX_DISABLE_SEARCHDIRS */ + assert_int_not_equal(0, UTEST_LYCTX->flags & LY_CTX_DISABLE_SEARCHDIRS); + assert_int_equal(LY_SUCCESS, ly_ctx_unset_options(UTEST_LYCTX, LY_CTX_DISABLE_SEARCHDIRS)); + assert_int_equal(0, UTEST_LYCTX->flags & LY_CTX_DISABLE_SEARCHDIRS); + + /* LY_CTX_DISABLE_SEARCHDIR_CWD */ + assert_int_not_equal(0, UTEST_LYCTX->flags & LY_CTX_DISABLE_SEARCHDIR_CWD); + assert_int_equal(LY_SUCCESS, ly_ctx_unset_options(UTEST_LYCTX, LY_CTX_DISABLE_SEARCHDIR_CWD)); + assert_int_equal(0, UTEST_LYCTX->flags & LY_CTX_DISABLE_SEARCHDIR_CWD); + + /* LY_CTX_PREFER_SEARCHDIRS */ + assert_int_not_equal(0, UTEST_LYCTX->flags & LY_CTX_PREFER_SEARCHDIRS); + assert_int_equal(LY_SUCCESS, ly_ctx_unset_options(UTEST_LYCTX, LY_CTX_PREFER_SEARCHDIRS)); + assert_int_equal(0, UTEST_LYCTX->flags & LY_CTX_PREFER_SEARCHDIRS); + + /* LY_CTX_LEAFREF_EXTENDED */ + assert_int_not_equal(0, UTEST_LYCTX->flags & LY_CTX_LEAFREF_EXTENDED); + assert_int_equal(LY_SUCCESS, ly_ctx_unset_options(UTEST_LYCTX, LY_CTX_LEAFREF_EXTENDED)); + assert_int_equal(0, UTEST_LYCTX->flags & LY_CTX_LEAFREF_EXTENDED); + + /* LY_CTX_LEAFREF_LINKING */ + assert_int_not_equal(0, UTEST_LYCTX->flags & LY_CTX_LEAFREF_LINKING); + assert_int_equal(LY_SUCCESS, ly_ctx_unset_options(UTEST_LYCTX, LY_CTX_LEAFREF_LINKING)); + assert_int_equal(0, UTEST_LYCTX->flags & LY_CTX_LEAFREF_LINKING); + + /* LY_CTX_BUILTIN_PLUGINS_ONLY */ + assert_int_not_equal(0, UTEST_LYCTX->flags & LY_CTX_BUILTIN_PLUGINS_ONLY); + assert_int_equal(LY_SUCCESS, ly_ctx_unset_options(UTEST_LYCTX, LY_CTX_BUILTIN_PLUGINS_ONLY)); + assert_int_equal(0, UTEST_LYCTX->flags & LY_CTX_BUILTIN_PLUGINS_ONLY); + + assert_int_equal(UTEST_LYCTX->flags, ly_ctx_get_options(UTEST_LYCTX)); + + /* set back */ + /* LY_CTX_ALL_IMPLEMENTED */ + assert_int_equal(LY_SUCCESS, ly_ctx_set_options(UTEST_LYCTX, LY_CTX_ALL_IMPLEMENTED)); + assert_int_not_equal(0, UTEST_LYCTX->flags & LY_CTX_ALL_IMPLEMENTED); + + /* LY_CTX_REF_IMPLEMENTED */ + assert_int_equal(LY_SUCCESS, ly_ctx_set_options(UTEST_LYCTX, LY_CTX_REF_IMPLEMENTED)); + assert_int_not_equal(0, UTEST_LYCTX->flags & LY_CTX_REF_IMPLEMENTED); + + /* LY_CTX_DISABLE_SEARCHDIRS */ + assert_int_equal(LY_SUCCESS, ly_ctx_set_options(UTEST_LYCTX, LY_CTX_DISABLE_SEARCHDIRS)); + assert_int_not_equal(0, UTEST_LYCTX->flags & LY_CTX_DISABLE_SEARCHDIRS); + + /* LY_CTX_DISABLE_SEARCHDIR_CWD */ + assert_int_equal(LY_SUCCESS, ly_ctx_set_options(UTEST_LYCTX, LY_CTX_DISABLE_SEARCHDIR_CWD)); + assert_int_not_equal(0, UTEST_LYCTX->flags & LY_CTX_DISABLE_SEARCHDIR_CWD); + + /* LY_CTX_PREFER_SEARCHDIRS */ + assert_int_equal(LY_SUCCESS, ly_ctx_set_options(UTEST_LYCTX, LY_CTX_PREFER_SEARCHDIRS)); + assert_int_not_equal(0, UTEST_LYCTX->flags & LY_CTX_PREFER_SEARCHDIRS); + + /* LY_CTX_LEAFREF_EXTENDED */ + assert_int_equal(LY_SUCCESS, ly_ctx_set_options(UTEST_LYCTX, LY_CTX_LEAFREF_EXTENDED)); + assert_int_not_equal(0, UTEST_LYCTX->flags & LY_CTX_LEAFREF_EXTENDED); + + /* LY_CTX_LEAFREF_LINKING */ + assert_int_equal(LY_SUCCESS, ly_ctx_set_options(UTEST_LYCTX, LY_CTX_LEAFREF_LINKING)); + assert_int_not_equal(0, UTEST_LYCTX->flags & LY_CTX_LEAFREF_LINKING); + + /* LY_CTX_BUILTIN_PLUGINS_ONLY */ + assert_int_equal(LY_EINVAL, ly_ctx_set_options(UTEST_LYCTX, LY_CTX_BUILTIN_PLUGINS_ONLY)); + CHECK_LOG_CTX("Invalid argument option (LY_CTX_BUILTIN_PLUGINS_ONLY can be set only when creating a new context) (ly_ctx_set_options()).", NULL, 0); + + assert_int_equal(UTEST_LYCTX->flags, ly_ctx_get_options(UTEST_LYCTX)); +} + +static LY_ERR +test_imp_clb(const char *UNUSED(mod_name), const char *UNUSED(mod_rev), const char *UNUSED(submod_name), + const char *UNUSED(sub_rev), void *user_data, LYS_INFORMAT *format, + const char **module_data, void (**free_module_data)(void *model_data, void *user_data)) +{ + *module_data = user_data; + *format = LYS_IN_YANG; + *free_module_data = NULL; + return LY_SUCCESS; +} + +static void +test_models(void **state) +{ + struct ly_in *in; + const char *str; + struct lys_module *mod1, *mod2; + struct lys_glob_unres unres = {0}; + + /* use own context with extra flags */ + ly_ctx_destroy(UTEST_LYCTX); + + /* invalid arguments */ + assert_int_equal(0, ly_ctx_get_change_count(NULL)); + CHECK_LOG_LASTMSG("Invalid argument ctx (ly_ctx_get_change_count())."); + + assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIRS, &UTEST_LYCTX)); + assert_int_equal(UTEST_LYCTX->change_count, ly_ctx_get_change_count(UTEST_LYCTX)); + + assert_int_equal(LY_SUCCESS, ly_in_new_memory("module x {namespace urn:x;prefix x;}", &in)); + assert_int_equal(LY_EINVAL, lys_parse_in(UTEST_LYCTX, in, 4, NULL, NULL, &unres.creating, &mod1)); + lys_unres_glob_erase(&unres); + ly_in_free(in, 0); + CHECK_LOG_CTX("Invalid schema input format.", NULL, 0); + + /* import callback */ + ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, (void *)(str = "test")); + assert_ptr_equal(test_imp_clb, UTEST_LYCTX->imp_clb); + assert_ptr_equal(str, UTEST_LYCTX->imp_clb_data); + assert_ptr_equal(test_imp_clb, ly_ctx_get_module_imp_clb(UTEST_LYCTX, (void **)&str)); + assert_string_equal("test", str); + + ly_ctx_set_module_imp_clb(UTEST_LYCTX, NULL, NULL); + assert_null(UTEST_LYCTX->imp_clb); + assert_null(UTEST_LYCTX->imp_clb_data); + + /* name collision of module and submodule */ + ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, "submodule y {belongs-to a {prefix a;} revision 2018-10-30;}"); + assert_int_equal(LY_SUCCESS, ly_in_new_memory("module y {namespace urn:y;prefix y;include y;}", &in)); + assert_int_equal(LY_EVALID, lys_parse_in(UTEST_LYCTX, in, LYS_IN_YANG, NULL, NULL, &unres.creating, &mod1)); + lys_unres_glob_erase(&unres); + ly_in_free(in, 0); + CHECK_LOG_CTX("Parsing module \"y\" failed.", NULL, 0); + CHECK_LOG_CTX("Name collision between module and submodule of name \"y\".", NULL, 1); + + assert_int_equal(LY_SUCCESS, ly_in_new_memory("module a {namespace urn:a;prefix a;include y;revision 2018-10-30; }", &in)); + assert_int_equal(LY_SUCCESS, lys_parse_in(UTEST_LYCTX, in, LYS_IN_YANG, NULL, NULL, &unres.creating, &mod1)); + ly_in_free(in, 0); + assert_int_equal(LY_SUCCESS, ly_in_new_memory("module y {namespace urn:y;prefix y;}", &in)); + assert_int_equal(LY_EVALID, lys_parse_in(UTEST_LYCTX, in, LYS_IN_YANG, NULL, NULL, &unres.creating, &mod1)); + lys_unres_glob_erase(&unres); + ly_in_free(in, 0); + CHECK_LOG_CTX("Parsing module \"y\" failed.", NULL, 0); + CHECK_LOG_CTX("Name collision between module and submodule of name \"y\".", NULL, 1); + + ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, "submodule y {belongs-to b {prefix b;}}"); + assert_int_equal(LY_SUCCESS, ly_in_new_memory("module b {namespace urn:b;prefix b;include y;}", &in)); + assert_int_equal(LY_EVALID, lys_parse_in(UTEST_LYCTX, in, LYS_IN_YANG, NULL, NULL, &unres.creating, &mod1)); + lys_unres_glob_revert(UTEST_LYCTX, &unres); + lys_unres_glob_erase(&unres); + ly_in_free(in, 0); + CHECK_LOG_CTX("Parsing module \"b\" failed.", NULL, 0); + CHECK_LOG_CTX("Including \"y\" submodule into \"b\" failed.", NULL, 0); + CHECK_LOG_CTX("Parsing submodule failed.", NULL, 0); + CHECK_LOG_CTX("Name collision between submodules of name \"y\".", NULL, 1); + + /* selecting correct revision of the submodules */ + ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, "submodule y {belongs-to a {prefix a;} revision 2018-10-31;}"); + assert_int_equal(LY_SUCCESS, ly_in_new_memory("module a {namespace urn:a;prefix a;include y; revision 2018-10-31;}", &in)); + assert_int_equal(LY_SUCCESS, lys_parse_in(UTEST_LYCTX, in, LYS_IN_YANG, NULL, NULL, &unres.creating, &mod2)); + lys_unres_glob_erase(&unres); + ly_in_free(in, 0); + assert_string_equal("2018-10-31", mod2->parsed->includes[0].submodule->revs[0].date); + + /* reloading module in case only the compiled module resists in the context */ + assert_int_equal(LY_SUCCESS, ly_in_new_memory("module w {namespace urn:w;prefix w;revision 2018-10-24;}", &in)); + assert_int_equal(LY_SUCCESS, lys_parse(UTEST_LYCTX, in, LYS_IN_YANG, NULL, &mod1)); + ly_in_free(in, 0); + assert_non_null(mod1->compiled); + assert_non_null(mod1->parsed); + + assert_int_equal(LY_SUCCESS, ly_in_new_memory("module z {namespace urn:z;prefix z;import w {prefix w;revision-date 2018-10-24;}}", &in)); + ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, "module w {namespace urn:w;prefix w;revision 2018-10-24;}"); + assert_int_equal(LY_SUCCESS, lys_parse(UTEST_LYCTX, in, LYS_IN_YANG, NULL, &mod2)); + ly_in_free(in, 0); + assert_non_null(mod2); + assert_non_null(mod1->parsed); + assert_string_equal("w", mod1->name); +} + +static void +test_imports(void **state) +{ + struct lys_module *mod1, *mod2, *mod3, *import; + char *str; + uint16_t ctx_options; + + /* use own context with extra flags */ + ly_ctx_destroy(UTEST_LYCTX); + ctx_options = LY_CTX_DISABLE_SEARCHDIRS | LY_CTX_NO_YANGLIBRARY; + + /* Import callback provides newer revision of module 'a', + * however the older revision is implemented soon and therefore it is preferred. */ + assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, ctx_options, &UTEST_LYCTX)); + ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, "module a {namespace urn:a; prefix a; revision 2019-09-17;}"); + assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module a {namespace urn:a;prefix a;revision 2019-09-16;}", + LYS_IN_YANG, &mod1)); + assert_true(LYS_MOD_LATEST_REV & mod1->latest_revision); + assert_int_equal(1, mod1->implemented); + assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module b {namespace urn:b;prefix b;import a {prefix a;}}", + LYS_IN_YANG, &mod2)); + assert_ptr_equal(mod1, mod2->parsed->imports[0].module); + assert_true((LYS_MOD_LATEST_REV | LYS_MOD_IMPORTED_REV) & mod1->latest_revision); + assert_string_equal("2019-09-16", mod1->revision); + assert_int_equal(1, mod1->implemented); + assert_non_null(ly_ctx_get_module(UTEST_LYCTX, "a", "2019-09-16")); + ly_ctx_destroy(UTEST_LYCTX); + + /* Import callback provides older revision of module 'a' and it is + * imported by another module, so it is preferred even if newer + * revision is implemented later. */ + assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, ctx_options, &UTEST_LYCTX)); + ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, "module a {namespace urn:a; prefix a; revision 2019-09-16;}"); + assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module b {namespace urn:b;prefix b;import a {prefix a;}}", + LYS_IN_YANG, &mod2)); + assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module a {namespace urn:a;prefix a;revision 2019-09-17;}", + LYS_IN_YANG, &mod1)); + ly_log_level(LY_LLVRB); + assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module c {namespace urn:c;prefix c;import a {prefix a;}}", + LYS_IN_YANG, &mod3)); + CHECK_LOG_LASTMSG("Implemented module \"a@2019-09-17\" is not used for import, revision \"2019-09-16\" is imported instead."); + ly_log_level(LY_LLWRN); + assert_true(LYS_MOD_LATEST_SEARCHDIRS & mod1->latest_revision); + assert_int_equal(1, mod1->implemented); + import = mod2->parsed->imports[0].module; + assert_true(LYS_MOD_IMPORTED_REV & import->latest_revision); + assert_string_equal("2019-09-16", import->revision); + assert_int_equal(0, import->implemented); + import = mod3->parsed->imports[0].module; + assert_string_equal("2019-09-16", import->revision); + assert_non_null(ly_ctx_get_module(UTEST_LYCTX, "a", "2019-09-16")); + assert_non_null(ly_ctx_get_module(UTEST_LYCTX, "a", "2019-09-17")); + assert_string_equal("2019-09-17", ly_ctx_get_module_implemented(UTEST_LYCTX, "a")->revision); + ly_ctx_destroy(UTEST_LYCTX); + + /* check of circular dependency */ + assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, ctx_options, &UTEST_LYCTX)); + str = "module a {namespace urn:a; prefix a;" + "import b {prefix b;}" + "}"; + ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, str); + str = "module b { yang-version 1.1; namespace urn:b; prefix b;" + "import a {prefix a;}" + "}"; + assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL)); + ly_err_clean(UTEST_LYCTX, NULL); +} + +static void +test_get_models(void **state) +{ + struct lys_module *mod, *mod2; + const char *str0 = "module a {namespace urn:a;prefix a;}"; + const char *str1 = "module a {namespace urn:a;prefix a;revision 2018-10-23;}"; + const char *str2 = "module a {namespace urn:a;prefix a;revision 2018-10-23;revision 2018-10-24;}"; + struct ly_in *in0, *in1, *in2; + struct lys_glob_unres unres = {0}; + + unsigned int index = 0; + const char *names[] = { + "ietf-yang-metadata", "yang", "ietf-inet-types", "ietf-yang-types", "ietf-yang-schema-mount", + "ietf-yang-structure-ext", "ietf-datastores", "ietf-yang-library", "a", "a", "a" + }; + + assert_int_equal(LY_SUCCESS, ly_in_new_memory(str0, &in0)); + assert_int_equal(LY_SUCCESS, ly_in_new_memory(str1, &in1)); + assert_int_equal(LY_SUCCESS, ly_in_new_memory(str2, &in2)); + + /* invalid arguments */ + assert_ptr_equal(NULL, ly_ctx_get_module(NULL, NULL, NULL)); + CHECK_LOG_LASTMSG("Invalid argument ctx (ly_ctx_get_module())."); + assert_ptr_equal(NULL, ly_ctx_get_module(UTEST_LYCTX, NULL, NULL)); + CHECK_LOG_CTX("Invalid argument name (ly_ctx_get_module()).", NULL, 0); + assert_ptr_equal(NULL, ly_ctx_get_module_ns(NULL, NULL, NULL)); + CHECK_LOG_LASTMSG("Invalid argument ctx (ly_ctx_get_module_ns())."); + assert_ptr_equal(NULL, ly_ctx_get_module_ns(UTEST_LYCTX, NULL, NULL)); + CHECK_LOG_CTX("Invalid argument ns (ly_ctx_get_module_ns()).", NULL, 0); + assert_null(ly_ctx_get_module(UTEST_LYCTX, "nonsence", NULL)); + + /* internal modules */ + assert_null(ly_ctx_get_module_implemented(UTEST_LYCTX, "ietf-yang-types")); + mod = ly_ctx_get_module_implemented(UTEST_LYCTX, "yang"); + assert_non_null(mod); + assert_non_null(mod->parsed); + assert_string_equal("yang", mod->name); + mod2 = ly_ctx_get_module_implemented_ns(UTEST_LYCTX, mod->ns); + assert_ptr_equal(mod, mod2); + assert_non_null(ly_ctx_get_module(UTEST_LYCTX, "ietf-yang-metadata", "2016-08-05")); + assert_non_null(ly_ctx_get_module(UTEST_LYCTX, "ietf-yang-types", "2013-07-15")); + assert_non_null(ly_ctx_get_module(UTEST_LYCTX, "ietf-inet-types", "2013-07-15")); + assert_non_null(ly_ctx_get_module_ns(UTEST_LYCTX, "urn:ietf:params:xml:ns:yang:ietf-datastores", "2018-02-14")); + + /* select module by revision */ + assert_int_equal(LY_SUCCESS, lys_parse(UTEST_LYCTX, in1, LYS_IN_YANG, NULL, &mod)); + /* invalid attempts - implementing module of the same name and inserting the same module */ + assert_int_equal(LY_SUCCESS, lys_parse_in(UTEST_LYCTX, in2, LYS_IN_YANG, NULL, NULL, &unres.creating, &mod2)); + assert_int_equal(LY_EDENIED, lys_implement(mod2, NULL, &unres)); + CHECK_LOG_CTX("Module \"a@2018-10-24\" is already implemented in revision \"2018-10-23\".", NULL, 0); + lys_unres_glob_erase(&unres); + ly_in_reset(in1); + /* it is already there, fine */ + assert_int_equal(LY_SUCCESS, lys_parse_in(UTEST_LYCTX, in1, LYS_IN_YANG, NULL, NULL, &unres.creating, NULL)); + /* insert the second module only as imported, not implemented */ + lys_unres_glob_erase(&unres); + ly_in_reset(in2); + assert_int_equal(LY_SUCCESS, lys_parse_in(UTEST_LYCTX, in2, LYS_IN_YANG, NULL, NULL, &unres.creating, &mod2)); + lys_unres_glob_erase(&unres); + assert_non_null(mod2); + assert_ptr_not_equal(mod, mod2); + mod = ly_ctx_get_module_latest(UTEST_LYCTX, "a"); + assert_ptr_equal(mod, mod2); + mod2 = ly_ctx_get_module_latest_ns(UTEST_LYCTX, mod->ns); + assert_ptr_equal(mod, mod2); + /* work with module with no revision */ + assert_int_equal(LY_SUCCESS, lys_parse_in(UTEST_LYCTX, in0, LYS_IN_YANG, NULL, NULL, &unres.creating, &mod)); + lys_unres_glob_erase(&unres); + assert_ptr_equal(mod, ly_ctx_get_module(UTEST_LYCTX, "a", NULL)); + assert_ptr_not_equal(mod, ly_ctx_get_module_latest(UTEST_LYCTX, "a")); + + str1 = "submodule b {belongs-to a {prefix a;}}"; + ly_in_free(in1, 0); + assert_int_equal(LY_SUCCESS, ly_in_new_memory(str1, &in1)); + assert_int_equal(LY_EINVAL, lys_parse_in(UTEST_LYCTX, in1, LYS_IN_YANG, NULL, NULL, &unres.creating, &mod)); + CHECK_LOG_CTX("Input data contains submodule which cannot be parsed directly without its main module.", NULL, 0); + lys_unres_glob_erase(&unres); + + while ((mod = (struct lys_module *)ly_ctx_get_module_iter(UTEST_LYCTX, &index))) { + assert_string_equal(names[index - 1], mod->name); + } + assert_int_equal(11, index); + + /* cleanup */ + ly_in_free(in0, 0); + ly_in_free(in1, 0); + ly_in_free(in2, 0); +} + +static void +test_ylmem(void **state) +{ +#define DATA_YANG_LIBRARY_START "<yang-library xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"\ + " <module-set>\n"\ + " <name>complete</name>\n"\ + " <module>\n"\ + " <name>yang</name>\n"\ + " <revision>2022-06-16</revision>\n"\ + " <namespace>urn:ietf:params:xml:ns:yang:1</namespace>\n"\ + " </module>\n"\ + " <module>\n"\ + " <name>ietf-yang-library</name>\n"\ + " <revision>2019-01-04</revision>\n"\ + " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace>\n"\ + " </module>\n" + +#define DATA_YANG_BASE_IMPORTS " <import-only-module>\n"\ + " <name>ietf-yang-metadata</name>\n"\ + " <revision>2016-08-05</revision>\n"\ + " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-metadata</namespace>\n"\ + " </import-only-module>\n"\ + " <import-only-module>\n"\ + " <name>ietf-inet-types</name>\n"\ + " <revision>2013-07-15</revision>\n"\ + " <namespace>urn:ietf:params:xml:ns:yang:ietf-inet-types</namespace>\n"\ + " </import-only-module>\n"\ + " <import-only-module>\n"\ + " <name>ietf-yang-types</name>\n"\ + " <revision>2013-07-15</revision>\n"\ + " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-types</namespace>\n"\ + " </import-only-module>\n"\ + " <import-only-module>\n"\ + " <name>ietf-datastores</name>\n"\ + " <revision>2018-02-14</revision>\n"\ + " <namespace>urn:ietf:params:xml:ns:yang:ietf-datastores</namespace>\n"\ + " </import-only-module>\n" + +#define DATA_YANG_SCHEMA_MODULE_STATE " </module-set>\n"\ + " <schema>\n"\ + " <name>complete</name>\n"\ + " <module-set>complete</module-set>\n"\ + " </schema>\n"\ + " <content-id>9</content-id>\n"\ + "</yang-library>\n"\ + "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"\ + " <module-set-id>12</module-set-id>\n"\ + " <module>\n"\ + " <name>ietf-yang-metadata</name>\n"\ + " <revision>2016-08-05</revision>\n"\ + " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-metadata</namespace>\n"\ + " <conformance-type>import</conformance-type>\n"\ + " </module>\n"\ + " <module>\n"\ + " <name>yang</name>\n"\ + " <revision>2022-06-16</revision>\n"\ + " <namespace>urn:ietf:params:xml:ns:yang:1</namespace>\n"\ + " <conformance-type>implement</conformance-type>\n"\ + " </module>\n"\ + " <module>\n"\ + " <name>ietf-inet-types</name>\n"\ + " <revision>2013-07-15</revision>\n"\ + " <namespace>urn:ietf:params:xml:ns:yang:ietf-inet-types</namespace>\n"\ + " <conformance-type>import</conformance-type>\n"\ + " </module>\n"\ + " <module>\n"\ + " <name>ietf-yang-types</name>\n"\ + " <revision>2013-07-15</revision>\n"\ + " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-types</namespace>\n"\ + " <conformance-type>import</conformance-type>\n"\ + " </module>\n"\ + " <module>\n"\ + " <name>ietf-yang-library</name>\n"\ + " <revision>2019-01-04</revision>\n"\ + " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace>\n"\ + " <conformance-type>implement</conformance-type>\n"\ + " </module>\n"\ + " <module>\n"\ + " <name>ietf-datastores</name>\n"\ + " <revision>2018-02-14</revision>\n"\ + " <namespace>urn:ietf:params:xml:ns:yang:ietf-datastores</namespace>\n"\ + " <conformance-type>import</conformance-type>\n"\ + " </module>\n" + + const char *yanglibrary_only = + DATA_YANG_LIBRARY_START + DATA_YANG_BASE_IMPORTS + DATA_YANG_SCHEMA_MODULE_STATE + "</modules-state>\n"; + + const char *with_netconf = + DATA_YANG_LIBRARY_START + " <module>\n" + " <name>ietf-netconf</name>\n" + " <revision>2011-06-01</revision>\n" + " <namespace>urn:ietf:params:xml:ns:netconf:base:1.0</namespace>\n" + " </module>\n" + DATA_YANG_BASE_IMPORTS + " <import-only-module>\n" + " <name>ietf-netconf-acm</name>\n" + " <revision>2018-02-14</revision>\n" + " <namespace>urn:ietf:params:xml:ns:yang:ietf-netconf-acm</namespace>\n" + " </import-only-module>\n" + DATA_YANG_SCHEMA_MODULE_STATE + " <module>\n" + " <name>ietf-netconf</name>\n" + " <revision>2011-06-01</revision>\n" + " <namespace>urn:ietf:params:xml:ns:netconf:base:1.0</namespace>\n" + " <conformance-type>implement</conformance-type>\n" + " </module>\n" + " <module>\n" + " <name>ietf-netconf-acm</name>\n" + " <revision>2018-02-14</revision>\n" + " <namespace>urn:ietf:params:xml:ns:yang:ietf-netconf-acm</namespace>\n" + " <conformance-type>import</conformance-type>\n" + " </module>\n" + "</modules-state>"; + + char *with_netconf_features = malloc(8096); + + strcpy(with_netconf_features, + DATA_YANG_LIBRARY_START + " <module>\n" + " <name>ietf-netconf</name>\n" + " <revision>2011-06-01</revision>\n" + " <namespace>urn:ietf:params:xml:ns:netconf:base:1.0</namespace>\n" + " <feature>writable-running</feature>\n" + " <feature>candidate</feature>\n" + " <feature>confirmed-commit</feature>\n" + " <feature>rollback-on-error</feature>\n" + " <feature>validate</feature>\n" + " <feature>startup</feature>\n" + " <feature>url</feature>\n" + " <feature>xpath</feature>\n" + " </module>\n" + " <import-only-module>\n" + " <name>ietf-yang-metadata</name>\n" + " <revision>2016-08-05</revision>\n" + " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-metadata</namespace>\n" + " </import-only-module>\n" + " <import-only-module>\n" + " <name>ietf-inet-types</name>\n" + " <revision>2013-07-15</revision>\n" + " <namespace>urn:ietf:params:xml:ns:yang:ietf-inet-types</namespace>\n" + " </import-only-module>\n" + " <import-only-module>\n" + " <name>ietf-yang-types</name>\n" + " <revision>2013-07-15</revision>\n" + " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-types</namespace>\n" + " </import-only-module>\n" + " <import-only-module>\n" + " <name>ietf-datastores</name>\n" + " <revision>2018-02-14</revision>\n" + " <namespace>urn:ietf:params:xml:ns:yang:ietf-datastores</namespace>\n" + " </import-only-module>\n" + " <import-only-module>\n" + " <name>ietf-netconf-acm</name>\n" + " <revision>2018-02-14</revision>\n" + " <namespace>urn:ietf:params:xml:ns:yang:ietf-netconf-acm</namespace>\n" + " </import-only-module>\n"); + strcpy(with_netconf_features + strlen(with_netconf_features), + DATA_YANG_SCHEMA_MODULE_STATE + " <module>\n" + " <name>ietf-netconf</name>\n" + " <revision>2011-06-01</revision>\n" + " <namespace>urn:ietf:params:xml:ns:netconf:base:1.0</namespace>\n" + " <feature>writable-running</feature>\n" + " <feature>candidate</feature>\n" + " <feature>confirmed-commit</feature>\n" + " <feature>rollback-on-error</feature>\n" + " <feature>validate</feature>\n" + " <feature>startup</feature>\n" + " <feature>url</feature>\n" + " <feature>xpath</feature>\n" + " <conformance-type>implement</conformance-type>\n" + " </module>\n" + " <module>\n" + " <name>ietf-netconf-acm</name>\n" + " <revision>2018-02-14</revision>\n" + " <namespace>urn:ietf:params:xml:ns:yang:ietf-netconf-acm</namespace>\n" + " <conformance-type>import</conformance-type>\n" + " </module>\n" + "</modules-state>"); + + const char *garbage_revision = + "<yang-library xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n" + " <module-set>\n" + " <name>complete</name>\n" + " <module>\n" + " <name>yang</name>\n" + " <revision>2022-06-16</revision>\n" + " <namespace>urn:ietf:params:xml:ns:yang:1</namespace>\n" + " </module>\n" + " <module>\n" + " <name>ietf-yang-library</name>\n" + " <revision>2019-01-01</revision>\n" + " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace>\n" + " </module>\n" + DATA_YANG_BASE_IMPORTS + DATA_YANG_SCHEMA_MODULE_STATE + "</modules-state>\n"; + + const char *no_yanglibrary = + "<yang-library xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n" + " <module-set>\n" + " <name>complete</name>\n" + " <module>\n" + " <name>yang</name>\n" + " <revision>2022-06-16</revision>\n" + " <namespace>urn:ietf:params:xml:ns:yang:1</namespace>\n" + " </module>\n" + DATA_YANG_BASE_IMPORTS + DATA_YANG_SCHEMA_MODULE_STATE + "</modules-state>\n"; + + (void) state; + /* seperate context to avoid double free during teadown */ + struct ly_ctx *ctx_test = NULL; + + /* test invalid parameters */ + assert_int_equal(LY_EINVAL, ly_ctx_new_ylpath(NULL, NULL, LYD_XML, 0, &ctx_test)); + assert_int_equal(LY_EINVAL, ly_ctx_new_ylpath(NULL, TESTS_SRC, LYD_XML, 0, NULL)); + assert_int_equal(LY_ESYS, ly_ctx_new_ylpath(NULL, TESTS_SRC "garbage", LYD_XML, 0, &ctx_test)); + + /* basic test with ietf-yang-library-only */ + assert_int_equal(LY_SUCCESS, ly_ctx_new_ylmem(TESTS_SRC "/modules/yang/", yanglibrary_only, LYD_XML, 0, &ctx_test)); + assert_non_null(ly_ctx_get_module(ctx_test, "ietf-yang-library", "2019-01-04")); + assert_null(ly_ctx_get_module(ctx_test, "ietf-netconf", "2011-06-01")); + ly_ctx_destroy(ctx_test); + ctx_test = NULL; + + /* test loading module, should also import other module */ + assert_int_equal(LY_SUCCESS, ly_ctx_new_ylmem(TESTS_SRC "/modules/yang/", with_netconf, LYD_XML, 0, &ctx_test)); + assert_non_null(ly_ctx_get_module(ctx_test, "ietf-netconf", "2011-06-01")); + assert_int_equal(1, ly_ctx_get_module(ctx_test, "ietf-netconf", "2011-06-01")->implemented); + assert_non_null(ly_ctx_get_module(ctx_test, "ietf-netconf-acm", "2018-02-14")); + assert_int_equal(0, ly_ctx_get_module(ctx_test, "ietf-netconf-acm", "2018-02-14")->implemented); + assert_int_equal(LY_ENOT, lys_feature_value(ly_ctx_get_module(ctx_test, "ietf-netconf", "2011-06-01"), "url")); + ly_ctx_destroy(ctx_test); + ctx_test = NULL; + + /* test loading module with feature if they are present */ + assert_int_equal(LY_SUCCESS, ly_ctx_new_ylmem(TESTS_SRC "/modules/yang/", with_netconf_features, LYD_XML, 0, &ctx_test)); + assert_non_null(ly_ctx_get_module(ctx_test, "ietf-netconf", "2011-06-01")); + assert_non_null(ly_ctx_get_module(ctx_test, "ietf-netconf-acm", "2018-02-14")); + assert_int_equal(LY_SUCCESS, lys_feature_value(ly_ctx_get_module(ctx_test, "ietf-netconf", "2011-06-01"), "url")); + ly_ctx_destroy(ctx_test); + ctx_test = NULL; + + /* test with not matching revision */ + assert_int_equal(LY_EINVAL, ly_ctx_new_ylmem(TESTS_SRC "/modules/yang/", garbage_revision, LYD_XML, 0, &ctx_test)); + + /* test data containing ietf-yang-library which conflicts with the option */ + assert_int_equal(LY_EINVAL, ly_ctx_new_ylmem(TESTS_SRC "/modules/yang/", with_netconf_features, LYD_XML, LY_CTX_NO_YANGLIBRARY, &ctx_test)); + + /* test creating without ietf-yang-library */ + assert_int_equal(LY_SUCCESS, ly_ctx_new_ylmem(TESTS_SRC "/modules/yang/", no_yanglibrary, LYD_XML, LY_CTX_NO_YANGLIBRARY, &ctx_test)); + assert_int_equal(NULL, ly_ctx_get_module(ctx_test, "ietf-yang-library", "2019-01-04")); + ly_ctx_destroy(ctx_test); + free(with_netconf_features); +} + +static LY_ERR +check_node_priv_parsed_is_set(struct lysc_node *node, void *data, ly_bool *UNUSED(dfs_continue)) +{ + const struct lysp_node *pnode; + const char ***iter; + + pnode = (const struct lysp_node *)node->priv; + CHECK_POINTER(pnode, 1); + iter = (const char ***)data; + CHECK_POINTER(**iter, 1); + CHECK_STRING(pnode->name, **iter); + (*iter)++; + + return LY_SUCCESS; +} + +static LY_ERR +check_node_priv_parsed_not_set(struct lysc_node *node, void *UNUSED(data), ly_bool *UNUSED(dfs_continue)) +{ + CHECK_POINTER(node->priv, 0); + return LY_SUCCESS; +} + +static void +check_ext_instance_priv_parsed_is_set(struct lysc_ext_instance *ext) +{ + LY_ARRAY_COUNT_TYPE u, v; + struct lysc_ext_substmt *substmts; + struct lysc_node *cnode; + const char **iter; + const char *check[] = { + "tmp_cont", "lf", NULL + }; + + LY_ARRAY_FOR(ext, u) { + substmts = ext[u].substmts; + LY_ARRAY_FOR(substmts, v) { + if (substmts && substmts[v].storage && (substmts[v].stmt & LY_STMT_DATA_NODE_MASK)) { + cnode = *(struct lysc_node **)substmts[v].storage; + iter = check; + assert_int_equal(LY_SUCCESS, lysc_tree_dfs_full(cnode, check_node_priv_parsed_is_set, &iter)); + } + } + } +} + +static void +check_ext_instance_priv_parsed_not_set(struct lysc_ext_instance *ext) +{ + LY_ARRAY_COUNT_TYPE u, v; + struct lysc_ext_substmt *substmts; + struct lysc_node *cnode; + + LY_ARRAY_FOR(ext, u) { + substmts = ext[u].substmts; + LY_ARRAY_FOR(substmts, v) { + if (substmts && substmts[v].storage && (substmts[v].stmt & LY_STMT_DATA_NODE_MASK)) { + cnode = *(struct lysc_node **)substmts[v].storage; + if (cnode) { + CHECK_POINTER((struct lysp_node *)cnode->priv, 0); + } + } + } + } +} + +/** + * @brief Testing of LY_CTX_SET_PRIV_PARSED. + */ +static void +test_set_priv_parsed(void **state) +{ + struct lys_module *mod; + const char *schema_a; + const char **iter; + const char *check[] = { + "cont", "contnotif", "contx", "grpleaf", "augleaf", "l1", + "l1a", "l1b", "l1c", "foo1", "ll", "any", "l2", + "l2c", "l2cx", "ch", "cas", "casx", "oper", + "input", "inparam", "output", "outparam", "n1", NULL + }; + + /* each node must have a unique name. */ + schema_a = "module a {\n" + " namespace urn:tests:a;\n" + " prefix a;yang-version 1.1;\n" + "\n" + " import ietf-restconf {\n" + " prefix rc;\n" + " revision-date 2017-01-26;\n" + " }\n" + "\n" + " rc:yang-data \"tmp\" {\n" + " container tmp_cont {\n" + " leaf lf {\n" + " type string;\n" + " }\n" + " }\n" + " }\n" + " container cont {\n" + " notification contnotif;\n" + " leaf-list contx {\n" + " type string;\n" + " }\n" + " uses grp;\n" + " }\n" + " list l1 {\n" + " key \"l1a l1b\";\n" + " leaf l1a {\n" + " type string;\n" + " }\n" + " leaf l1b {\n" + " type string;\n" + " }\n" + " leaf l1c {\n" + " type string;\n" + " }\n" + " }\n" + " feature f1;\n" + " feature f2;\n" + " leaf foo1 {\n" + " type uint16;\n" + " if-feature f1;\n" + " }\n" + " leaf foo2 {\n" + " type uint16;\n" + " }\n" + " leaf foo3 {\n" + " type uint16;\n" + " if-feature f2;\n" + " }\n" + " leaf-list ll {\n" + " type string;\n" + " }\n" + " anydata any {\n" + " config false;\n" + " }\n" + " list l2 {\n" + " config false;\n" + " container l2c {\n" + " leaf l2cx {\n" + " type string;\n" + " }\n" + " }\n" + " }\n" + " choice ch {\n" + " case cas {\n" + " leaf casx {\n" + " type string;\n" + " }\n" + " }\n" + " }\n" + " rpc oper {\n" + " input {\n" + " leaf inparam {\n" + " type string;\n" + " }\n" + " }\n" + " output {\n" + " leaf outparam {\n" + " type int8;\n" + " }\n" + " }\n" + " }\n" + " notification n1;\n" + " grouping grp {\n" + " leaf grpleaf {\n" + " type uint16;\n" + " }\n" + " }\n" + " augment /cont {\n" + " leaf augleaf {\n" + " type uint16;\n" + " }\n" + " }\n" + " deviation /a:foo2 {\n" + " deviate not-supported;\n" + " }\n" + "}\n"; + + /* use own context with extra flags */ + ly_ctx_destroy(UTEST_LYCTX); + const char *feats[] = {"f1", NULL}; + + assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, LY_CTX_SET_PRIV_PARSED, &UTEST_LYCTX)); + assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_DIR_MODULES_YANG)); + assert_non_null(ly_ctx_load_module(UTEST_LYCTX, "ietf-restconf", "2017-01-26", NULL)); + UTEST_ADD_MODULE(schema_a, LYS_IN_YANG, feats, NULL); + + print_message("[ ] create context\n"); + mod = ly_ctx_get_module(UTEST_LYCTX, "a", NULL); + iter = check; + assert_int_equal(LY_SUCCESS, lysc_module_dfs_full(mod, check_node_priv_parsed_is_set, &iter)); + check_ext_instance_priv_parsed_is_set(mod->compiled->exts); + + print_message("[ ] unset option\n"); + assert_int_equal(LY_SUCCESS, ly_ctx_unset_options(UTEST_LYCTX, LY_CTX_SET_PRIV_PARSED)); + mod = ly_ctx_get_module(UTEST_LYCTX, "a", NULL); + iter = check; + assert_int_equal(LY_SUCCESS, lysc_module_dfs_full(mod, check_node_priv_parsed_not_set, &iter)); + check_ext_instance_priv_parsed_not_set(mod->compiled->exts); + + print_message("[ ] set option\n"); + assert_int_equal(LY_SUCCESS, ly_ctx_set_options(UTEST_LYCTX, LY_CTX_SET_PRIV_PARSED)); + mod = ly_ctx_get_module(UTEST_LYCTX, "a", NULL); + iter = check; + assert_int_equal(LY_SUCCESS, lysc_module_dfs_full(mod, check_node_priv_parsed_is_set, &iter)); + check_ext_instance_priv_parsed_is_set(mod->compiled->exts); +} + +static void +test_explicit_compile(void **state) +{ + uint32_t i; + struct lys_module *mod; + const char *schema_a = "module a {\n" + " namespace urn:tests:a;\n" + " prefix a;yang-version 1.1;\n" + " feature f1;\n" + " feature f2;\n" + " leaf foo1 {\n" + " type uint16;\n" + " if-feature f1;\n" + " }\n" + " leaf foo2 {\n" + " type uint16;\n" + " }\n" + " container cont {\n" + " leaf foo3 {\n" + " type string;\n" + " }\n" + " }\n" + "}\n"; + const char *schema_b = "module b {\n" + " namespace urn:tests:b;\n" + " prefix b;yang-version 1.1;\n" + " import a {\n" + " prefix a;\n" + " }\n" + " augment /a:cont {\n" + " leaf augleaf {\n" + " type uint16;\n" + " }\n" + " }\n" + "}\n"; + const char *schema_c = "module c {\n" + " namespace urn:tests:c;\n" + " prefix c;yang-version 1.1;\n" + " import a {\n" + " prefix a;\n" + " }\n" + " deviation /a:foo2 {\n" + " deviate not-supported;\n" + " }\n" + "}\n"; + + /* use own context with extra flags */ + ly_ctx_destroy(UTEST_LYCTX); + const char *feats[] = {"f1", NULL}; + + assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, LY_CTX_EXPLICIT_COMPILE, &UTEST_LYCTX)); + UTEST_ADD_MODULE(schema_a, LYS_IN_YANG, NULL, &mod); + UTEST_ADD_MODULE(schema_b, LYS_IN_YANG, NULL, NULL); + UTEST_ADD_MODULE(schema_c, LYS_IN_YANG, NULL, NULL); + assert_int_equal(LY_SUCCESS, lys_set_implemented((struct lys_module *)mod, feats)); + + /* none of the modules should be compiled */ + i = 0; + while ((mod = ly_ctx_get_module_iter(UTEST_LYCTX, &i))) { + assert_null(mod->compiled); + } + + assert_int_equal(LY_SUCCESS, ly_ctx_compile(UTEST_LYCTX)); + + /* check internal modules */ + mod = ly_ctx_get_module_implemented(UTEST_LYCTX, "yang"); + assert_non_null(mod); + mod = ly_ctx_get_module_implemented(UTEST_LYCTX, "ietf-datastores"); + assert_non_null(mod); + mod = ly_ctx_get_module_implemented(UTEST_LYCTX, "ietf-yang-library"); + assert_non_null(mod); + + /* check test modules */ + mod = ly_ctx_get_module_implemented(UTEST_LYCTX, "a"); + assert_non_null(mod); + mod = ly_ctx_get_module_implemented(UTEST_LYCTX, "b"); + assert_non_null(mod); + mod = ly_ctx_get_module_implemented(UTEST_LYCTX, "c"); + assert_non_null(mod); +} + +int +main(void) +{ + const struct CMUnitTest tests[] = { + UTEST(test_searchdirs), + UTEST(test_options), + UTEST(test_models), + UTEST(test_imports), + UTEST(test_get_models), + UTEST(test_ylmem), + UTEST(test_set_priv_parsed), + UTEST(test_explicit_compile), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} |