blob: c82dbb49b3f14e538d0877f28f207ee97d363347 [file] [log] [blame]
/*
* @file test_schema_extensions.c
* @author: Radek Krejci <rkrejci@cesnet.cz>
* @brief unit tests for YANG (YIN) extension statements and their instances in schemas
*
* Copyright (c) 2018-2021 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 "test_schema.h"
#include <string.h>
#include "context.h"
#include "log.h"
#include "plugins_exts.h"
#include "tree_schema.h"
void
test_extension_argument(void **state)
{
struct lys_module *mod;
const char *mod_def_yang = "module a {\n"
" namespace \"urn:a\";\n"
" prefix a;\n\n"
" extension e {\n"
" argument name;\n"
" }\n\n"
" a:e \"aaa\";\n"
"}\n";
const char *mod_def_yin =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<module name=\"a\"\n"
" xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"\n"
" xmlns:a=\"urn:a\">\n"
" <namespace uri=\"urn:a\"/>\n"
" <prefix value=\"a\"/>\n\n"
" <extension name=\"e\">\n"
" <argument name=\"name\"/>\n"
" </extension>\n\n"
" <a:e name=\"aaa\"/>\n"
"</module>\n";
const char *mod_test_yin, *mod_test_yang;
char *printed;
mod_test_yang = "module b {\n"
" namespace \"urn:b\";\n"
" prefix b;\n\n"
" import a {\n"
" prefix a;\n"
" }\n\n"
" a:e \"xxx\";\n"
"}\n";
mod_test_yin =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<module name=\"b\"\n"
" xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"\n"
" xmlns:b=\"urn:b\"\n"
" xmlns:a=\"urn:a\">\n"
" <namespace uri=\"urn:b\"/>\n"
" <prefix value=\"b\"/>\n"
" <import module=\"a\">\n"
" <prefix value=\"a\"/>\n"
" </import>\n\n"
" <a:e name=\"xxx\"/>\n"
"</module>\n";
/* from YANG */
ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, (void *)mod_def_yang);
assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, mod_test_yang, LYS_IN_YANG, &mod));
assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG, 0));
assert_string_equal(printed, mod_test_yang);
free(printed);
assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YIN, 0));
assert_string_equal(printed, mod_test_yin);
free(printed);
assert_non_null(mod = ly_ctx_get_module(UTEST_LYCTX, "a", NULL));
assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG, 0));
assert_string_equal(printed, mod_def_yang);
free(printed);
assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YIN, 0));
assert_string_equal(printed, mod_def_yin);
free(printed);
/* context reset */
ly_ctx_destroy(UTEST_LYCTX);
ly_ctx_new(NULL, 0, &UTEST_LYCTX);
/* from YIN */
ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, (void *)mod_def_yin);
assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, mod_test_yin, LYS_IN_YIN, &mod));
assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG, 0));
assert_string_equal(printed, mod_test_yang);
free(printed);
assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YIN, 0));
assert_string_equal(printed, mod_test_yin);
free(printed);
assert_non_null(mod = ly_ctx_get_module(UTEST_LYCTX, "a", NULL));
assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG, 0));
assert_string_equal(printed, mod_def_yang);
free(printed);
assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YIN, 0));
assert_string_equal(printed, mod_def_yin);
free(printed);
}
void
test_extension_argument_element(void **state)
{
struct lys_module *mod;
const char *mod_def_yang = "module a {\n"
" namespace \"urn:a\";\n"
" prefix a;\n\n"
" extension e {\n"
" argument name {\n"
" yin-element true;\n"
" }\n"
" }\n\n"
" a:e \"aaa\";\n"
"}\n";
const char *mod_def_yin =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<module name=\"a\"\n"
" xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"\n"
" xmlns:a=\"urn:a\">\n"
" <namespace uri=\"urn:a\"/>\n"
" <prefix value=\"a\"/>\n\n"
" <extension name=\"e\">\n"
" <argument name=\"name\">\n"
" <yin-element value=\"true\"/>\n"
" </argument>\n"
" </extension>\n\n"
" <a:e>\n"
" <a:name>aaa</a:name>\n"
" </a:e>\n"
"</module>\n";
const char *mod_test_yin, *mod_test_yang;
char *printed;
mod_test_yang = "module b {\n"
" namespace \"urn:b\";\n"
" prefix b;\n\n"
" import a {\n"
" prefix a;\n"
" }\n\n"
" a:e \"xxx\";\n"
"}\n";
mod_test_yin =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<module name=\"b\"\n"
" xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"\n"
" xmlns:b=\"urn:b\"\n"
" xmlns:a=\"urn:a\">\n"
" <namespace uri=\"urn:b\"/>\n"
" <prefix value=\"b\"/>\n"
" <import module=\"a\">\n"
" <prefix value=\"a\"/>\n"
" </import>\n\n"
" <a:e>\n"
" <a:name>xxx</a:name>\n"
" </a:e>\n"
"</module>\n";
/* from YANG */
ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, (void *)mod_def_yang);
assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, mod_test_yang, LYS_IN_YANG, &mod));
assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG, 0));
assert_string_equal(printed, mod_test_yang);
free(printed);
assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YIN, 0));
assert_string_equal(printed, mod_test_yin);
free(printed);
assert_non_null(mod = ly_ctx_get_module(UTEST_LYCTX, "a", NULL));
assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG, 0));
assert_string_equal(printed, mod_def_yang);
free(printed);
assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YIN, 0));
assert_string_equal(printed, mod_def_yin);
free(printed);
/* context reset */
ly_ctx_destroy(UTEST_LYCTX);
ly_ctx_new(NULL, 0, &UTEST_LYCTX);
/* from YIN */
ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, (void *)mod_def_yin);
assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, mod_test_yin, LYS_IN_YIN, &mod));
assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG, 0));
assert_string_equal(printed, mod_test_yang);
free(printed);
assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YIN, 0));
assert_string_equal(printed, mod_test_yin);
free(printed);
assert_non_null(mod = ly_ctx_get_module(UTEST_LYCTX, "a", NULL));
assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG, 0));
assert_string_equal(printed, mod_def_yang);
free(printed);
assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YIN, 0));
assert_string_equal(printed, mod_def_yin);
free(printed);
/* invalid */
mod_test_yang = "module x { namespace \"urn:x\"; prefix x; import a { prefix a; } a:e; }";
assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, mod_test_yang, LYS_IN_YANG, NULL));
CHECK_LOG_CTX("Extension instance \"a:e\" misses argument element \"name\".", "/x:{extension='a:e'}");
mod_test_yin = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<module name=\"x\"\n"
" xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"\n"
" xmlns:x=\"urn:x\"\n"
" xmlns:a=\"urn:a\">\n"
" <namespace uri=\"urn:x\"/>\n"
" <prefix value=\"x\"/>\n"
" <import module=\"a\">\n"
" <prefix value=\"a\"/>\n"
" </import>\n\n"
" <a:e/>\n"
"</module>\n";
assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, mod_test_yin, LYS_IN_YIN, NULL));
CHECK_LOG_CTX("Extension instance \"a:e\" misses argument element \"name\".", "/x:{extension='a:e'}");
mod_test_yin = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<module name=\"x\"\n"
" xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"\n"
" xmlns:x=\"urn:x\"\n"
" xmlns:a=\"urn:a\">\n"
" <namespace uri=\"urn:x\"/>\n"
" <prefix value=\"x\"/>\n"
" <import module=\"a\">\n"
" <prefix value=\"a\"/>\n"
" </import>\n\n"
" <a:e name=\"xxx\"/>\n"
"</module>\n";
assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, mod_test_yin, LYS_IN_YIN, NULL));
CHECK_LOG_CTX("Extension instance \"a:e\" misses argument element \"name\".", "/x:{extension='a:e'}");
mod_test_yin = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<module name=\"x\"\n"
" xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"\n"
" xmlns:x=\"urn:x\"\n"
" xmlns:a=\"urn:a\">\n"
" <namespace uri=\"urn:x\"/>\n"
" <prefix value=\"x\"/>\n"
" <import module=\"a\">\n"
" <prefix value=\"a\"/>\n"
" </import>\n\n"
" <a:e>\n"
" <x:name>xxx</x:name>\n"
" </a:e>\n"
"</module>\n";
assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, mod_test_yin, LYS_IN_YIN, NULL));
CHECK_LOG_CTX("Extension instance \"a:e\" element and its argument element \"name\" are expected in the same namespace, but they differ.",
"/x:{extension='a:e'}");
mod_test_yin = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<module name=\"x\"\n"
" xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"\n"
" xmlns:x=\"urn:x\"\n"
" xmlns:a=\"urn:a\">\n"
" <namespace uri=\"urn:x\"/>\n"
" <prefix value=\"x\"/>\n"
" <import module=\"a\">\n"
" <prefix value=\"a\"/>\n"
" </import>\n\n"
" <a:e>\n"
" <a:value>xxx</a:value>\n"
" </a:e>\n"
"</module>\n";
assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, mod_test_yin, LYS_IN_YIN, NULL));
CHECK_LOG_CTX("Extension instance \"a:e\" expects argument element \"name\" as its first XML child, but \"value\" element found.",
"/x:{extension='a:e'}");
}
void
test_extension_compile(void **state)
{
struct lys_module *mod;
struct lysc_ctx cctx = {0};
struct lysp_ext_instance ext_p = {0};
struct lysp_stmt child = {0};
struct lysc_ext_instance ext_c = {0};
struct lysc_ext_substmt *substmt;
LY_ERR rc = LY_SUCCESS;
/* current module, whatever */
mod = ly_ctx_get_module_implemented(UTEST_LYCTX, "yang");
assert_true(mod);
/* compile context */
cctx.ctx = UTEST_LYCTX;
cctx.cur_mod = mod;
cctx.pmod = mod->parsed;
cctx.path_len = 1;
cctx.path[0] = '/';
/* parsed ext instance */
lydict_insert(UTEST_LYCTX, "pref:my-ext", 0, &ext_p.name);
ext_p.format = LY_VALUE_JSON;
ext_p.parent_stmt = LY_STMT_MODULE;
/* compiled ext instance */
ext_c.parent_stmt = ext_p.parent_stmt;
// ext_c.parent =
LY_ARRAY_NEW_GOTO(UTEST_LYCTX, ext_c.substmts, substmt, rc, cleanup);
/*
* error-message
*/
ext_p.child = &child;
lydict_insert(UTEST_LYCTX, "error-message", 0, &child.stmt);
lydict_insert(UTEST_LYCTX, "my error", 0, &child.arg);
child.format = LY_VALUE_JSON;
child.kw = LY_STMT_ERROR_MESSAGE;
substmt->stmt = LY_STMT_ERROR_MESSAGE;
substmt->cardinality = LY_STMT_CARD_OPT;
substmt->storage = &ext_c.data;
/* compile */
assert_int_equal(LY_SUCCESS, lys_compile_extension_instance(&cctx, &ext_p, &ext_c));
/* check */
assert_string_equal(ext_c.data, "my error");
cleanup:
lydict_remove(UTEST_LYCTX, ext_p.name);
lydict_remove(UTEST_LYCTX, child.stmt);
lydict_remove(UTEST_LYCTX, child.arg);
LY_ARRAY_FREE(ext_c.substmts);
lydict_remove(UTEST_LYCTX, ext_c.data);
if (rc) {
fail();
}
}