/*
* @file test_tree_schema.cpp
* @author: Hrvoje Varga <hrvoje.varga@sartura.hr>
* @brief unit tests for functions from tree_schema.h header
*
* Copyright (C) 2018 Deutsche Telekom AG.
*
* Author: Hrvoje Varga <hrvoje.varga@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 "Libyang.hpp"
#include "Tree_Schema.hpp"
#include "microtest.h"
#include "../tests/config.h"
const char *lys_module_a = \
"<?xml version=\"1.0\" encoding=\"UTF-8\"?> \
<module name=\"a\" \
xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" \
xmlns:a=\"urn:a\"> \
<namespace uri=\"urn:a\"/> \
<prefix value=\"a_mod\"/> \
<include module=\"asub\"/> \
<include module=\"atop\"/> \
<revision date=\"2015-01-01\"> \
<description> \
<text>version 1</text> \
</description> \
<reference> \
<text>RFC XXXX</text> \
</reference> \
</revision> \
<feature name=\"foo\"/> \
<grouping name=\"gg\"> \
<leaf name=\"bar-gggg\"> \
<type name=\"string\"/> \
</leaf> \
</grouping> \
<container name=\"x\"> \
<leaf name=\"bar-leaf\"> \
<if-feature name=\"bar\"/> \
<type name=\"string\"/> \
</leaf> \
<uses name=\"gg\"> \
<if-feature name=\"bar\"/> \
</uses> \
<leaf name=\"baz\"> \
<if-feature name=\"foo\"/> \
<type name=\"string\"/> \
</leaf> \
<leaf name=\"bubba\"> \
<type name=\"string\"/> \
</leaf> \
</container> \
<augment target-node=\"/x\"> \
<if-feature name=\"bar\"/> \
<container name=\"bar-y\"> \
<leaf name=\"ll\"> \
<type name=\"string\"/> \
</leaf> \
</container> \
</augment> \
<rpc name=\"bar-rpc\"> \
<if-feature name=\"bar\"/> \
</rpc> \
<rpc name=\"foo-rpc\"> \
<if-feature name=\"foo\"/> \
</rpc> \
</module> \
";
const char *lys_module_b = \
"module b {\
namespace \"urn:b\";\
prefix b_mod;\
include bsub;\
include btop;\
feature foo;\
grouping gg {\
leaf bar-gggg {\
type string;\
}\
}\
container x {\
leaf bar-leaf {\
if-feature \"bar\";\
type string;\
}\
uses gg {\
if-feature \"bar\";\
}\
leaf baz {\
if-feature \"foo\";\
type string;\
}\
leaf bubba {\
type string;\
}\
}\
augment \"/x\" {\
if-feature \"bar\";\
container bar-y;\
}\
rpc bar-rpc {\
if-feature \"bar\";\
}\
rpc foo-rpc {\
if-feature \"foo\";\
}\
}";
const char *lys_module_a_with_typo = \
"<?xml version=\"1.0\" encoding=\"UTF-8\"?> \
<module_typo name=\"a\" \
xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" \
xmlns:a=\"urn:a\"> \
<namespace uri=\"urn:a\"/> \
<prefix value=\"a_mod\"/> \
<include module=\"asub\"/> \
<include module=\"atop\"/> \
<feature name=\"foo\"/> \
<grouping name=\"gg\"> \
<leaf name=\"bar-gggg\"> \
<type name=\"string\"/> \
</leaf> \
</grouping> \
<container name=\"x\"> \
<leaf name=\"bar-leaf\"> \
<if-feature name=\"bar\"/> \
<type name=\"string\"/> \
</leaf> \
<uses name=\"gg\"> \
<if-feature name=\"bar\"/> \
</uses> \
<leaf name=\"baz\"> \
<if-feature name=\"foo\"/> \
<type name=\"string\"/> \
</leaf> \
<leaf name=\"bubba\"> \
<type name=\"string\"/> \
</leaf> \
</container> \
<augment target-node=\"/x\"> \
<if-feature name=\"bar\"/> \
<container name=\"bar-y\"> \
<leaf name=\"ll\"> \
<type name=\"string\"/> \
</leaf> \
</container> \
</augment> \
<rpc name=\"bar-rpc\"> \
<if-feature name=\"bar\"/> \
</rpc> \
<rpc name=\"foo-rpc\"> \
<if-feature name=\"foo\"/> \
</rpc> \
</module> \
";
const char *result_tree = "\
module: a\n\
+--rw top\n\
| +--rw bar-sub2\n\
+--rw x\n\
+--rw bubba? string\n";
const char *result_yang = "\
module a {\n\
namespace \"urn:a\";\n\
prefix a_mod;\n\
\n\
include \"asub\";\n\
\n\
include \"atop\";\n\
\n\
revision 2015-01-01 {\n\
description\n\
\"version 1\";\n\
reference\n\
\"RFC XXXX\";\n\
}\n\
\n\
feature foo;\n\
\n\
grouping gg {\n\
leaf bar-gggg {\n\
type string;\n\
}\n\
}\n\
\n\
container x {\n\
leaf bar-leaf {\n\
if-feature \"bar\";\n\
type string;\n\
}\n\n\
uses gg {\n\
if-feature \"bar\";\n\
}\n\n\
leaf baz {\n\
if-feature \"foo\";\n\
type string;\n\
}\n\n\
leaf bubba {\n\
type string;\n\
}\n\
}\n\
\n\
augment \"/x\" {\n\
if-feature \"bar\";\n\
container bar-y {\n\
leaf ll {\n\
type string;\n\
}\n\
}\n\
}\n\
\n\
rpc bar-rpc {\n\
if-feature \"bar\";\n\
}\n\
\n\
rpc foo-rpc {\n\
if-feature \"foo\";\n\
}\n\
}\n";
const char *result_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_mod=\"urn:a\">\n\
<namespace uri=\"urn:a\"/>\n\
<prefix value=\"a_mod\"/>\n\
<include module=\"asub\"/>\n\
<include module=\"atop\"/>\n\
<revision date=\"2015-01-01\">\n\
<description>\n\
<text>version 1</text>\n\
</description>\n\
<reference>\n\
<text>RFC XXXX</text>\n\
</reference>\n\
</revision>\n\
<feature name=\"foo\"/>\n\
<grouping name=\"gg\">\n\
<leaf name=\"bar-gggg\">\n\
<type name=\"string\"/>\n\
</leaf>\n\
</grouping>\n\
<container name=\"x\">\n\
<leaf name=\"bar-leaf\">\n\
<if-feature name=\"bar\"/>\n\
<type name=\"string\"/>\n\
</leaf>\n\
<uses name=\"gg\">\n\
<if-feature name=\"bar\"/>\n\
</uses>\n\
<leaf name=\"baz\">\n\
<if-feature name=\"foo\"/>\n\
<type name=\"string\"/>\n\
</leaf>\n\
<leaf name=\"bubba\">\n\
<type name=\"string\"/>\n\
</leaf>\n\
</container>\n\
<augment target-node=\"/x\">\n\
<if-feature name=\"bar\"/>\n\
<container name=\"bar-y\">\n\
<leaf name=\"ll\">\n\
<type name=\"string\"/>\n\
</leaf>\n\
</container>\n\
</augment>\n\
<rpc name=\"bar-rpc\">\n\
<if-feature name=\"bar\"/>\n\
</rpc>\n\
<rpc name=\"foo-rpc\">\n\
<if-feature name=\"foo\"/>\n\
</rpc>\n\
</module>\n";
TEST(test_ly_ctx_parse_module_mem)
{
const char *yang_folder = TESTS_DIR "/api/files";
try {
auto ctx = std::make_shared<libyang::Context>(yang_folder);
ASSERT_NOTNULL(ctx);
auto module = ctx->parse_module_mem(lys_module_a, LYS_IN_YIN);
ASSERT_NOTNULL(module);
ASSERT_STREQ("a", module->name());
module = ctx->parse_module_mem(lys_module_b, LYS_IN_YANG);
ASSERT_NOTNULL(module);
ASSERT_STREQ("b", module->name());
} catch (const std::exception& e) {
mt::printFailed(e.what(), stdout);
throw;
}
}
TEST(test_ly_ctx_parse_module_mem_invalid)
{
const char *yang_folder = TESTS_DIR "/api/files";
try {
auto ctx = std::make_shared<libyang::Context>(yang_folder);
ASSERT_NOTNULL(ctx);
ctx->parse_module_mem(lys_module_a_with_typo, LYS_IN_YIN);
throw std::runtime_error("exception not thrown");
} catch (const std::exception& e) {
ASSERT_STREQ("Module parsing failed.", e.what());
return;
}
}
TEST(test_ly_ctx_parse_module_fd)
{
const char *yang_folder = TESTS_DIR "/api/files";
const char *yin_file = TESTS_DIR "/api/files/a.yin";
const char *yang_file = TESTS_DIR "/api/files/b.yang";
try {
auto ctx = std::make_shared<libyang::Context>(yang_folder);
ASSERT_NOTNULL(ctx);
FILE *f = fopen(yin_file, "r");
auto fd = fileno(f);
auto module = ctx->parse_module_fd(fd, LYS_IN_YIN);
ASSERT_NOTNULL(module);
ASSERT_STREQ("a", module->name());
fclose(f);
f = fopen(yang_file, "r");
fd = fileno(f);
module = ctx->parse_module_fd(fd, LYS_IN_YANG);
ASSERT_NOTNULL(module);
ASSERT_STREQ("b", module->name());
fclose(f);
} catch (const std::exception& e) {
mt::printFailed(e.what(), stdout);
throw;
}
}
TEST(test_ly_ctx_parse_module_fd_invalid)
{
const char *yang_folder = TESTS_DIR "/api/files";
const char *yin_file = TESTS_DIR "/api/files/a.yin";
try {
auto ctx = std::make_shared<libyang::Context>(yang_folder);
ASSERT_NOTNULL(ctx);
FILE *f = fopen(yin_file, "r");
auto fd = fileno(f);
auto module = ctx->parse_module_fd(fd, LYS_IN_YANG);
throw std::runtime_error("exception not thrown");
} catch( const std::exception& e ) {
ASSERT_STREQ("Module parsing failed.", e.what());
return;
}
}
TEST(test_ly_ctx_parse_module_path)
{
const char *yang_folder = TESTS_DIR "/api/files";
const char *yin_file = TESTS_DIR "/api/files/a.yin";
const char *yang_file = TESTS_DIR "/api/files/b.yang";
try {
auto ctx = std::make_shared<libyang::Context>(yang_folder);
ASSERT_NOTNULL(ctx);
auto module = ctx->parse_module_path(yin_file, LYS_IN_YIN);
ASSERT_NOTNULL(module);
ASSERT_STREQ("a", module->name());
module = ctx->parse_module_path(yang_file, LYS_IN_YANG);
ASSERT_NOTNULL(module);
ASSERT_STREQ("b", module->name());
} catch (const std::exception& e) {
mt::printFailed(e.what(), stdout);
throw;
}
}
TEST(test_ly_ctx_parse_module_path_invalid)
{
const char *yang_folder = TESTS_DIR "/api/files";
const char *yin_file = TESTS_DIR "/api/files/a.yin";
try {
auto ctx = std::make_shared<libyang::Context>(yang_folder);
ASSERT_NOTNULL(ctx);
auto module = ctx->parse_module_path(yin_file, LYS_IN_YANG);
throw std::runtime_error("exception not thrown");
} catch( const std::exception& e ) {
ASSERT_STREQ("Module parsing failed.", e.what());
return;
}
}
TEST(test_ly_module_print_mem_tree)
{
const char *yang_folder = TESTS_DIR "/api/files";
try {
auto ctx = std::make_shared<libyang::Context>(yang_folder);
ASSERT_NOTNULL(ctx);
auto module = ctx->parse_module_mem(lys_module_a, LYS_IN_YIN);
ASSERT_NOTNULL(module);
auto result = module->print_mem(LYS_OUT_TREE, 0);
ASSERT_STREQ(result_tree, result);
} catch (const std::exception& e) {
mt::printFailed(e.what(), stdout);
throw;
}
}
TEST(test_ly_module_print_mem_yang)
{
const char *yang_folder = TESTS_DIR "/api/files";
try {
auto ctx = std::make_shared<libyang::Context>(yang_folder);
ASSERT_NOTNULL(ctx);
auto module = ctx->parse_module_mem(lys_module_a, LYS_IN_YIN);
ASSERT_NOTNULL(module);
auto result = module->print_mem(LYS_OUT_YANG, 0);
ASSERT_STREQ(result_yang, result);
} catch (const std::exception& e) {
mt::printFailed(e.what(), stdout);
throw;
}
}
TEST(test_ly_module_print_mem_yin)
{
const char *yang_folder = TESTS_DIR "/api/files";
try {
auto ctx = std::make_shared<libyang::Context>(yang_folder);
ASSERT_NOTNULL(ctx);
auto module = ctx->parse_module_mem(lys_module_a, LYS_IN_YIN);
ASSERT_NOTNULL(module);
auto result = module->print_mem(LYS_OUT_YIN, 0);
ASSERT_STREQ(result_yin, result);
} catch (const std::exception& e) {
mt::printFailed(e.what(), stdout);
throw;
}
}
TEST(test_ly_schema_node_find_path)
{
const char *yang_folder = TESTS_DIR "/api/files";
try {
auto ctx = std::make_shared<libyang::Context>(yang_folder);
ASSERT_NOTNULL(ctx);
auto module = ctx->parse_module_mem(lys_module_a, LYS_IN_YIN);
ASSERT_NOTNULL(module);
auto schema_node = module->data();
ASSERT_NOTNULL(schema_node);
auto set = schema_node->find_path("/a:x/*");
ASSERT_NOTNULL(set);
ASSERT_EQ(5, set->number());
set = schema_node->find_path("/a:x//*");
ASSERT_NOTNULL(set);
ASSERT_EQ(6, set->number());
set = schema_node->find_path("/a:x//.");
ASSERT_NOTNULL(set);
ASSERT_EQ(7, set->number());
} catch (const std::exception& e) {
mt::printFailed(e.what(), stdout);
throw;
}
}
TEST(test_ly_schema_node_path)
{
const char *yang_folder = TESTS_DIR "/api/files";
try {
auto ctx = std::make_shared<libyang::Context>(yang_folder);
ASSERT_NOTNULL(ctx);
auto module = ctx->parse_module_mem(lys_module_a, LYS_IN_YIN);
ASSERT_NOTNULL(module);
auto schema_node = module->data();
ASSERT_NOTNULL(schema_node);
const char *path_template = "/a:x/a:bar-gggg";
auto set = schema_node->find_path(path_template);
ASSERT_NOTNULL(set);
auto schemas = set->schema();
auto schema = schemas.at(0);
auto path = schema->path(0);
ASSERT_STREQ(path_template, path);
} catch (const std::exception& e) {
mt::printFailed(e.what(), stdout);
throw;
}
}
TEST(test_ly_module_data_instatiables)
{
const char *yang_folder = TESTS_DIR "/api/files";
const char *module_name1 = "b";
try {
auto ctx = std::make_shared<libyang::Context>(yang_folder);
ASSERT_NOTNULL(ctx);
auto module = ctx->load_module(module_name1);
ASSERT_NOTNULL(module);
ASSERT_STREQ(module_name1, module->name());
auto list = std::make_shared<std::vector<libyang::S_Schema_Node>>(module->data_instantiables(0));
ASSERT_NOTNULL(list);
ASSERT_EQ(1, list->size());
} catch( const std::exception& e ) {
mt::printFailed(e.what(), stdout);
throw;
}
}
TEST(test_ly_schema_child_instatiables)
{
const char *yang_folder = TESTS_DIR "/api/files";
const char *module_name = "b";
try {
auto ctx = std::make_shared<libyang::Context>(yang_folder);
ASSERT_NOTNULL(ctx);
auto module = ctx->load_module(module_name);
ASSERT_NOTNULL(module);
ASSERT_STREQ(module_name, module->name());
auto list = std::make_shared<std::vector<libyang::S_Schema_Node>>(module->data_instantiables(0));
ASSERT_NOTNULL(list);
ASSERT_EQ(1, list->size());
auto child_list = std::make_shared<std::vector<libyang::S_Schema_Node>>(list->front()->child_instantiables(0));
ASSERT_NOTNULL(child_list);
ASSERT_EQ(3, child_list->size());
} catch( const std::exception& e ) {
mt::printFailed(e.what(), stdout);
throw;
}
}
TEST_MAIN();