| /* |
| * @file test_libyang.c |
| * @author: Mislav Novakovic <mislav.novakovic@sartura.hr> |
| * @brief unit tests for functions from libyang.h header |
| * |
| * Copyright (C) 2016 Deutsche Telekom AG. |
| * |
| * Author: Mislav Novakovic <mislav.novakovic@sartura.hr> |
| * |
| * 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 |
| */ |
| |
| #include <stdarg.h> |
| #include <stddef.h> |
| #include <setjmp.h> |
| #include <cmocka.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <fcntl.h> |
| #include <sys/mman.h> |
| #include <unistd.h> |
| #include <string.h> |
| #include <limits.h> |
| |
| #include "../config.h" |
| #include "../../src/libyang.h" |
| |
| /* include private header to be able to check internal values */ |
| #include "../../src/context.h" |
| |
| struct ly_ctx *ctx = NULL; |
| struct lyd_node *root = NULL; |
| const struct lys_module *module = NULL; |
| |
| int |
| generic_init(char *config_file, char *yin_file, char *yang_file, char *yang_folder) |
| { |
| LYD_FORMAT in_format; |
| char *schema1 = NULL; |
| char *schema2 = NULL; |
| char *config = NULL; |
| struct stat sb_schema1, sb_schema2, sb_config; |
| int fd = -1; |
| |
| if (!config_file || !yang_file || !yin_file || !yang_folder) { |
| goto error; |
| } |
| |
| in_format = LYD_XML; |
| |
| ctx = ly_ctx_new(yang_folder); |
| if (!ctx) { |
| goto error; |
| } |
| |
| fd = open(yin_file, O_RDONLY); |
| if (fd == -1 || fstat(fd, &sb_schema1) == -1 || !S_ISREG(sb_schema1.st_mode)) { |
| goto error; |
| } |
| |
| schema1 = mmap(NULL, sb_schema1.st_size, PROT_READ, MAP_PRIVATE, fd, 0); |
| close(fd); |
| |
| fd = open(yang_file, O_RDONLY); |
| if (fd == -1 || fstat(fd, &sb_schema2) == -1 || !S_ISREG(sb_schema2.st_mode)) { |
| goto error; |
| } |
| |
| schema2 = mmap(NULL, sb_schema2.st_size + 2, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); |
| close(fd); |
| |
| fd = open(config_file, O_RDONLY); |
| if (fd == -1 || fstat(fd, &sb_config) == -1 || !S_ISREG(sb_config.st_mode)) { |
| goto error; |
| } |
| |
| config = mmap(NULL, sb_config.st_size, PROT_READ, MAP_PRIVATE, fd, 0); |
| close(fd); |
| fd = -1; |
| |
| if (!lys_parse_mem(ctx, schema1, LYS_IN_YIN)) { |
| goto error; |
| } |
| |
| if (!(module = lys_parse_mem(ctx, schema2, LYS_IN_YANG))) { |
| goto error; |
| } |
| |
| root = lyd_parse_mem(ctx, config, in_format, LYD_OPT_CONFIG | LYD_OPT_STRICT); |
| if (!root) { |
| goto error; |
| } |
| |
| /* cleanup */ |
| munmap(config, sb_config.st_size); |
| munmap(schema1, sb_schema1.st_size); |
| munmap(schema2, sb_schema2.st_size + 2); |
| |
| return 0; |
| |
| error: |
| if (schema1) { |
| munmap(schema1, sb_schema1.st_size); |
| } |
| if (schema2) { |
| munmap(schema2, sb_schema2.st_size + 2); |
| } |
| if (config) { |
| munmap(config, sb_config.st_size); |
| } |
| if (fd != -1) { |
| close(fd); |
| } |
| |
| return -1; |
| } |
| |
| static int |
| setup_f(void **state) |
| { |
| (void) state; /* unused */ |
| char *config_file = TESTS_DIR"/api/files/a.xml"; |
| char *yin_file = TESTS_DIR"/api/files/a.yin"; |
| char *yang_file = TESTS_DIR"/api/files/b.yang"; |
| char *yang_folder = TESTS_DIR"/api/files"; |
| int rc; |
| |
| rc = generic_init(config_file, yin_file, yang_file, yang_folder); |
| |
| if (rc) { |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| static int |
| teardown_f(void **state) |
| { |
| (void) state; /* unused */ |
| if (root) { |
| lyd_free_withsiblings(root); |
| } |
| |
| if (ctx) { |
| ly_ctx_destroy(ctx, NULL); |
| } |
| |
| root = NULL; |
| ctx = NULL; |
| |
| return 0; |
| } |
| |
| static void |
| test_ly_ctx_new(void **state) |
| { |
| char *yang_folder = TESTS_DIR"/data/files"; |
| (void) state; /* unused */ |
| ctx = ly_ctx_new(yang_folder); |
| if (!ctx) { |
| fail(); |
| } |
| |
| ly_ctx_destroy(ctx, NULL); |
| } |
| |
| static void |
| test_ly_ctx_new_invalid(void **state) |
| { |
| char *yang_folder = "INVALID_PATH"; |
| (void) state; /* unused */ |
| ctx = ly_ctx_new(yang_folder); |
| if (ctx) { |
| fail(); |
| } |
| } |
| |
| static void |
| test_ly_ctx_get_searchdirs(void **state) |
| { |
| const char * const *result; |
| char yang_folder[PATH_MAX]; |
| (void) state; /* unused */ |
| |
| assert_ptr_not_equal(realpath(TESTS_DIR"/data/files", yang_folder), NULL); |
| |
| ctx = ly_ctx_new(yang_folder); |
| if (!ctx) { |
| fail(); |
| } |
| |
| result = ly_ctx_get_searchdirs(ctx); |
| if (!result) { |
| fail(); |
| } |
| assert_string_equal(yang_folder, result[0]); |
| assert_ptr_equal(NULL, result[1]); |
| |
| ly_ctx_destroy(ctx, NULL); |
| } |
| |
| static void |
| test_ly_ctx_set_searchdir(void **state) |
| { |
| const char * const *result; |
| char yang_folder[PATH_MAX]; |
| char new_yang_folder[PATH_MAX]; |
| (void) state; /* unused */ |
| |
| assert_ptr_not_equal(realpath(TESTS_DIR"/data/files", yang_folder), NULL); |
| assert_ptr_not_equal(realpath(TESTS_DIR"/schema/yin", new_yang_folder), NULL); |
| |
| ctx = ly_ctx_new(yang_folder); |
| if (!ctx) { |
| fail(); |
| } |
| |
| ly_ctx_set_searchdir(ctx, new_yang_folder); |
| result = ly_ctx_get_searchdirs(ctx); |
| if (!result) { |
| fail(); |
| } |
| |
| assert_string_equal(yang_folder, result[0]); |
| assert_string_equal(new_yang_folder, result[1]); |
| assert_ptr_equal(NULL, result[2]); |
| |
| ly_ctx_destroy(ctx, NULL); |
| } |
| |
| static void |
| test_ly_ctx_set_searchdir_invalid(void **state) |
| { |
| const char * const *result; |
| char yang_folder[PATH_MAX]; |
| char *new_yang_folder = "INVALID_PATH"; |
| (void) state; /* unused */ |
| |
| assert_ptr_not_equal(realpath(TESTS_DIR"/data/files", yang_folder), NULL); |
| |
| ctx = ly_ctx_new(yang_folder); |
| if (!ctx) { |
| fail(); |
| } |
| |
| /* adding duplicity - the path is not duplicated */ |
| ly_ctx_set_searchdir(NULL, yang_folder); |
| result = ly_ctx_get_searchdirs(ctx); |
| if (!result) { |
| fail(); |
| } |
| assert_string_equal(yang_folder, result[0]); |
| assert_ptr_equal(NULL, result[1]); |
| |
| /* adding invalid path, previous is kept */ |
| ly_ctx_set_searchdir(ctx, new_yang_folder); |
| result = ly_ctx_get_searchdirs(ctx); |
| if (!result) { |
| fail(); |
| } |
| assert_string_equal(yang_folder, result[0]); |
| assert_ptr_equal(NULL, result[1]); |
| |
| ly_ctx_unset_searchdirs(ctx); |
| result = ly_ctx_get_searchdirs(ctx); |
| if (result) { |
| fail(); |
| } |
| |
| ly_ctx_destroy(ctx, NULL); |
| } |
| |
| static void |
| test_ly_ctx_info(void **state) |
| { |
| struct lyd_node *node; |
| (void) state; /* unused */ |
| |
| node = ly_ctx_info(NULL); |
| if (node) { |
| fail(); |
| } |
| |
| node = ly_ctx_info(ctx); |
| if (!node) { |
| fail(); |
| } |
| |
| assert_int_equal(LYD_VAL_OK, node->validity); |
| |
| lyd_free_withsiblings(node); |
| } |
| |
| static void |
| test_ly_ctx_get_module(void **state) |
| { |
| (void) state; /* unused */ |
| const struct lys_module *module; |
| const char *name1 = "a"; |
| const char *name2 = "b"; |
| const char *revision = "2016-03-01"; |
| |
| module = ly_ctx_get_module(NULL, name1, NULL); |
| if (module) { |
| fail(); |
| } |
| |
| module = ly_ctx_get_module(ctx, NULL, NULL); |
| if (module) { |
| fail(); |
| } |
| |
| module = ly_ctx_get_module(ctx, "invalid", NULL); |
| if (module) { |
| fail(); |
| } |
| |
| module = ly_ctx_get_module(ctx, name1, NULL); |
| if (!module) { |
| fail(); |
| } |
| |
| assert_string_equal("a", module->name); |
| |
| module = ly_ctx_get_module(ctx, name1, "invalid"); |
| if (module) { |
| fail(); |
| } |
| |
| module = ly_ctx_get_module(ctx, name1, revision); |
| if (!module) { |
| fail(); |
| } |
| |
| assert_string_equal(revision, module->rev->date); |
| |
| module = ly_ctx_get_module(ctx, name2, NULL); |
| if (!module) { |
| fail(); |
| } |
| |
| assert_string_equal("b", module->name); |
| |
| module = ly_ctx_get_module(ctx, name2, "invalid"); |
| if (module) { |
| fail(); |
| } |
| |
| module = ly_ctx_get_module(ctx, name2, revision); |
| if (!module) { |
| fail(); |
| } |
| |
| assert_string_equal(revision, module->rev->date); |
| } |
| |
| static void |
| test_ly_ctx_get_module_older(void **state) |
| { |
| (void) state; /* unused */ |
| const struct lys_module *module = NULL; |
| const struct lys_module *module_older = NULL; |
| const char *name = "a"; |
| const char *revision = "2016-03-01"; |
| const char *revision_older = "2015-01-01"; |
| |
| module_older = ly_ctx_get_module_older(NULL, module); |
| if (module_older) { |
| fail(); |
| } |
| |
| module_older = ly_ctx_get_module_older(ctx, NULL); |
| if (module_older) { |
| fail(); |
| } |
| |
| module = ly_ctx_load_module(ctx, "c", NULL); |
| if (!module) { |
| fail(); |
| } |
| |
| module = ly_ctx_load_module(ctx, name, revision); |
| if (!module) { |
| fail(); |
| } |
| |
| module_older = ly_ctx_get_module_older(ctx, module); |
| if (!module_older) { |
| fail(); |
| } |
| |
| assert_string_equal(revision_older, module_older->rev->date); |
| } |
| |
| static void |
| test_ly_ctx_load_module(void **state) |
| { |
| (void) state; /* unused */ |
| const struct lys_module *module; |
| const char *name = "a"; |
| const char *revision = "2015-01-01"; |
| |
| module = ly_ctx_load_module(NULL, name, revision); |
| if (module) { |
| fail(); |
| } |
| |
| module = ly_ctx_load_module(ctx, NULL, revision); |
| if (module) { |
| fail(); |
| } |
| |
| module = ly_ctx_load_module(ctx, "INVALID_NAME", revision); |
| if (module) { |
| fail(); |
| } |
| |
| module = ly_ctx_load_module(ctx, "c", NULL); |
| if (!module) { |
| fail(); |
| } |
| |
| assert_string_equal("c", module->name); |
| |
| module = ly_ctx_get_module(ctx, "a", revision); |
| if (!module) { |
| fail(); |
| } |
| |
| assert_string_equal("a", module->name); |
| |
| module = ly_ctx_get_module(ctx, "b", revision); |
| if (!module) { |
| fail(); |
| } |
| |
| assert_string_equal("b", module->name); |
| } |
| |
| static void |
| test_ly_ctx_clean(void **state) |
| { |
| (void) state; /* unused */ |
| const struct lys_module *mod; |
| struct ly_ctx *ctx; |
| uint32_t dict_used; |
| uint16_t setid; |
| int modules_count; |
| |
| ctx = ly_ctx_new(TESTS_DIR"/api/files/"); |
| /* remember starting values */ |
| setid = ctx->models.module_set_id; |
| modules_count = ctx->models.used; |
| dict_used = ctx->dict.used; |
| |
| /* add a module */ |
| mod = ly_ctx_load_module(ctx, "x", NULL); |
| assert_ptr_not_equal(mod, NULL); |
| assert_int_equal(modules_count + 1, ctx->models.used); |
| assert_int_not_equal(dict_used, ctx->dict.used); |
| |
| /* clean the context */ |
| ly_ctx_clean(ctx, NULL); |
| assert_int_equal(setid + 2, ctx->models.module_set_id); |
| assert_int_equal(modules_count, ctx->models.used); |
| assert_int_equal(dict_used, ctx->dict.used); |
| |
| /* add a module again ... */ |
| mod = ly_ctx_load_module(ctx, "x", NULL); |
| assert_ptr_not_equal(mod, NULL); |
| assert_int_equal(modules_count + 1, ctx->models.used); |
| assert_int_not_equal(dict_used, ctx->dict.used); |
| /* .. and add some string into dictionary */ |
| assert_ptr_not_equal(lydict_insert(ctx, "qwertyuiop", 0), NULL); |
| |
| /* clean the context */ |
| ly_ctx_clean(ctx, NULL); |
| assert_int_equal(setid + 4, ctx->models.module_set_id); |
| assert_int_equal(modules_count, ctx->models.used); |
| assert_int_equal(dict_used + 1, ctx->dict.used); |
| |
| /* cleanup */ |
| ly_ctx_destroy(ctx, NULL); |
| } |
| |
| static void |
| test_ly_ctx_clean2(void **state) |
| { |
| (void) state; /* unused */ |
| const char *yang_dep = "module x {" |
| " namespace uri:x;" |
| " prefix x;" |
| " import ietf-yang-library { prefix yl; }" |
| " leaf x { config false; type leafref { path /yl:modules-state/yl:module/yl:name; } } }"; |
| struct ly_ctx *ctx; |
| const struct lys_module *mod; |
| struct lys_node_leaf *leaf; |
| |
| ctx = ly_ctx_new(NULL); |
| assert_ptr_not_equal(ctx, NULL); |
| |
| /* load module depending by leafref on internal ietf-yang-library */ |
| assert_ptr_not_equal(lys_parse_mem(ctx, yang_dep, LYS_IN_YANG), NULL); |
| |
| /* get the target leaf in ietf-yang-library */ |
| mod = ctx->models.list[4]; |
| /* magic: leaf = /yl:modules-state/yl:module/yl:name */ |
| leaf = (struct lys_node_leaf *)mod->data->next->child->next->child->prev->child->child; |
| assert_true(leaf->backlinks && leaf->backlinks->number == 1); |
| |
| /* clean the context ... */ |
| ly_ctx_clean(ctx, NULL); |
| |
| /* ... and check that the leafref backlinks are removed */ |
| assert_true(!leaf->backlinks || !leaf->backlinks->number); |
| |
| /* cleanup */ |
| ly_ctx_destroy(ctx, NULL); |
| } |
| |
| static void |
| test_ly_ctx_remove_module(void **state) |
| { |
| (void) state; /* unused */ |
| const struct lys_module *mod; |
| uint32_t dict_used; |
| uint16_t setid; |
| int modules_count; |
| |
| ctx = ly_ctx_new(TESTS_DIR"/api/files/"); |
| /* remember starting values */ |
| setid = ctx->models.module_set_id; |
| modules_count = ctx->models.used; |
| dict_used = ctx->dict.used; |
| |
| mod = ly_ctx_load_module(ctx, "x", NULL); |
| ly_ctx_remove_module(mod, NULL); |
| |
| /* add a module */ |
| mod = ly_ctx_load_module(ctx, "y", NULL); |
| assert_ptr_not_equal(mod, NULL); |
| assert_true(setid < ctx->models.module_set_id); |
| setid = ctx->models.module_set_id; |
| assert_int_equal(modules_count + 2, ctx->models.used); |
| assert_int_not_equal(dict_used, ctx->dict.used); |
| |
| /* remove the imported module (x), that should cause removing also the loaded module (y) */ |
| mod = ly_ctx_get_module(ctx, "x", NULL); |
| assert_ptr_not_equal(mod, NULL); |
| ly_ctx_remove_module(mod, NULL); |
| assert_true(setid < ctx->models.module_set_id); |
| setid = ctx->models.module_set_id; |
| assert_int_equal(modules_count, ctx->models.used); |
| assert_int_equal(dict_used, ctx->dict.used); |
| |
| /* add a module again ... */ |
| mod = ly_ctx_load_module(ctx, "y", NULL); |
| assert_ptr_not_equal(mod, NULL); |
| assert_true(setid < ctx->models.module_set_id); |
| setid = ctx->models.module_set_id; |
| assert_int_equal(modules_count + 2, ctx->models.used); |
| assert_int_not_equal(dict_used, ctx->dict.used); |
| /* ... now remove the loaded module, the imported module is supposed to be removed because it is not |
| * used in any other module */ |
| ly_ctx_remove_module(mod, NULL); |
| assert_true(setid < ctx->models.module_set_id); |
| setid = ctx->models.module_set_id; |
| assert_int_equal(modules_count, ctx->models.used); |
| assert_int_equal(dict_used, ctx->dict.used); |
| |
| /* add a module again ... */ |
| mod = ly_ctx_load_module(ctx, "y", NULL); |
| assert_ptr_not_equal(mod, NULL); |
| assert_true(setid < ctx->models.module_set_id); |
| setid = ctx->models.module_set_id; |
| assert_int_equal(modules_count + 2, ctx->models.used); |
| assert_int_not_equal(dict_used, ctx->dict.used); |
| /* and mark even the imported module 'x' as implemented ... */ |
| assert_int_equal(lys_set_implemented(mod->imp[0].module), EXIT_SUCCESS); |
| /* ... now remove the loaded module, the imported module is supposed to be kept because it is implemented */ |
| ly_ctx_remove_module(mod, NULL); |
| assert_true(setid < ctx->models.module_set_id); |
| setid = ctx->models.module_set_id; |
| assert_int_equal(modules_count + 1, ctx->models.used); |
| assert_int_not_equal(dict_used, ctx->dict.used); |
| ly_ctx_clean(ctx, NULL); |
| |
| /* add a module again ... */ |
| mod = ly_ctx_load_module(ctx, "y", NULL); |
| assert_true(setid < ctx->models.module_set_id); |
| setid = ctx->models.module_set_id; |
| assert_int_equal(modules_count + 2, ctx->models.used); |
| assert_int_not_equal(dict_used, ctx->dict.used); |
| /* and add another one also importing module 'x' ... */ |
| assert_ptr_not_equal(ly_ctx_load_module(ctx, "z", NULL), NULL); |
| assert_true(setid < ctx->models.module_set_id); |
| setid = ctx->models.module_set_id; |
| assert_int_equal(modules_count + 3, ctx->models.used); |
| /* ... now remove the first loaded module, the imported module is supposed to be kept because it is used |
| * by the second loaded module */ |
| ly_ctx_remove_module(mod, NULL); |
| assert_true(setid < ctx->models.module_set_id); |
| setid = ctx->models.module_set_id; |
| assert_int_equal(modules_count + 2, ctx->models.used); |
| assert_int_not_equal(dict_used, ctx->dict.used); |
| } |
| |
| static void |
| test_ly_ctx_remove_module2(void **state) |
| { |
| (void) state; /* unused */ |
| const char *yang_main = "module x {" |
| " namespace uri:x;" |
| " prefix x;" |
| " feature x;" |
| " identity basex;" |
| " leaf x { type string; } }"; |
| const char *yang_dep = "module y {" |
| " namespace uri:y;" |
| " prefix y;" |
| " import x { prefix x; }" |
| " feature y { if-feature x:x; }" |
| " identity y { base x:basex; }" |
| " leaf y { type leafref { path /x:x; } } }"; |
| const struct lys_module *mod; |
| struct lys_node_leaf *leaf; |
| |
| ctx = ly_ctx_new(NULL); |
| assert_ptr_not_equal(ctx, NULL); |
| |
| /* load both modules, y depends on x and x will contain several backlinks to y */ |
| assert_ptr_not_equal((mod = lys_parse_mem(ctx, yang_main, LYS_IN_YANG)), NULL); |
| assert_ptr_not_equal(lys_parse_mem(ctx, yang_dep, LYS_IN_YANG), NULL); |
| |
| /* check that there are the expected backlinks */ |
| leaf = (struct lys_node_leaf *)mod->data; |
| assert_true(mod->features[0].depfeatures && mod->features[0].depfeatures->number); |
| assert_true(mod->ident[0].der && mod->ident[0].der->number); |
| assert_true(leaf->backlinks && leaf->backlinks->number); |
| |
| /* remove y ... */ |
| mod = ly_ctx_get_module(ctx, "y", NULL); |
| assert_ptr_not_equal(mod, NULL); |
| assert_int_equal(ly_ctx_remove_module(mod, NULL), 0); |
| |
| /* ... make sure that x is still present ... */ |
| mod = ly_ctx_get_module(ctx, "x", NULL); |
| assert_ptr_not_equal(mod, NULL); |
| leaf = (struct lys_node_leaf *)mod->data; |
| |
| /* ... and check that the backlinks in it were removed */ |
| assert_true(!mod->features[0].depfeatures || !mod->features[0].depfeatures->number); |
| assert_true(!mod->ident[0].der || !mod->ident[0].der->number); |
| assert_true(!leaf->backlinks || !leaf->backlinks->number); |
| } |
| |
| static void |
| test_lys_set_enabled(void **state) |
| { |
| (void) state; /* unused */ |
| const struct lys_module *mod; |
| |
| ctx = ly_ctx_new(NULL); |
| assert_ptr_not_equal(ctx, NULL); |
| |
| /* test failures - invalid input */ |
| assert_int_not_equal(lys_set_enabled(NULL), 0); |
| |
| /* test success - enabled module */ |
| mod = ly_ctx_get_module(ctx, "ietf-yang-library", NULL); |
| assert_ptr_not_equal(mod, NULL); |
| assert_int_equal(lys_set_enabled(mod), 0); |
| } |
| |
| /* include also some test for lys_set_enabled() */ |
| static void |
| test_lys_set_disabled(void **state) |
| { |
| (void) state; /* unused */ |
| const struct lys_module *mod, *modx, *mody; |
| const char *yang_x = "module x {" |
| " namespace uri:x;" |
| " prefix x;" |
| " container x { presence yes; }}"; |
| const char *yang_y = "module y {" |
| " namespace uri:y;" |
| " prefix y;" |
| " import x { prefix x;}" |
| " augment /x:x {" |
| " leaf y { type string;}}}"; |
| |
| ctx = ly_ctx_new(NULL); |
| assert_ptr_not_equal(ctx, NULL); |
| |
| /* test failures - invalid input */ |
| assert_int_not_equal(lys_set_disabled(NULL), 0); |
| |
| /* test failures - internal module */ |
| mod = ly_ctx_get_module(ctx, "ietf-yang-library", NULL); |
| assert_ptr_not_equal(mod, NULL); |
| assert_int_not_equal(lys_set_disabled(mod), 0); |
| |
| /* test success - disabling y extending x */ |
| modx = lys_parse_mem(ctx, yang_x, LYS_IN_YANG); |
| assert_ptr_not_equal(modx, NULL); |
| mody = lys_parse_mem(ctx, yang_y, LYS_IN_YANG); |
| assert_ptr_not_equal(mody, NULL); |
| |
| /* all the modules are enabled ... */ |
| assert_int_equal(mody->disabled, 0); |
| assert_int_equal(modx->disabled, 0); |
| /* ... and the y's augment is applied */ |
| assert_ptr_not_equal(modx->data->child, NULL); |
| |
| /* by disabling y ... */ |
| assert_int_equal(lys_set_disabled(mody), 0); |
| /* ... y is disabled while x stays enabled (it is implemented) ...*/ |
| assert_int_equal(mody->disabled, 1); |
| assert_int_equal(modx->disabled, 0); |
| /* ... and y's augment disappeared from x */ |
| assert_ptr_equal(modx->data->child, NULL); |
| |
| /* by enabling it, everything goes back */ |
| assert_int_equal(lys_set_enabled(mody), 0); |
| assert_int_equal(mody->disabled, 0); |
| assert_int_equal(modx->disabled, 0); |
| assert_ptr_not_equal(modx->data->child, NULL); |
| |
| /* by disabling x ... */ |
| assert_int_equal(lys_set_disabled(modx), 0); |
| /* ... both x and y are disabled (y depends on x) ...*/ |
| assert_int_equal(mody->disabled, 1); |
| assert_int_equal(modx->disabled, 1); |
| /* ... and y's augment disappeared from x */ |
| assert_ptr_equal(modx->data->child, NULL); |
| |
| /* by enabling it, everything goes back */ |
| assert_int_equal(lys_set_enabled(modx), 0); |
| assert_int_equal(mody->disabled, 0); |
| assert_int_equal(modx->disabled, 0); |
| assert_ptr_not_equal(modx->data->child, NULL); |
| } |
| |
| |
| static void |
| test_ly_ctx_get_module_by_ns(void **state) |
| { |
| (void) state; /* unused */ |
| const struct lys_module *module; |
| const char *ns = "urn:a"; |
| const char *revision = NULL; |
| |
| module = ly_ctx_get_module_by_ns(NULL, ns, revision); |
| if (module) { |
| fail(); |
| } |
| |
| module = ly_ctx_get_module_by_ns(ctx, NULL, revision); |
| if (module) { |
| fail(); |
| } |
| |
| module = ly_ctx_get_module_by_ns(ctx, ns, revision); |
| if (!module) { |
| fail(); |
| } |
| |
| assert_string_equal("a", module->name); |
| |
| module = ly_ctx_get_module_by_ns(ctx, "urn:b", revision); |
| if (!module) { |
| fail(); |
| } |
| |
| assert_string_equal("b", module->name); |
| } |
| |
| static void |
| test_ly_ctx_get_submodule(void **state) |
| { |
| (void) state; /* unused */ |
| const struct lys_submodule *submodule; |
| const char *mod_name = "a"; |
| const char *sub_name = "asub"; |
| const char *revision = NULL; |
| |
| submodule = ly_ctx_get_submodule(NULL, mod_name, revision, sub_name, NULL); |
| if (submodule) { |
| fail(); |
| } |
| |
| submodule = ly_ctx_get_submodule(ctx, NULL, revision, sub_name, "2010-02-08"); |
| if (submodule) { |
| fail(); |
| } |
| |
| submodule = ly_ctx_get_submodule(ctx, mod_name, revision, NULL, NULL); |
| if (submodule) { |
| fail(); |
| } |
| |
| submodule = ly_ctx_get_submodule(ctx, mod_name, revision, sub_name, NULL); |
| if (!submodule) { |
| fail(); |
| } |
| |
| assert_string_equal("asub", submodule->name); |
| |
| submodule = ly_ctx_get_submodule(ctx, "b", revision, "bsub", NULL); |
| if (!submodule) { |
| fail(); |
| } |
| |
| assert_string_equal("bsub", submodule->name); |
| } |
| |
| static void |
| test_ly_ctx_get_submodule2(void **state) |
| { |
| (void) state; /* unused */ |
| const struct lys_submodule *submodule; |
| const char *sub_name1 = "asub"; |
| const char *sub_name2 = "bsub"; |
| |
| submodule = ly_ctx_get_submodule2(NULL, sub_name1); |
| if (submodule) { |
| fail(); |
| } |
| |
| submodule = ly_ctx_get_submodule2(root->schema->module, NULL); |
| if (submodule) { |
| fail(); |
| } |
| |
| submodule = ly_ctx_get_submodule2(root->schema->module, sub_name1); |
| if (!submodule) { |
| fail(); |
| } |
| |
| assert_string_equal("asub", submodule->name); |
| |
| submodule = ly_ctx_get_submodule2(module, sub_name2); |
| if (!submodule) { |
| fail(); |
| } |
| |
| assert_string_equal("bsub", submodule->name); |
| } |
| |
| static void |
| test_ly_ctx_get_node(void **state) |
| { |
| (void) state; /* unused */ |
| const struct lys_node *node; |
| const char *nodeid1 = "/a:x/bubba"; |
| const char *nodeid2 = "/b:x/bubba"; |
| const char *nodeid3 = "/a:x/choic/con/con/lef"; |
| |
| node = ly_ctx_get_node(NULL, root->schema, nodeid1); |
| if (node) { |
| fail(); |
| } |
| |
| node = ly_ctx_get_node(ctx, root->schema, NULL); |
| if (node) { |
| fail(); |
| } |
| |
| node = ly_ctx_get_node(ctx, root->schema, nodeid1); |
| if (!node) { |
| fail(); |
| } |
| |
| assert_string_equal("bubba", node->name); |
| |
| node = ly_ctx_get_node(ctx, root->schema, nodeid2); |
| if (!node) { |
| fail(); |
| } |
| |
| assert_string_equal("bubba", node->name); |
| |
| node = ly_ctx_get_node(ctx, root->schema, nodeid3); |
| if (!node) { |
| fail(); |
| } |
| |
| assert_string_equal("lef", node->name); |
| } |
| |
| static void |
| test_ly_set_new(void **state) |
| { |
| (void) state; /* unused */ |
| struct ly_set *set; |
| |
| set = ly_set_new(); |
| if (!set) { |
| fail(); |
| } |
| |
| free(set); |
| } |
| |
| static void |
| test_ly_set_add(void **state) |
| { |
| (void) state; /* unused */ |
| struct ly_set *set; |
| int rc; |
| |
| set = ly_set_new(); |
| if (!set) { |
| fail(); |
| } |
| |
| rc = ly_set_add(NULL, root->child->schema, 0); |
| if(rc != -1) { |
| fail(); |
| } |
| |
| rc = ly_set_add(set, NULL, 0); |
| if(rc != -1) { |
| fail(); |
| } |
| |
| rc = ly_set_add(set, root->child->schema, 0); |
| if(rc == -1) { |
| fail(); |
| } |
| |
| ly_set_free(set); |
| } |
| |
| static void |
| test_ly_set_rm(void **state) |
| { |
| (void) state; /* unused */ |
| struct ly_set *set; |
| int rc; |
| |
| set = ly_set_new(); |
| if (!set) { |
| fail(); |
| } |
| |
| rc = ly_set_rm(NULL, root->child->schema); |
| if(!rc) { |
| fail(); |
| } |
| |
| rc = ly_set_rm(set, NULL); |
| if(!rc) { |
| fail(); |
| } |
| |
| rc = ly_set_add(set, root->child->schema, 0); |
| if(rc) { |
| fail(); |
| } |
| |
| rc = ly_set_rm(set, root->child->schema); |
| if(rc) { |
| fail(); |
| } |
| |
| ly_set_free(set); |
| } |
| |
| static void |
| test_ly_set_rm_index(void **state) |
| { |
| (void) state; /* unused */ |
| struct ly_set *set; |
| int rc; |
| |
| set = ly_set_new(); |
| if (!set) { |
| fail(); |
| } |
| |
| rc = ly_set_rm_index(NULL, 0); |
| if(!rc) { |
| fail(); |
| } |
| |
| rc = ly_set_add(set, root->child->schema, 0); |
| if(rc) { |
| fail(); |
| } |
| |
| rc = ly_set_rm_index(set, 0); |
| if(rc) { |
| fail(); |
| } |
| |
| ly_set_free(set); |
| } |
| |
| static void |
| test_ly_set_free(void **state) |
| { |
| (void) state; /* unused */ |
| struct ly_set *set; |
| |
| set = ly_set_new(); |
| if (!set) { |
| fail(); |
| } |
| |
| ly_set_free(set); |
| |
| if (!set) { |
| fail(); |
| } |
| } |
| |
| static void |
| test_ly_verb(void **state) |
| { |
| (void) state; /* unused */ |
| |
| ly_verb(LY_LLERR); |
| } |
| |
| void clb_custom(LY_LOG_LEVEL level, const char *msg, const char *path ) |
| { |
| (void) level; /* unused */ |
| (void) msg; /* unused */ |
| (void) path; /* unused */ |
| } |
| |
| static void |
| test_ly_get_log_clb(void **state) |
| { |
| (void) state; /* unused */ |
| void *clb = NULL; |
| |
| clb = ly_get_log_clb(); |
| assert_ptr_equal(clb, NULL); |
| } |
| |
| static void |
| test_ly_set_log_clb(void **state) |
| { |
| (void) state; /* unused */ |
| void *clb = NULL; |
| void *clb_new = NULL; |
| |
| clb = ly_get_log_clb(); |
| |
| ly_set_log_clb(clb_custom,0); |
| |
| clb_new = ly_get_log_clb(); |
| |
| assert_ptr_not_equal(clb, clb_new); |
| } |
| |
| static void |
| test_ly_errno_location(void **state) |
| { |
| (void) state; /* unused */ |
| char *yang_folder = "INVALID_PATH"; |
| |
| LY_ERR *error; |
| |
| error = ly_errno_location(); |
| |
| assert_int_equal(LY_SUCCESS, *error); |
| |
| ctx = ly_ctx_new(yang_folder); |
| if (ctx) { |
| fail(); |
| } |
| |
| error = ly_errno_location(); |
| |
| assert_int_equal(LY_ESYS, *error); |
| ly_ctx_destroy(ctx, NULL); |
| } |
| |
| static void |
| test_ly_errmsg(void **state) |
| { |
| (void) state; /* unused */ |
| const char *msg; |
| char *yang_folder = "INVALID_PATH"; |
| char *compare = "Unable to use search directory \"INVALID_PATH\" (No such file or directory)"; |
| |
| ctx = ly_ctx_new(yang_folder); |
| if (ctx) { |
| fail(); |
| } |
| |
| msg = ly_errmsg(); |
| |
| assert_string_equal(compare, msg); |
| } |
| |
| static void |
| test_ly_errpath(void **state) |
| { |
| (void) state; /* unused */ |
| const char *path; |
| char *compare = ""; |
| |
| path = ly_errpath(); |
| |
| assert_string_equal(compare, path); |
| } |
| |
| int main(void) |
| { |
| const struct CMUnitTest tests[] = { |
| cmocka_unit_test(test_ly_ctx_new), |
| cmocka_unit_test(test_ly_ctx_new_invalid), |
| cmocka_unit_test(test_ly_ctx_get_searchdirs), |
| cmocka_unit_test(test_ly_ctx_set_searchdir), |
| cmocka_unit_test(test_ly_ctx_set_searchdir_invalid), |
| cmocka_unit_test_setup_teardown(test_ly_ctx_info, setup_f, teardown_f), |
| cmocka_unit_test_setup_teardown(test_ly_ctx_get_module, setup_f, teardown_f), |
| cmocka_unit_test_setup_teardown(test_ly_ctx_get_module_older, setup_f, teardown_f), |
| cmocka_unit_test_setup_teardown(test_ly_ctx_load_module, setup_f, teardown_f), |
| cmocka_unit_test_teardown(test_ly_ctx_remove_module, teardown_f), |
| cmocka_unit_test_teardown(test_ly_ctx_remove_module2, teardown_f), |
| cmocka_unit_test_teardown(test_lys_set_enabled, teardown_f), |
| cmocka_unit_test_teardown(test_lys_set_disabled, teardown_f), |
| cmocka_unit_test(test_ly_ctx_clean), |
| cmocka_unit_test(test_ly_ctx_clean2), |
| cmocka_unit_test_setup_teardown(test_ly_ctx_get_module_by_ns, setup_f, teardown_f), |
| cmocka_unit_test_setup_teardown(test_ly_ctx_get_submodule, setup_f, teardown_f), |
| cmocka_unit_test_setup_teardown(test_ly_ctx_get_submodule2, setup_f, teardown_f), |
| cmocka_unit_test_setup_teardown(test_ly_ctx_get_node, setup_f, teardown_f), |
| cmocka_unit_test_setup_teardown(test_ly_set_new, setup_f, teardown_f), |
| cmocka_unit_test_setup_teardown(test_ly_set_add, setup_f, teardown_f), |
| cmocka_unit_test_setup_teardown(test_ly_set_rm, setup_f, teardown_f), |
| cmocka_unit_test_setup_teardown(test_ly_set_rm_index, setup_f, teardown_f), |
| cmocka_unit_test_setup_teardown(test_ly_set_free, setup_f, teardown_f), |
| cmocka_unit_test(test_ly_verb), |
| cmocka_unit_test(test_ly_get_log_clb), |
| cmocka_unit_test(test_ly_set_log_clb), |
| cmocka_unit_test(test_ly_errno_location), |
| cmocka_unit_test(test_ly_errmsg), |
| cmocka_unit_test_setup_teardown(test_ly_errpath, setup_f, teardown_f), |
| }; |
| |
| return cmocka_run_group_tests(tests, NULL, NULL); |
| } |