| /** |
| * \file test_augment.c |
| * \author Michal Vasko <mvasko@cesnet.cz> |
| * \brief libyang tests - augment targets |
| * |
| * Copyright (c) 2015 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 |
| */ |
| |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <pthread.h> |
| #include <setjmp.h> |
| #include <stdarg.h> |
| #include <stddef.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| |
| #include <cmocka.h> |
| |
| #include "libyang.h" |
| #include "context.h" |
| #include "tests/config.h" |
| |
| #define SCHEMA_FOLDER_YIN TESTS_DIR"/schema/yin/files" |
| #define SCHEMA_FOLDER_YANG TESTS_DIR"/schema/yang/files" |
| |
| #define MOD_COUNT 7 |
| #define YANG_MOD_IDX(idx) (idx) |
| #define YIN_MOD_IDX(idx) (MOD_COUNT + idx) |
| |
| struct ly_ctx *ctx; |
| char *yang_modules[2 * MOD_COUNT] = {0}; |
| char *yin_modules[2 * MOD_COUNT] = {0}; |
| |
| |
| static int |
| setup_ctx_yin(void **state) |
| { |
| *state = malloc(strlen(TESTS_DIR) + 64); |
| assert_non_null(*state); |
| memcpy(*state, SCHEMA_FOLDER_YIN, strlen(SCHEMA_FOLDER_YIN) + 1); |
| |
| ctx = ly_ctx_new(NULL, 0); |
| if (!ctx) { |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| static int |
| setup_ctx_yang(void **state) |
| { |
| *state = malloc(strlen(TESTS_DIR) + 64); |
| assert_non_null(*state); |
| memcpy(*state, SCHEMA_FOLDER_YANG, strlen(SCHEMA_FOLDER_YANG) + 1); |
| |
| ctx = ly_ctx_new(NULL, 0); |
| if (!ctx) { |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| static int |
| teardown_ctx(void **state) |
| { |
| free(*state); |
| ly_ctx_destroy(ctx, NULL); |
| |
| return 0; |
| } |
| |
| static void |
| test_target_include_submodule(void **state) |
| { |
| int length; |
| char *path = *state; |
| const struct lys_module *module; |
| |
| ly_ctx_set_searchdir(ctx, path); |
| length = strlen(path); |
| if (!strcmp(path, SCHEMA_FOLDER_YIN)) { |
| strcpy(path + length, "/a.yin"); |
| if (!(module = lys_parse_path(ctx, path, LYS_IN_YIN))) { |
| fail(); |
| } |
| lys_print_mem(&yin_modules[YANG_MOD_IDX(0)], module, LYS_OUT_YANG, NULL, 0, 0); |
| lys_print_mem(&yin_modules[YIN_MOD_IDX(0)], module, LYS_OUT_YIN, NULL, 0, 0); |
| } else { |
| strcpy(path + length, "/a.yang"); |
| if (!(module = lys_parse_path(ctx, path, LYS_IN_YANG))) { |
| fail(); |
| } |
| lys_print_mem(&yang_modules[YANG_MOD_IDX(0)], module, LYS_OUT_YANG, NULL, 0, 0); |
| lys_print_mem(&yang_modules[YIN_MOD_IDX(0)], module, LYS_OUT_YIN, NULL, 0, 0); |
| } |
| } |
| |
| static void |
| test_leafref(void **state) |
| { |
| int length; |
| char *path = *state; |
| const struct lys_module *module; |
| |
| ly_ctx_set_searchdir(ctx, path); |
| length = strlen(path); |
| if (!strcmp(path, SCHEMA_FOLDER_YIN)) { |
| strcpy(path + length, "/b1.yin"); |
| if (!(module = lys_parse_path(ctx, path, LYS_IN_YIN))) { |
| fail(); |
| } |
| lys_print_mem(&yin_modules[YANG_MOD_IDX(1)], module, LYS_OUT_YANG, NULL, 0, 0); |
| lys_print_mem(&yin_modules[YIN_MOD_IDX(1)], module, LYS_OUT_YIN, NULL, 0, 0); |
| |
| strcpy(path + length, "/b2.yin"); |
| if (!(module = lys_parse_path(ctx, path, LYS_IN_YIN))) { |
| fail(); |
| } |
| lys_print_mem(&yin_modules[YANG_MOD_IDX(2)], module, LYS_OUT_YANG, NULL, 0, 0); |
| lys_print_mem(&yin_modules[YIN_MOD_IDX(2)], module, LYS_OUT_YIN, NULL, 0, 0); |
| } else { |
| strcpy(path + length, "/b1.yang"); |
| if (!(module = lys_parse_path(ctx, path, LYS_IN_YANG))) { |
| fail(); |
| } |
| lys_print_mem(&yang_modules[YANG_MOD_IDX(1)], module, LYS_OUT_YANG, NULL, 0, 0); |
| lys_print_mem(&yang_modules[YIN_MOD_IDX(1)], module, LYS_OUT_YIN, NULL, 0, 0); |
| |
| strcpy(path + length, "/b2.yang"); |
| if (!(module = lys_parse_path(ctx, path, LYS_IN_YANG))) { |
| fail(); |
| } |
| lys_print_mem(&yang_modules[YANG_MOD_IDX(2)], module, LYS_OUT_YANG, NULL, 0, 0); |
| lys_print_mem(&yang_modules[YIN_MOD_IDX(2)], module, LYS_OUT_YIN, NULL, 0, 0); |
| } |
| } |
| |
| /* Test case to verify the solution for an augment resolution issue: |
| The iffeature consistency check for leafrefs failed because |
| some of the imported augments have not yet been applied. */ |
| static void |
| test_leafref_w_feature1(void **state) |
| { |
| int length, i; |
| char *path = *state; |
| const struct lys_module *module; |
| |
| ly_ctx_set_searchdir(ctx, path); |
| length = strlen(path); |
| if (!strcmp(path, SCHEMA_FOLDER_YIN)) { |
| strcpy(path + length, "/leafref_w_feature1-mod3.yin"); |
| if (!(module = lys_parse_path(ctx, path, LYS_IN_YIN))) { |
| fail(); |
| } |
| } else { |
| strcpy(path + length, "/leafref_w_feature1-mod3.yang"); |
| if (!(module = lys_parse_path(ctx, path, LYS_IN_YANG))) { |
| fail(); |
| } |
| } |
| for (i = 0; i < ctx->models.used; i++) { |
| if (strncmp("leafref_w_feature1-mod",ctx->models.list[i]->name,strlen("leafref_w_feature1-mod")) == 0) { |
| assert_non_null(ctx->models.list[i]->implemented); |
| } |
| } |
| } |
| |
| /* Test case to verify the solution for an augment resolution issue: |
| The iffeature consistency check for leafrefs failed because |
| some of the augments have not yet been applied, due to an |
| ordering problem in resolution (similar as in test_leafref_w_feature1()) */ |
| static void |
| test_leafref_w_feature2(void **state) |
| { |
| int length, i; |
| char *path = *state; |
| const struct lys_module *module; |
| |
| ly_ctx_set_searchdir(ctx, path); |
| length = strlen(path); |
| if (!strcmp(path, SCHEMA_FOLDER_YIN)) { |
| strcpy(path + length, "/leafref_w_feature2-mod1.yin"); |
| if (!(module = lys_parse_path(ctx, path, LYS_IN_YIN))) { |
| fail(); |
| } |
| } else { |
| strcpy(path + length, "/leafref_w_feature2-mod1.yang"); |
| if (!(module = lys_parse_path(ctx, path, LYS_IN_YANG))) { |
| fail(); |
| } |
| } |
| for (i = 0; i < ctx->models.used; i++) { |
| if (strncmp("leafref_w_feature2-mod",ctx->models.list[i]->name,strlen("leafref_w_feature2-mod")) == 0) { |
| assert_non_null(ctx->models.list[i]->implemented); |
| } |
| } |
| } |
| |
| /* Test case to verify the solution for an augment resolution issue: |
| The iffeature consistency check for leafrefs failed for augments |
| which are in imported modules and which are not going to be |
| implemented/applied. This prevented the module to be installed from |
| being installed */ |
| static void |
| test_leafref_w_feature3(void **state) |
| { |
| int length, i; |
| char *path = *state; |
| const struct lys_module *module; |
| |
| ly_ctx_set_searchdir(ctx, path); |
| length = strlen(path); |
| if (!strcmp(path, SCHEMA_FOLDER_YIN)) { |
| strcpy(path + length, "/leafref_w_feature1-mod4.yin"); |
| if (!(module = lys_parse_path(ctx, path, LYS_IN_YIN))) { |
| fail(); |
| } |
| } else { |
| strcpy(path + length, "/leafref_w_feature1-mod4.yang"); |
| if (!(module = lys_parse_path(ctx, path, LYS_IN_YANG))) { |
| fail(); |
| } |
| } |
| for (i = 0; i < ctx->models.used; i++) { |
| if (strcmp("leafref_w_feature1-mod4",ctx->models.list[i]->name) == 0) { |
| assert_non_null(ctx->models.list[i]->implemented); |
| } else if (strncmp("leafref_w_feature1-mod",ctx->models.list[i]->name,strlen("leafref_w_feature1-mod")) == 0) { |
| assert_null(ctx->models.list[i]->implemented); |
| } |
| } |
| } |
| |
| /* Test case to verify the solution for an augment resolution issue: |
| An augment having a relative nodeid couldn't be resolved, if a grouping |
| which is declared in a submodule uses a grouping of an imported module |
| and augments it. Please have a look at all imp_aug_m* schema files. |
| */ |
| static void |
| test_imp_aug(void **state) |
| { |
| int length; |
| char *path = *state; |
| const struct lys_module *module; |
| |
| ly_ctx_set_searchdir(ctx, path); |
| length = strlen(path); |
| if (!strcmp(path, SCHEMA_FOLDER_YIN)) { |
| strcpy(path + length, "/imp_aug_m1.yin"); |
| if (!(module = lys_parse_path(ctx, path, LYS_IN_YIN))) { |
| fail(); |
| } |
| } else { |
| strcpy(path + length, "/imp_aug_m1.yang"); |
| if (!(module = lys_parse_path(ctx, path, LYS_IN_YANG))) { |
| fail(); |
| } |
| } |
| } |
| |
| static void |
| test_target_augment(void **state) |
| { |
| int length; |
| char *path = *state; |
| const struct lys_module *module; |
| |
| ly_ctx_set_searchdir(ctx, path); |
| length = strlen(path); |
| if (!strcmp(path, SCHEMA_FOLDER_YIN)) { |
| strcpy(path + length, "/c1.yin"); |
| if (!(module = lys_parse_path(ctx, path, LYS_IN_YIN))) { |
| fail(); |
| } |
| lys_print_mem(&yin_modules[YANG_MOD_IDX(3)], module, LYS_OUT_YANG, NULL, 0, 0); |
| lys_print_mem(&yin_modules[YIN_MOD_IDX(3)], module, LYS_OUT_YIN, NULL, 0, 0); |
| |
| strcpy(path + length, "/c2.yin"); |
| if (!(module = lys_parse_path(ctx, path, LYS_IN_YIN))) { |
| fail(); |
| } |
| lys_print_mem(&yin_modules[YANG_MOD_IDX(4)], module, LYS_OUT_YANG, NULL, 0, 0); |
| lys_print_mem(&yin_modules[YIN_MOD_IDX(4)], module, LYS_OUT_YIN, NULL, 0, 0); |
| |
| strcpy(path + length, "/c3.yin"); |
| if (!(module = lys_parse_path(ctx, path, LYS_IN_YIN))) { |
| fail(); |
| } |
| lys_print_mem(&yin_modules[YANG_MOD_IDX(5)], module, LYS_OUT_YANG, NULL, 0, 0); |
| lys_print_mem(&yin_modules[YIN_MOD_IDX(5)], module, LYS_OUT_YIN, NULL, 0, 0); |
| } else { |
| strcpy(path + length, "/c1.yang"); |
| if (!(module = lys_parse_path(ctx, path, LYS_IN_YANG))) { |
| fail(); |
| } |
| lys_print_mem(&yang_modules[YANG_MOD_IDX(3)], module, LYS_OUT_YANG, NULL, 0, 0); |
| lys_print_mem(&yang_modules[YIN_MOD_IDX(3)], module, LYS_OUT_YIN, NULL, 0, 0); |
| |
| strcpy(path + length, "/c2.yang"); |
| if (!(module = lys_parse_path(ctx, path, LYS_IN_YANG))) { |
| fail(); |
| } |
| lys_print_mem(&yang_modules[YANG_MOD_IDX(4)], module, LYS_OUT_YANG, NULL, 0, 0); |
| lys_print_mem(&yang_modules[YIN_MOD_IDX(4)], module, LYS_OUT_YIN, NULL, 0, 0); |
| |
| strcpy(path + length, "/c3.yang"); |
| if (!(module = lys_parse_path(ctx, path, LYS_IN_YANG))) { |
| fail(); |
| } |
| lys_print_mem(&yang_modules[YANG_MOD_IDX(5)], module, LYS_OUT_YANG, NULL, 0, 0); |
| lys_print_mem(&yang_modules[YIN_MOD_IDX(5)], module, LYS_OUT_YIN, NULL, 0, 0); |
| } |
| } |
| |
| static void |
| test_unres_augment(void **state) |
| { |
| int length; |
| char *path = *state; |
| const struct lys_module *module; |
| |
| ly_ctx_set_searchdir(ctx, path); |
| length = strlen(path); |
| if (!strcmp(path, SCHEMA_FOLDER_YIN)) { |
| strcpy(path + length, "/emod.yin"); |
| if (!(module = lys_parse_path(ctx, path, LYS_IN_YIN))) { |
| fail(); |
| } |
| lys_print_mem(&yin_modules[YANG_MOD_IDX(6)], module, LYS_OUT_YANG, NULL, 0, 0); |
| lys_print_mem(&yin_modules[YIN_MOD_IDX(6)], module, LYS_OUT_YIN, NULL, 0, 0); |
| } else { |
| strcpy(path + length, "/emod.yang"); |
| if (!(module = lys_parse_path(ctx, path, LYS_IN_YANG))) { |
| fail(); |
| } |
| lys_print_mem(&yang_modules[YANG_MOD_IDX(6)], module, LYS_OUT_YANG, NULL, 0, 0); |
| lys_print_mem(&yang_modules[YIN_MOD_IDX(6)], module, LYS_OUT_YIN, NULL, 0, 0); |
| } |
| } |
| |
| static void |
| test_import_augment_target(void **state) |
| { |
| int length; |
| char *path = *state; |
| const struct lys_module *module; |
| |
| ly_ctx_set_searchdir(ctx, path); |
| length = strlen(path); |
| if (!strcmp(path, SCHEMA_FOLDER_YIN)) { |
| strcpy(path + length, "/g1.yin"); |
| if (!(module = lys_parse_path(ctx, path, LYS_IN_YIN))) { |
| fail(); |
| } |
| /*lys_print_mem(&yin_modules[7], module, LYS_OUT_YANG, NULL); |
| lys_print_mem(&yin_modules[14], module, LYS_OUT_YIN, NULL);*/ |
| } else { |
| strcpy(path + length, "/g1.yang"); |
| if (!(module = lys_parse_path(ctx, path, LYS_IN_YANG))) { |
| fail(); |
| } |
| /*lys_print_mem(&yin_modules[7], module, LYS_OUT_YANG, NULL); |
| lys_print_mem(&yin_modules[14], module, LYS_OUT_YIN, NULL);*/ |
| } |
| } |
| |
| static void |
| test_import_augment_leafref_implemented(void **state) |
| { |
| int length; |
| char *path = *state; |
| const struct lys_module *module; |
| |
| ly_ctx_set_searchdir(ctx, path); |
| length = strlen(path); |
| if (!strcmp(path, SCHEMA_FOLDER_YIN)) { |
| strcpy(path + length, "/mainmodule.yin"); |
| if (!(module = lys_parse_path(ctx, path, LYS_IN_YIN))) { |
| fail(); |
| } |
| } else { |
| strcpy(path + length, "/mainmodule.yang"); |
| if (!(module = lys_parse_path(ctx, path, LYS_IN_YANG))) { |
| fail(); |
| } |
| } |
| |
| module = ly_ctx_get_module(ctx, "mainmodule", NULL, 0); |
| assert_true(module && module->implemented); |
| module = ly_ctx_get_module(ctx, "augmentbase", NULL, 0); |
| assert_true(module && module->implemented); |
| module = ly_ctx_get_module(ctx, "augmentone", NULL, 0); |
| assert_true(module && module->implemented); |
| module = ly_ctx_get_module(ctx, "augmenttwo", NULL, 0); |
| assert_true(module && module->implemented); |
| |
| } |
| |
| static void |
| test_import_augment_leafref_imported(void **state) |
| { |
| int length; |
| char *path = *state; |
| const struct lys_module *module; |
| |
| ly_ctx_set_searchdir(ctx, path); |
| length = strlen(path); |
| if (!strcmp(path, SCHEMA_FOLDER_YIN)) { |
| strcpy(path + length, "/installme.yin"); |
| if (!(module = lys_parse_path(ctx, path, LYS_IN_YIN))) { |
| fail(); |
| } |
| } else { |
| strcpy(path + length, "/installme.yang"); |
| if (!(module = lys_parse_path(ctx, path, LYS_IN_YANG))) { |
| fail(); |
| } |
| } |
| |
| module = ly_ctx_get_module(ctx, "installme", NULL, 0); |
| assert_true(module && module->implemented); |
| |
| module = ly_ctx_get_module(ctx, "aug", NULL, 0); |
| assert_true(module && !module->implemented); |
| |
| module = ly_ctx_get_module(ctx, "base", NULL, 0); |
| assert_true(module && !module->implemented); |
| } |
| |
| static void |
| compare_output(void **state) |
| { |
| int i; |
| char *name[] = {"a", "b1", "b2", "c1", "c2", "c3", "emod"}; |
| |
| (void) state; /* unused state*/ |
| for (i = 0; i < 14; ++i) { |
| fprintf(stdout, "Compare \"%s\" modules print by %s ... ", name[i % 7], (i / 7) ? "yin_print" : "yang_print"); |
| assert_non_null(yang_modules[i]); |
| assert_non_null(yin_modules[i]); |
| if (strcmp(yang_modules[i], yin_modules[i])) { |
| fprintf(stderr, "failed.\n"); |
| fail(); |
| } |
| fprintf(stdout, "ok.\n"); |
| } |
| } |
| |
| static int |
| teardown_output(void **state) |
| { |
| int i; |
| |
| (void)state; /* unused state*/ |
| for (i = 0; i < 14; ++i) { |
| free(yang_modules[i]); |
| free(yin_modules[i]); |
| } |
| return 0; |
| } |
| |
| int |
| main(void) |
| { |
| ly_verb(LY_LLWRN); |
| const struct CMUnitTest cmut[] = { |
| cmocka_unit_test_setup_teardown(test_target_include_submodule, setup_ctx_yin, teardown_ctx), |
| cmocka_unit_test_setup_teardown(test_leafref, setup_ctx_yin, teardown_ctx), |
| cmocka_unit_test_setup_teardown(test_target_augment, setup_ctx_yin, teardown_ctx), |
| cmocka_unit_test_setup_teardown(test_unres_augment, setup_ctx_yin, teardown_ctx), |
| cmocka_unit_test_setup_teardown(test_import_augment_target, setup_ctx_yin, teardown_ctx), |
| cmocka_unit_test_setup_teardown(test_leafref_w_feature1, setup_ctx_yin, teardown_ctx), |
| cmocka_unit_test_setup_teardown(test_leafref_w_feature2, setup_ctx_yin, teardown_ctx), |
| cmocka_unit_test_setup_teardown(test_leafref_w_feature3, setup_ctx_yin, teardown_ctx), |
| cmocka_unit_test_setup_teardown(test_imp_aug, setup_ctx_yin, teardown_ctx), |
| cmocka_unit_test_setup_teardown(test_import_augment_leafref_implemented, setup_ctx_yin, teardown_ctx), |
| cmocka_unit_test_setup_teardown(test_import_augment_leafref_imported, setup_ctx_yin, teardown_ctx), |
| |
| cmocka_unit_test_setup_teardown(test_target_include_submodule, setup_ctx_yang, teardown_ctx), |
| cmocka_unit_test_setup_teardown(test_leafref, setup_ctx_yang, teardown_ctx), |
| cmocka_unit_test_setup_teardown(test_target_augment, setup_ctx_yang, teardown_ctx), |
| cmocka_unit_test_setup_teardown(test_unres_augment, setup_ctx_yang, teardown_ctx), |
| cmocka_unit_test_setup_teardown(test_import_augment_target, setup_ctx_yang, teardown_ctx), |
| cmocka_unit_test_setup_teardown(test_leafref_w_feature1, setup_ctx_yang, teardown_ctx), |
| cmocka_unit_test_setup_teardown(test_leafref_w_feature2, setup_ctx_yang, teardown_ctx), |
| cmocka_unit_test_setup_teardown(test_leafref_w_feature3, setup_ctx_yang, teardown_ctx), |
| cmocka_unit_test_setup_teardown(test_imp_aug, setup_ctx_yang, teardown_ctx), |
| cmocka_unit_test_setup_teardown(test_import_augment_leafref_implemented, setup_ctx_yang, teardown_ctx), |
| cmocka_unit_test_setup_teardown(test_import_augment_leafref_imported, setup_ctx_yang, teardown_ctx), |
| |
| cmocka_unit_test_teardown(compare_output, teardown_output), |
| }; |
| |
| return cmocka_run_group_tests(cmut, NULL, NULL); |
| } |