1
0
Fork 0

Adding upstream version 3.1.0+dfsg.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-05 08:00:08 +01:00
parent 64dbec996d
commit cfcebb1a7d
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
569 changed files with 205393 additions and 0 deletions

View file

@ -0,0 +1,79 @@
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
set(format_sources
${format_sources}
${CMAKE_CURRENT_SOURCE_DIR}/*.h
${CMAKE_CURRENT_SOURCE_DIR}/basic/*.c
${CMAKE_CURRENT_SOURCE_DIR}/data/*.c
${CMAKE_CURRENT_SOURCE_DIR}/extensions/*.c
${CMAKE_CURRENT_SOURCE_DIR}/schema/*.c
${CMAKE_CURRENT_SOURCE_DIR}/types/*.c
${CMAKE_CURRENT_SOURCE_DIR}/restriction/*.c
${CMAKE_CURRENT_SOURCE_DIR}/node/*.c
PARENT_SCOPE)
ly_add_utest(NAME uint8 SOURCES types/uint8.c)
ly_add_utest(NAME uint16 SOURCES types/uint16.c)
ly_add_utest(NAME uint32 SOURCES types/uint32.c)
ly_add_utest(NAME uint64 SOURCES types/uint64.c)
ly_add_utest(NAME int8 SOURCES types/int8.c)
ly_add_utest(NAME int16 SOURCES types/int16.c)
ly_add_utest(NAME int32 SOURCES types/int32.c)
ly_add_utest(NAME int64 SOURCES types/int64.c)
ly_add_utest(NAME string SOURCES types/string.c)
ly_add_utest(NAME bits SOURCES types/bits.c)
ly_add_utest(NAME binary SOURCES types/binary.c)
ly_add_utest(NAME inet_types SOURCES types/inet_types.c)
ly_add_utest(NAME yang_types SOURCES types/yang_types.c)
ly_add_utest(NAME enumeration SOURCES types/enumeration.c)
ly_add_utest(NAME instanceid SOURCES types/instanceid.c)
ly_add_utest(NAME instanceid_keys SOURCES types/instanceid_keys.c)
ly_add_utest(NAME union SOURCES types/union.c)
ly_add_utest(NAME boolean SOURCES types/boolean.c)
ly_add_utest(NAME decimal64 SOURCES types/decimal64.c)
ly_add_utest(NAME empty SOURCES types/empty.c)
ly_add_utest(NAME identityref SOURCES types/identityref.c)
ly_add_utest(NAME leafref SOURCES types/leafref.c)
ly_add_utest(NAME range SOURCES restriction/test_range.c)
ly_add_utest(NAME pattern SOURCES restriction/test_pattern.c)
ly_add_utest(NAME list SOURCES node/list.c)
ly_add_utest(NAME common SOURCES basic/test_common.c)
ly_add_utest(NAME set SOURCES basic/test_set.c)
ly_add_utest(NAME hash_table SOURCES basic/test_hash_table.c)
ly_add_utest(NAME inout SOURCES basic/test_inout.c)
ly_add_utest(NAME context SOURCES basic/test_context.c)
if(NOT WIN32)
ly_add_utest(NAME plugins SOURCES basic/test_plugins.c)
endif()
ly_add_utest(NAME xml SOURCES basic/test_xml.c)
ly_add_utest(NAME json SOURCES basic/test_json.c)
ly_add_utest(NAME xpath SOURCES basic/test_xpath.c)
ly_add_utest(NAME yanglib SOURCES basic/test_yanglib.c)
ly_add_utest(NAME schema SOURCES schema/test_schema.c)
ly_add_utest(NAME yang SOURCES schema/test_yang.c)
ly_add_utest(NAME yin SOURCES schema/test_yin.c)
ly_add_utest(NAME tree_schema_compile SOURCES schema/test_tree_schema_compile.c)
ly_add_utest(NAME printer_tree SOURCES schema/test_printer_tree.c)
ly_add_utest(NAME tree_data SOURCES data/test_tree_data.c)
ly_add_utest(NAME tree_data_sorted SOURCES data/test_tree_data_sorted.c)
ly_add_utest(NAME new SOURCES data/test_new.c)
ly_add_utest(NAME parser_xml SOURCES data/test_parser_xml.c)
ly_add_utest(NAME printer_xml SOURCES data/test_printer_xml.c)
ly_add_utest(NAME printer_json SOURCES data/test_printer_json.c)
ly_add_utest(NAME parser_json SOURCES data/test_parser_json.c)
ly_add_utest(NAME lyb SOURCES data/test_lyb.c)
ly_add_utest(NAME validation SOURCES data/test_validation.c)
ly_add_utest(NAME merge SOURCES data/test_merge.c)
ly_add_utest(NAME diff SOURCES data/test_diff.c)
ly_add_utest(NAME metadata SOURCES extensions/test_metadata.c)
ly_add_utest(NAME nacm SOURCES extensions/test_nacm.c)
ly_add_utest(NAME yangdata SOURCES extensions/test_yangdata.c)
ly_add_utest(NAME schema_mount SOURCES extensions/test_schema_mount.c)
ly_add_utest(NAME structure SOURCES extensions/test_structure.c)

View file

@ -0,0 +1,416 @@
/**
* @file test_common.c
* @author: Radek Krejci <rkrejci@cesnet.cz>
* @brief unit tests for functions from common.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 "ly_common.h"
static void
test_utf8(void **UNUSED(state))
{
char buf[5] = {0};
const char *str = buf;
unsigned int c;
size_t len;
/* test invalid UTF-8 characters in lyxml_getutf8
* - https://en.wikipedia.org/wiki/UTF-8 */
buf[0] = (char)0x04;
assert_int_equal(LY_EINVAL, ly_getutf8(&str, &c, &len));
buf[0] = (char)0x80;
assert_int_equal(LY_EINVAL, ly_getutf8(&str, &c, &len));
buf[0] = (char)0xc0;
buf[1] = (char)0x00;
assert_int_equal(LY_EINVAL, ly_getutf8(&str, &c, &len));
buf[1] = (char)0x80;
assert_int_equal(LY_EINVAL, ly_getutf8(&str, &c, &len));
buf[0] = (char)0xe0;
buf[1] = (char)0x00;
buf[2] = (char)0x80;
assert_int_equal(LY_EINVAL, ly_getutf8(&str, &c, &len));
buf[1] = (char)0x80;
assert_int_equal(LY_EINVAL, ly_getutf8(&str, &c, &len));
buf[0] = (char)0xf0;
buf[1] = (char)0x00;
buf[2] = (char)0x80;
buf[3] = (char)0x80;
assert_int_equal(LY_EINVAL, ly_getutf8(&str, &c, &len));
buf[1] = (char)0x80;
assert_int_equal(LY_EINVAL, ly_getutf8(&str, &c, &len));
}
static void
test_parse_int(void **UNUSED(state))
{
const char *str;
int64_t i = 500;
str = "10";
assert_int_equal(LY_SUCCESS, ly_parse_int(str, strlen(str), -10, 10, 10, &i));
assert_int_equal(i, 10);
/* leading zeros are allowed, trailing whitespaces are allowed */
str = "000\n\t ";
assert_int_equal(LY_SUCCESS, ly_parse_int(str, strlen(str), -10, 10, 10, &i));
assert_int_equal(i, 0);
/* negative value */
str = "-10";
assert_int_equal(LY_SUCCESS, ly_parse_int(str, strlen(str), -10, 10, 10, &i));
assert_int_equal(i, -10);
/* non-NULL terminated string */
str = "+5sometext";
assert_int_equal(LY_SUCCESS, ly_parse_int(str, 2, -10, 10, 10, &i));
assert_int_equal(i, 5);
/* out of bounds value */
str = "11";
assert_int_equal(LY_EDENIED, ly_parse_int(str, strlen(str), -10, 10, 10, &i));
str = "-11";
assert_int_equal(LY_EDENIED, ly_parse_int(str, strlen(str), -10, 10, 10, &i));
/* NaN */
str = "zero";
assert_int_equal(LY_EVALID, ly_parse_int(str, strlen(str), -10, 10, 10, &i));
/* mixing number with text */
str = "10zero";
assert_int_equal(LY_EVALID, ly_parse_int(str, strlen(str), -10, 10, 10, &i));
str = "10 zero";
assert_int_equal(LY_EVALID, ly_parse_int(str, strlen(str), -10, 10, 10, &i));
}
static void
test_parse_uint(void **UNUSED(state))
{
const char *str;
uint64_t u = 500;
str = "10";
assert_int_equal(LY_SUCCESS, ly_parse_uint(str, strlen(str), 10, 10, &u));
assert_int_equal(u, 10);
/* leading zeros are allowed, trailing whitespaces are allowed */
str = "000\n\t ";
assert_int_equal(LY_SUCCESS, ly_parse_uint(str, strlen(str), 10, 10, &u));
assert_int_equal(u, 0);
/* non-NULL terminated string */
str = "+5sometext";
assert_int_equal(LY_SUCCESS, ly_parse_uint(str, 2, 10, 10, &u));
assert_int_equal(u, 5);
/* out of bounds value */
str = "11";
assert_int_equal(LY_EDENIED, ly_parse_uint(str, strlen(str), 10, 10, &u));
str = "-1";
assert_int_equal(LY_EDENIED, ly_parse_uint(str, strlen(str), (uint64_t)-1, 10, &u));
/* NaN */
str = "zero";
assert_int_equal(LY_EVALID, ly_parse_uint(str, strlen(str), 10, 10, &u));
/* mixing number with text */
str = "10zero";
assert_int_equal(LY_EVALID, ly_parse_uint(str, strlen(str), 10, 10, &u));
str = "10 zero";
assert_int_equal(LY_EVALID, ly_parse_uint(str, strlen(str), 10, 10, &u));
}
static void
test_parse_nodeid(void **UNUSED(state))
{
const char *str;
const char *prefix, *name;
size_t prefix_len, name_len;
str = "123";
assert_int_equal(LY_EINVAL, ly_parse_nodeid(&str, &prefix, &prefix_len, &name, &name_len));
str = "a12_-.!";
assert_int_equal(LY_SUCCESS, ly_parse_nodeid(&str, &prefix, &prefix_len, &name, &name_len));
assert_null(prefix);
assert_int_equal(0, prefix_len);
assert_non_null(name);
assert_int_equal(6, name_len);
assert_int_equal(0, strncmp("a12_-.", name, name_len));
assert_string_equal("!", str);
str = "a12_-.:_b2 xxx";
assert_int_equal(LY_SUCCESS, ly_parse_nodeid(&str, &prefix, &prefix_len, &name, &name_len));
assert_non_null(prefix);
assert_int_equal(6, prefix_len);
assert_int_equal(0, strncmp("a12_-.", prefix, prefix_len));
assert_non_null(name);
assert_int_equal(3, name_len);
assert_int_equal(0, strncmp("_b2", name, name_len));
assert_string_equal(" xxx", str);
}
static void
test_parse_instance_predicate(void **UNUSED(state))
{
const char *str, *errmsg;
const char *prefix, *id, *value;
size_t prefix_len, id_len, value_len;
str = "[ex:name='fred']";
assert_int_equal(LY_SUCCESS, ly_parse_instance_predicate(&str, strlen(str), LYD_XML, &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
assert_string_equal(str, "");
assert_string_equal(prefix, "ex:name='fred']");
assert_int_equal(prefix_len, 2);
assert_string_equal(id, "name='fred']");
assert_int_equal(id_len, 4);
assert_string_equal(value, "fred']");
assert_int_equal(value_len, 4);
str = "[ex:ip = \"[192.0.2.1]\"][ex:port='80']";
assert_int_equal(LY_SUCCESS, ly_parse_instance_predicate(&str, strlen(str), LYD_XML, &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
assert_string_equal(str, "[ex:port='80']");
assert_string_equal(prefix, "ex:ip = \"[192.0.2.1]\"][ex:port='80']");
assert_int_equal(prefix_len, 2);
assert_string_equal(id, "ip = \"[192.0.2.1]\"][ex:port='80']");
assert_int_equal(id_len, 2);
assert_string_equal(value, "[192.0.2.1]\"][ex:port='80']");
assert_int_equal(value_len, 11);
str = "[. = 'blowfish-cbc']";
assert_int_equal(LY_SUCCESS, ly_parse_instance_predicate(&str, strlen(str), LYD_XML, &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
assert_string_equal(str, "");
assert_null(prefix);
assert_int_equal(prefix_len, 0);
assert_string_equal(id, ". = 'blowfish-cbc']");
assert_int_equal(id_len, 1);
assert_string_equal(value, "blowfish-cbc']");
assert_int_equal(value_len, 12);
str = "[ 3 ]";
assert_int_equal(LY_SUCCESS, ly_parse_instance_predicate(&str, strlen(str), LYD_XML, &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
assert_string_equal(str, "");
assert_null(prefix);
assert_int_equal(prefix_len, 0);
assert_null(id);
assert_int_equal(id_len, 0);
assert_string_equal(value, "3 ]");
assert_int_equal(value_len, 1);
/* invalid predicates */
/* position must be positive integer */
str = "[0]";
assert_int_equal(LY_EVALID, ly_parse_instance_predicate(&str, strlen(str), LYD_XML, &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
assert_string_equal(errmsg, "The position predicate cannot be zero.");
str = "[-1]";
assert_int_equal(LY_EVALID, ly_parse_instance_predicate(&str, strlen(str), LYD_XML, &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
assert_string_equal(errmsg, "Invalid instance predicate format (negative position or invalid node-identifier).");
/* invalid node-identifier */
str = "[$node='value']";
assert_int_equal(LY_EVALID, ly_parse_instance_predicate(&str, strlen(str), LYD_XML, &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
assert_string_equal(errmsg, "Invalid node-identifier.");
str = "[.node='value']";
assert_int_equal(LY_EVALID, ly_parse_instance_predicate(&str, strlen(str), LYD_XML, &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
assert_string_equal(errmsg, "Unexpected character instead of '=' in leaf-list-predicate.");
str = "[13node='value']";
assert_int_equal(LY_EVALID, ly_parse_instance_predicate(&str, strlen(str), LYD_XML, &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
assert_string_equal(errmsg, "Predicate (pos) is not terminated by \']\' character.");
str = "[ex:node]";
assert_int_equal(LY_EVALID, ly_parse_instance_predicate(&str, strlen(str), LYD_XML, &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
assert_string_equal(errmsg, "Unexpected character instead of '=' in key-predicate.");
str = "[ex:node= value]";
assert_int_equal(LY_EVALID, ly_parse_instance_predicate(&str, strlen(str), LYD_XML, &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
assert_string_equal(errmsg, "String value is not quoted.");
str = "[ex:node='value\"]";
assert_int_equal(LY_EVALID, ly_parse_instance_predicate(&str, strlen(str), LYD_XML, &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
assert_string_equal(errmsg, "Value is not terminated quoted-string.");
str = "[ex:node='value ]";
assert_int_equal(LY_EVALID, ly_parse_instance_predicate(&str, strlen(str), LYD_XML, &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
assert_string_equal(errmsg, "Value is not terminated quoted-string.");
str = "[ex:node=\"value\"[3]";
assert_int_equal(LY_EVALID, ly_parse_instance_predicate(&str, strlen(str), LYD_XML, &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
assert_string_equal(errmsg, "Predicate (key-predicate) is not terminated by \']\' character.");
str = "[.=\"value\"[3]";
assert_int_equal(LY_EVALID, ly_parse_instance_predicate(&str, strlen(str), LYD_XML, &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
assert_string_equal(errmsg, "Predicate (leaf-list-predicate) is not terminated by \']\' character.");
/* the limit of the string is too short, it ends one character earlier */
str = "[ex:node='value']";
assert_int_equal(LY_EINVAL, ly_parse_instance_predicate(&str, strlen(str) - 1, LYD_XML, &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
assert_string_equal(errmsg, "Predicate is incomplete.");
}
static void
test_value_prefix_next(void **UNUSED(state))
{
const char *next;
ly_bool is_prefix;
uint32_t bytes;
assert_int_equal(LY_SUCCESS, ly_value_prefix_next(NULL, NULL, &bytes, &is_prefix, &next));
assert_int_equal(0, bytes);
assert_int_equal(LY_SUCCESS, ly_value_prefix_next("", NULL, &bytes, &is_prefix, &next));
assert_int_equal(0, bytes);
/* prefix */
next = "pref:";
assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
assert_int_equal(4, bytes);
assert_null(next);
assert_int_equal(1, is_prefix);
/* no-prefix */
next = "node";
assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
assert_int_equal(4, bytes);
assert_null(next);
assert_int_equal(0, is_prefix);
/* no-prefix */
next = "::::";
assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
assert_int_equal(4, bytes);
assert_null(next);
assert_int_equal(0, is_prefix);
/* no-prefix */
next = "//a/:";
assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
assert_int_equal(5, bytes);
assert_null(next);
assert_int_equal(0, is_prefix);
/* no-prefix */
next = "//a//";
assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
assert_int_equal(5, bytes);
assert_null(next);
assert_int_equal(0, is_prefix);
/* prefix, prefix */
next = "pref1:pref2:";
assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
assert_int_equal(5, bytes);
assert_string_equal(next, "pref2:");
assert_int_equal(1, is_prefix);
assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
assert_int_equal(5, bytes);
assert_null(next);
assert_int_equal(1, is_prefix);
/* prefix, no-prefix */
next = "pref:node";
assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
assert_int_equal(4, bytes);
assert_string_equal(next, "node");
assert_int_equal(1, is_prefix);
assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
assert_int_equal(4, bytes);
assert_null(next);
assert_int_equal(0, is_prefix);
/* no-prefix, prefix */
next = "/pref:";
assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
assert_int_equal(1, bytes);
assert_string_equal(next, "pref:");
assert_int_equal(0, is_prefix);
assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
assert_int_equal(4, bytes);
assert_null(next);
assert_int_equal(1, is_prefix);
/* no-prefix, prefix */
next = "//pref:";
assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
assert_int_equal(2, bytes);
assert_string_equal(next, "pref:");
assert_int_equal(0, is_prefix);
assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
assert_int_equal(4, bytes);
assert_null(next);
assert_int_equal(1, is_prefix);
/* no-prefix, prefix, no-prefix */
next = "/pref:node";
assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
assert_int_equal(1, bytes);
assert_string_equal(next, "pref:node");
assert_int_equal(0, is_prefix);
assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
assert_int_equal(4, bytes);
assert_string_equal(next, "node");
assert_int_equal(1, is_prefix);
assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
assert_int_equal(4, bytes);
assert_null(next);
assert_int_equal(0, is_prefix);
/* prefix, no-prefix, prefix */
next = "pref:node pref:";
assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
assert_int_equal(4, bytes);
assert_string_equal(next, "node pref:");
assert_int_equal(1, is_prefix);
assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
assert_int_equal(5, bytes);
assert_string_equal(next, "pref:");
assert_int_equal(0, is_prefix);
assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
assert_int_equal(4, bytes);
assert_null(next);
assert_int_equal(1, is_prefix);
/* prefix, no-prefix, prefix, no-prefix */
next = "pref:node /pref:node";
assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
assert_int_equal(4, bytes);
assert_string_equal(next, "node /pref:node");
assert_int_equal(1, is_prefix);
assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
assert_int_equal(6, bytes);
assert_string_equal(next, "pref:node");
assert_int_equal(0, is_prefix);
assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
assert_int_equal(4, bytes);
assert_string_equal(next, "node");
assert_int_equal(1, is_prefix);
assert_int_equal(LY_SUCCESS, ly_value_prefix_next(next, NULL, &bytes, &is_prefix, &next));
assert_int_equal(4, bytes);
assert_null(next);
assert_int_equal(0, is_prefix);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_utf8),
UTEST(test_parse_int),
UTEST(test_parse_uint),
UTEST(test_parse_nodeid),
UTEST(test_parse_instance_predicate),
UTEST(test_value_prefix_next),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,262 @@
/**
* @file test_hash_table.c
* @author: Radek Krejci <rkrejci@cesnet.cz>
* @brief unit tests for functions from hash_table.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 <stdlib.h>
#include "hash_table.h"
#include "ly_common.h"
static void
test_invalid_arguments(void **state)
{
assert_int_equal(LY_EINVAL, lydict_insert(NULL, NULL, 0, NULL));
CHECK_LOG_LASTMSG("Invalid argument ctx (lydict_insert()).");
assert_int_equal(LY_EINVAL, lydict_insert_zc(NULL, NULL, NULL));
CHECK_LOG_LASTMSG("Invalid argument ctx (lydict_insert_zc()).");
assert_int_equal(LY_EINVAL, lydict_insert_zc(UTEST_LYCTX, NULL, NULL));
CHECK_LOG_CTX("Invalid argument str_p (lydict_insert_zc()).", NULL, 0);
}
static void
test_dict_hit(void **state)
{
const char *str1, *str2, *str3;
/* insert 2 strings, one of them repeatedly */
assert_int_equal(LY_SUCCESS, lydict_insert(UTEST_LYCTX, "test1", 0, &str1));
assert_non_null(str1);
/* via zerocopy we have to get the same pointer as provided */
assert_non_null(str2 = strdup("test2"));
assert_int_equal(LY_SUCCESS, lydict_insert_zc(UTEST_LYCTX, (char *)str2, &str3));
assert_ptr_equal(str2, str3);
/* here we get the same pointer as in case the string was inserted first time */
assert_int_equal(LY_SUCCESS, lydict_insert(UTEST_LYCTX, "test1", 0, &str2));
assert_non_null(str2);
assert_ptr_equal(str1, str2);
/* remove strings, but the repeatedly inserted only once */
lydict_remove(UTEST_LYCTX, "test1");
lydict_remove(UTEST_LYCTX, "test2");
/* destroy dictionary - should raise warning about data presence */
ly_ctx_destroy(UTEST_LYCTX);
UTEST_LYCTX = NULL;
CHECK_LOG_LASTMSG("String \"test1\" not freed from the dictionary, refcount 1.");
#ifndef NDEBUG
/* cleanup */
free((char *)str1);
#endif
}
static uint8_t
ht_equal_clb(void *val1, void *val2, uint8_t mod, void *cb_data)
{
int *v1, *v2;
(void)mod;
(void)cb_data;
v1 = (int *)val1;
v2 = (int *)val2;
return *v1 == *v2;
}
static void
test_ht_basic(void **UNUSED(state))
{
uint32_t i;
struct ly_ht *ht;
assert_non_null(ht = lyht_new(8, sizeof(int), ht_equal_clb, NULL, 0));
i = 2;
assert_int_equal(LY_ENOTFOUND, lyht_find(ht, &i, i, NULL));
assert_int_equal(LY_SUCCESS, lyht_insert(ht, &i, i, NULL));
assert_int_equal(LY_SUCCESS, lyht_find(ht, &i, i, NULL));
assert_int_equal(LY_SUCCESS, lyht_remove(ht, &i, i));
assert_int_equal(LY_ENOTFOUND, lyht_find(ht, &i, i, NULL));
assert_int_equal(LY_ENOTFOUND, lyht_remove(ht, &i, i));
CHECK_LOG_LASTMSG("Invalid argument hash (lyht_remove_with_resize_cb()).");
lyht_free(ht, NULL);
}
static void
test_ht_resize(void **UNUSED(state))
{
uint32_t i;
struct ly_ht *ht;
assert_non_null(ht = lyht_new(8, sizeof(int), ht_equal_clb, NULL, 1));
assert_int_equal(8, ht->size);
/* insert records into indexes 2-7 */
for (i = 2; i < 8; ++i) {
assert_int_equal(LY_SUCCESS, lyht_insert(ht, &i, i, NULL));
}
/* check that table resized */
assert_int_equal(16, ht->size);
/* check expected content of the table */
for (i = 0; i < 16; ++i) {
if ((i >= 2) && (i < 8)) {
/* inserted data on indexes 2-7 */
assert_int_not_equal(UINT32_MAX, ht->hlists[i].first);
assert_int_equal(LY_SUCCESS, lyht_find(ht, &i, i, NULL));
} else {
/* nothing otherwise */
assert_int_equal(UINT32_MAX, ht->hlists[i].first);
assert_int_equal(LY_ENOTFOUND, lyht_find(ht, &i, i, NULL));
}
}
/* removing not present data should fail */
for (i = 0; i < 2; ++i) {
assert_int_equal(LY_ENOTFOUND, lyht_remove(ht, &i, i));
CHECK_LOG_LASTMSG("Invalid argument hash (lyht_remove_with_resize_cb()).");
}
/* removing present data, resize should happened
* when we are below 25% of the table filled, so with 3 records left */
for ( ; i < 5; ++i) {
assert_int_equal(LY_SUCCESS, lyht_remove(ht, &i, i));
}
assert_int_equal(8, ht->size);
/* remove the rest */
for ( ; i < 8; ++i) {
assert_int_equal(LY_SUCCESS, lyht_remove(ht, &i, i));
}
for (i = 0; i < 8; ++i) {
assert_int_equal(LY_ENOTFOUND, lyht_find(ht, &i, i, NULL));
}
/* cleanup */
lyht_free(ht, NULL);
}
static void
test_ht_collisions(void **UNUSED(state))
{
#define GET_REC_INT(rec) (*((uint32_t *)&(rec)->val))
uint32_t i;
struct ly_ht_rec *rec;
struct ly_ht *ht;
uint32_t rec_idx;
int count;
assert_non_null(ht = lyht_new(8, sizeof(int), ht_equal_clb, NULL, 1));
for (i = 2; i < 6; ++i) {
assert_int_equal(lyht_insert(ht, &i, 2, NULL), 0);
}
/* check all records */
for (i = 0; i < 8; ++i) {
if (i == 2) {
assert_int_not_equal(UINT32_MAX, ht->hlists[i].first);
} else {
assert_int_equal(UINT32_MAX, ht->hlists[i].first);
}
}
for (i = 0; i < 8; ++i) {
if ((i >= 2) && (i < 6)) {
assert_int_equal(LY_SUCCESS, lyht_find(ht, &i, 2, NULL));
} else {
assert_int_equal(LY_ENOTFOUND, lyht_find(ht, &i, 2, NULL));
}
}
rec_idx = ht->hlists[2].first;
count = 0;
while (rec_idx != UINT32_MAX) {
rec = lyht_get_rec(ht->recs, ht->rec_size, rec_idx);
rec_idx = rec->next;
assert_int_equal(rec->hash, 2);
count++;
}
assert_int_equal(count, 4);
i = 4;
assert_int_equal(lyht_remove(ht, &i, 2), 0);
rec = lyht_get_rec(ht->recs, ht->rec_size, i);
i = 2;
assert_int_equal(lyht_remove(ht, &i, 2), 0);
/* check all records */
for (i = 0; i < 8; ++i) {
if (i == 2) {
assert_int_not_equal(UINT32_MAX, ht->hlists[i].first);
} else {
assert_int_equal(UINT32_MAX, ht->hlists[i].first);
}
}
for (i = 0; i < 8; ++i) {
if ((i == 3) || (i == 5)) {
assert_int_equal(LY_SUCCESS, lyht_find(ht, &i, 2, NULL));
} else {
assert_int_equal(LY_ENOTFOUND, lyht_find(ht, &i, 2, NULL));
}
}
rec_idx = ht->hlists[2].first;
count = 0;
while (rec_idx != UINT32_MAX) {
rec = lyht_get_rec(ht->recs, ht->rec_size, rec_idx);
rec_idx = rec->next;
assert_int_equal(rec->hash, 2);
count++;
}
assert_int_equal(count, 2);
for (i = 0; i < 8; ++i) {
if ((i == 3) || (i == 5)) {
assert_int_equal(lyht_find(ht, &i, 2, NULL), LY_SUCCESS);
} else {
assert_int_equal(lyht_find(ht, &i, 2, NULL), LY_ENOTFOUND);
}
}
i = 3;
assert_int_equal(lyht_remove(ht, &i, 2), 0);
i = 5;
assert_int_equal(lyht_remove(ht, &i, 2), 0);
/* check all records */
for (i = 0; i < 8; ++i) {
assert_int_equal(UINT32_MAX, ht->hlists[i].first);
}
lyht_free(ht, NULL);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_invalid_arguments),
UTEST(test_dict_hit),
UTEST(test_ht_basic),
UTEST(test_ht_resize),
UTEST(test_ht_collisions),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

View file

@ -0,0 +1,407 @@
/**
* @file test_inout.c
* @author: Radek Krejci <rkrejci@cesnet.cz>
* @brief unit tests for input and output handlers functions
*
* Copyright (c) 2020 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 <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "in.h"
#include "log.h"
#include "ly_common.h"
#include "out.h"
#define TEST_INPUT_FILE TESTS_BIN "/libyang_test_input"
#define TEST_OUTPUT_FILE TESTS_BIN "/libyang_test_output"
#define TEST_OUTPUT_FILE2 TESTS_BIN "/libyang_test_output2"
static int
setup_files(void **state)
{
int fd;
UTEST_SETUP;
/* create input */
fd = open(TEST_INPUT_FILE, O_CREAT | O_WRONLY, 00600);
if (fd == -1) {
return 1;
}
/* write something */
if (write(fd, "data", 4) != 4) {
return 1;
}
close(fd);
/* create output */
fd = open(TEST_OUTPUT_FILE, O_CREAT | O_RDONLY, 00600);
if (fd == -1) {
return 1;
}
close(fd);
/* create output2 */
fd = open(TEST_OUTPUT_FILE2, O_CREAT | O_RDONLY, 00600);
if (fd == -1) {
return 1;
}
close(fd);
return 0;
}
static int
teardown_files(void **state)
{
unlink(TEST_INPUT_FILE);
unlink(TEST_OUTPUT_FILE);
unlink(TEST_OUTPUT_FILE2);
UTEST_TEARDOWN;
return 0;
}
static void
test_input_mem(void **UNUSED(state))
{
struct ly_in *in = NULL;
char *str1 = "a", *str2 = "b";
assert_int_equal(LY_EINVAL, ly_in_new_memory(NULL, NULL));
CHECK_LOG_LASTMSG("Invalid argument str (ly_in_new_memory()).");
assert_int_equal(LY_EINVAL, ly_in_new_memory(str1, NULL));
CHECK_LOG_LASTMSG("Invalid argument in (ly_in_new_memory()).");
assert_null(ly_in_memory(NULL, NULL));
CHECK_LOG_LASTMSG("Invalid argument in (ly_in_memory()).");
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str1, &in));
assert_int_equal(LY_IN_MEMORY, ly_in_type(in));
assert_ptr_equal(str1, ly_in_memory(in, str2));
assert_ptr_equal(str2, ly_in_memory(in, NULL));
assert_ptr_equal(str2, ly_in_memory(in, NULL));
ly_in_free(in, 0);
}
static void
test_input_fd(void **UNUSED(state))
{
struct ly_in *in = NULL;
int fd1, fd2;
struct stat statbuf;
assert_int_equal(LY_EINVAL, ly_in_new_fd(-1, NULL));
CHECK_LOG_LASTMSG("Invalid argument fd >= 0 (ly_in_new_fd()).");
assert_int_equal(-1, ly_in_fd(NULL, -1));
CHECK_LOG_LASTMSG("Invalid argument in (ly_in_fd()).");
assert_int_not_equal(-1, fd1 = open(TEST_INPUT_FILE, O_RDONLY));
assert_int_not_equal(-1, fd2 = open(TEST_INPUT_FILE, O_RDONLY));
assert_int_equal(LY_EINVAL, ly_in_new_fd(fd1, NULL));
CHECK_LOG_LASTMSG("Invalid argument in (ly_in_new_fd()).");
assert_int_equal(LY_SUCCESS, ly_in_new_fd(fd1, &in));
assert_int_equal(LY_IN_FD, ly_in_type(in));
assert_ptr_equal(fd1, ly_in_fd(in, fd2));
assert_ptr_equal(fd2, ly_in_fd(in, -1));
assert_ptr_equal(fd2, ly_in_fd(in, -1));
ly_in_free(in, 1);
/* fd1 is still open */
assert_int_equal(0, fstat(fd1, &statbuf));
close(fd1);
#ifndef _WIN32
/* But fd2 was closed by ly_in_free(). This results in an "invalid handler" on Windows. */
errno = 0;
assert_int_equal(-1, fstat(fd2, &statbuf));
assert_int_equal(errno, EBADF);
#endif
}
static void
test_input_file(void **UNUSED(state))
{
struct ly_in *in = NULL;
FILE *f1 = NULL, *f2 = NULL;
assert_int_equal(LY_EINVAL, ly_in_new_file(NULL, NULL));
assert_null(ly_in_file(NULL, NULL));
assert_non_null(f1 = fopen(TEST_INPUT_FILE, "rb"));
assert_non_null(f2 = fopen(TEST_INPUT_FILE, "rb"));
assert_int_equal(LY_EINVAL, ly_in_new_file(f1, NULL));
assert_int_equal(LY_SUCCESS, ly_in_new_file(f1, &in));
assert_int_equal(LY_IN_FILE, ly_in_type(in));
assert_ptr_equal(f1, ly_in_file(in, f2));
assert_ptr_equal(f2, ly_in_file(in, NULL));
assert_ptr_equal(f2, ly_in_file(in, NULL));
ly_in_free(in, 1);
/* f1 is still open */
assert_int_not_equal(-1, fileno(f1));
fclose(f1);
/* but f2 was closed by ly_in_free() */
}
static void
test_input_filepath(void **UNUSED(state))
{
struct ly_in *in = NULL;
const char *path1 = TEST_INPUT_FILE, *path2 = TEST_INPUT_FILE;
assert_int_equal(LY_EINVAL, ly_in_new_filepath(NULL, 0, NULL));
assert_int_equal(LY_EINVAL, ly_in_new_filepath(path1, 0, NULL));
assert_ptr_equal(((void *)-1), ly_in_filepath(NULL, NULL, 0));
assert_int_equal(LY_SUCCESS, ly_in_new_filepath(path1, 0, &in));
assert_int_equal(LY_IN_FILEPATH, ly_in_type(in));
assert_ptr_equal(NULL, ly_in_filepath(in, path2, 0));
assert_string_equal(path2, ly_in_filepath(in, NULL, 0));
ly_in_free(in, 0);
}
static void
test_output_mem(void **UNUSED(state))
{
struct ly_out *out = NULL;
char *buf1 = NULL, *buf2 = NULL;
/* manipulate with the handler */
assert_int_equal(LY_SUCCESS, ly_out_new_memory(&buf1, 0, &out));
assert_int_equal(LY_OUT_MEMORY, ly_out_type(out));
ly_write(out, "test", 4);
assert_ptr_equal(buf1, ly_out_memory(out, &buf2, 0));
assert_ptr_equal(buf2, ly_out_memory(out, NULL, 0));
assert_ptr_equal(buf2, ly_out_memory(out, &buf1, strlen(buf1)));
ly_out_free(out, NULL, 0);
assert_int_equal(LY_SUCCESS, ly_out_new_memory(&buf1, strlen(buf1), &out));
ly_out_free(out, NULL, 1);
/* writing data */
assert_int_equal(LY_SUCCESS, ly_out_new_memory(&buf1, 0, &out));
assert_int_equal(LY_SUCCESS, ly_print(out, "test %s", "print"));
assert_int_equal(10, ly_out_printed(out));
assert_string_equal("test print", buf1);
assert_int_equal(LY_SUCCESS, ly_out_reset(out));
assert_int_equal(LY_SUCCESS, ly_write(out, "rewrite", 8));
assert_int_equal(8, ly_out_printed(out));
assert_string_equal("rewrite", buf1);
ly_out_free(out, NULL, 1);
}
static void
test_output_fd(void **UNUSED(state))
{
struct ly_out *out = NULL;
int fd1, fd2;
char buf[31] = {0};
assert_int_not_equal(-1, fd1 = open(TEST_OUTPUT_FILE, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR));
assert_int_not_equal(-1, fd2 = open(TEST_OUTPUT_FILE, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR));
/* manipulate with the handler */
assert_int_equal(LY_SUCCESS, ly_out_new_fd(fd1, &out));
assert_int_equal(LY_OUT_FD, ly_out_type(out));
assert_ptr_equal(fd1, ly_out_fd(out, fd2));
assert_ptr_equal(fd2, ly_out_fd(out, -1));
assert_ptr_equal(fd2, ly_out_fd(out, fd1));
ly_out_free(out, NULL, 0);
assert_int_equal(0, close(fd2));
assert_int_equal(LY_SUCCESS, ly_out_new_fd(fd1, &out));
ly_out_free(out, NULL, 1);
/* writing data */
assert_int_not_equal(-1, fd1 = open(TEST_OUTPUT_FILE, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR));
assert_int_not_equal(-1, fd2 = open(TEST_OUTPUT_FILE, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR));
/* truncate file to start with no data */
assert_int_equal(0, ftruncate(fd1, 0));
assert_int_equal(LY_SUCCESS, ly_out_new_fd(fd1, &out));
assert_int_equal(LY_SUCCESS, ly_print(out, "test %s", "print"));
assert_int_equal(10, ly_out_printed(out));
ly_print_flush(out);
assert_int_equal(10, read(fd2, buf, 30));
assert_string_equal("test print", buf);
assert_int_equal(0, lseek(fd2, 0, SEEK_SET));
assert_int_equal(LY_SUCCESS, ly_out_reset(out));
assert_int_equal(LY_SUCCESS, ly_write(out, "rewrite", 8));
assert_int_equal(8, ly_out_printed(out));
ly_print_flush(out);
assert_int_equal(8, read(fd2, buf, 30));
assert_string_equal("rewrite", buf);
close(fd2);
ly_out_free(out, NULL, 1);
}
static void
test_output_file(void **UNUSED(state))
{
struct ly_out *out = NULL;
FILE *f1, *f2;
char buf[31] = {0};
assert_non_null(f1 = fopen(TEST_OUTPUT_FILE, "wb"));
assert_non_null(f2 = fopen(TEST_OUTPUT_FILE, "wb"));
/* manipulate with the handler */
assert_int_equal(LY_SUCCESS, ly_out_new_file(f1, &out));
assert_int_equal(LY_OUT_FILE, ly_out_type(out));
assert_ptr_equal(f1, ly_out_file(out, f2));
assert_ptr_equal(f2, ly_out_file(out, NULL));
assert_ptr_equal(f2, ly_out_file(out, f1));
ly_out_free(out, NULL, 0);
assert_int_equal(0, fclose(f2));
assert_int_equal(LY_SUCCESS, ly_out_new_file(f1, &out));
ly_out_free(out, NULL, 1);
/* writing data */
assert_non_null(f1 = fopen(TEST_OUTPUT_FILE, "wb"));
assert_non_null(f2 = fopen(TEST_OUTPUT_FILE, "rb"));
assert_int_equal(LY_SUCCESS, ly_out_new_file(f1, &out));
assert_int_equal(LY_SUCCESS, ly_print(out, "test %s", "print"));
assert_int_equal(10, ly_out_printed(out));
ly_print_flush(out);
assert_non_null(fgets(buf, 31, f2));
assert_string_equal("test print", buf);
assert_int_equal(0, fseek(f2, 0, SEEK_SET));
assert_int_equal(LY_SUCCESS, ly_out_reset(out));
assert_int_equal(LY_SUCCESS, ly_write(out, "rewrite", 8));
assert_int_equal(8, ly_out_printed(out));
ly_print_flush(out);
assert_non_null(fgets(buf, 31, f2));
assert_string_equal("rewrite", buf);
fclose(f2);
ly_out_free(out, NULL, 1);
}
static void
test_output_filepath(void **UNUSED(state))
{
struct ly_out *out = NULL;
FILE *f1;
char buf[31] = {0};
const char *fp1 = TEST_OUTPUT_FILE;
const char *fp2 = TEST_OUTPUT_FILE2;
/* manipulate with the handler */
assert_int_equal(LY_SUCCESS, ly_out_new_filepath(fp1, &out));
assert_int_equal(LY_OUT_FILEPATH, ly_out_type(out));
assert_ptr_equal(NULL, ly_out_filepath(out, fp2));
assert_string_equal(fp2, ly_out_filepath(out, NULL));
assert_ptr_equal(NULL, ly_out_filepath(out, fp1));
ly_out_free(out, NULL, 0);
assert_int_equal(LY_SUCCESS, ly_out_new_filepath(fp1, &out));
ly_out_free(out, NULL, 1);
/* writing data */
assert_non_null(f1 = fopen(fp1, "rb"));
assert_int_equal(LY_SUCCESS, ly_out_new_filepath(fp1, &out));
assert_int_equal(LY_SUCCESS, ly_print(out, "test %s", "print"));
assert_int_equal(10, ly_out_printed(out));
ly_print_flush(out);
assert_non_null(fgets(buf, 31, f1));
assert_string_equal("test print", buf);
assert_int_equal(0, fseek(f1, 0, SEEK_SET));
assert_int_equal(LY_SUCCESS, ly_out_reset(out));
assert_int_equal(LY_SUCCESS, ly_write(out, "rewrite", 8));
assert_int_equal(8, ly_out_printed(out));
ly_print_flush(out);
assert_non_null(fgets(buf, 31, f1));
assert_string_equal("rewrite", buf);
fclose(f1);
ly_out_free(out, NULL, 1);
}
static ssize_t
write_clb(void *user_data, const void *buf, size_t count)
{
return write((uintptr_t)user_data, buf, count);
}
void
close_clb(void *arg)
{
close((uintptr_t)arg);
}
static void
test_output_clb(void **UNUSED(state))
{
struct ly_out *out = NULL;
int fd1, fd2;
char buf[31] = {0};
assert_int_not_equal(-1, fd1 = open(TEST_OUTPUT_FILE, O_RDWR));
assert_int_not_equal(-1, fd2 = open(TEST_OUTPUT_FILE, O_RDWR));
/* manipulate with the handler */
assert_int_equal(LY_SUCCESS, ly_out_new_clb(write_clb, (void *)(intptr_t)fd1, &out));
assert_int_equal(LY_OUT_CALLBACK, ly_out_type(out));
assert_ptr_equal(fd1, ly_out_clb_arg(out, (void *)(intptr_t)fd2));
assert_ptr_equal(fd2, ly_out_clb_arg(out, NULL));
assert_ptr_equal(fd2, ly_out_clb_arg(out, (void *)(intptr_t)fd1));
assert_ptr_equal(write_clb, ly_out_clb(out, write_clb));
ly_out_free(out, NULL, 0);
assert_int_equal(0, close(fd2));
assert_int_equal(LY_SUCCESS, ly_out_new_clb(write_clb, (void *)(intptr_t)fd1, &out));
ly_out_free(out, close_clb, 0);
/* writing data */
assert_int_not_equal(-1, fd1 = open(TEST_OUTPUT_FILE, O_RDWR));
assert_int_not_equal(-1, fd2 = open(TEST_OUTPUT_FILE, O_RDWR));
/* truncate file to start with no data */
assert_int_equal(0, ftruncate(fd1, 0));
assert_int_equal(LY_SUCCESS, ly_out_new_clb(write_clb, (void *)(intptr_t)fd1, &out));
assert_int_equal(LY_SUCCESS, ly_print(out, "test %s", "print"));
assert_int_equal(10, ly_out_printed(out));
assert_int_equal(10, read(fd2, buf, 30));
assert_string_equal("test print", buf);
close(fd2);
ly_out_free(out, close_clb, 0);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_input_mem),
UTEST(test_input_fd, setup_files, teardown_files),
UTEST(test_input_file, setup_files, teardown_files),
UTEST(test_input_filepath, setup_files, teardown_files),
UTEST(test_output_mem),
UTEST(test_output_fd, setup_files, teardown_files),
UTEST(test_output_file, setup_files, teardown_files),
UTEST(test_output_filepath, setup_files, teardown_files),
UTEST(test_output_clb, setup_files, teardown_files),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

View file

@ -0,0 +1,773 @@
/**
* @file test_json.c
* @author: Radek Krejci <rkrejci@cesnet.cz>
* @brief unit tests for a generic JSON parser
*
* Copyright (c) 2020 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_internal.h"
#include "json.h"
static void
test_general(void **state)
{
struct lyjson_ctx *jsonctx;
struct ly_in *in;
const char *str;
/* empty */
str = "";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
CHECK_LOG_CTX("Empty JSON file.", NULL, 1);
str = " \n\t \n";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
CHECK_LOG_CTX("Empty JSON file.", NULL, 3);
/* constant values */
str = "true";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_TRUE, lyjson_ctx_status(jsonctx));
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
lyjson_ctx_free(jsonctx);
str = "false";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_FALSE, lyjson_ctx_status(jsonctx));
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
lyjson_ctx_free(jsonctx);
str = "null";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NULL, lyjson_ctx_status(jsonctx));
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
lyjson_ctx_free(jsonctx);
ly_in_free(in, 0);
}
static void
test_number(void **state)
{
struct lyjson_ctx *jsonctx;
struct ly_in *in;
const char *str;
/* simple value */
str = "11";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("11", jsonctx->value);
assert_int_equal(2, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
/* fraction number */
str = "37.7668";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("37.7668", jsonctx->value);
assert_int_equal(7, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
/* negative number */
str = "-122.3959";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("-122.3959", jsonctx->value);
assert_int_equal(9, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
/* integer, positive exponent */
str = "550E3";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("550000", jsonctx->value);
assert_int_equal(6, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
str = "-550E3";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("-550000", jsonctx->value);
assert_int_equal(7, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
/* integer, negative exponent */
str = "1E-1";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("0.1", jsonctx->value);
assert_int_equal(3, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
str = "15E-1";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("1.5", jsonctx->value);
assert_int_equal(3, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
str = "-15E-1";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("-1.5", jsonctx->value);
assert_int_equal(4, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
str = "16E-2";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("0.16", jsonctx->value);
assert_int_equal(4, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
str = "-16E-2";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("-0.16", jsonctx->value);
assert_int_equal(5, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
str = "17E-3";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("0.017", jsonctx->value);
assert_int_equal(5, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
str = "-17E-3";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("-0.017", jsonctx->value);
assert_int_equal(6, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
str = "21000E-2";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("210", jsonctx->value);
assert_int_equal(3, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
str = "21000E-4";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("2.1", jsonctx->value);
assert_int_equal(3, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
str = "21000E-7";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("0.0021", jsonctx->value);
assert_int_equal(6, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
/* decimal number, positive exponent */
str = "5.087E1";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("50.87", jsonctx->value);
assert_int_equal(5, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
str = "-5.087E1";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("-50.87", jsonctx->value);
assert_int_equal(6, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
str = "5.087E5";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("508700", jsonctx->value);
assert_int_equal(6, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
str = "59.1e+1";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("591", jsonctx->value);
assert_int_equal(3, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
str = "0.005087E1";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("0.05087", jsonctx->value);
assert_int_equal(7, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
str = "0.005087E2";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("0.5087", jsonctx->value);
assert_int_equal(6, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
str = "0.005087E6";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("5087", jsonctx->value);
assert_int_equal(4, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
str = "0.05087E6";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("50870", jsonctx->value);
assert_int_equal(5, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
str = "0.005087E8";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("508700", jsonctx->value);
assert_int_equal(6, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
/* decimal number, negative exponent */
str = "35.94e-1";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("3.594", jsonctx->value);
assert_int_equal(5, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
str = "-35.94e-1";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("-3.594", jsonctx->value);
assert_int_equal(6, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
str = "35.94e-2";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("0.3594", jsonctx->value);
assert_int_equal(6, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
str = "35.94e-3";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("0.03594", jsonctx->value);
assert_int_equal(7, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
str = "0.3594e-1";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("0.03594", jsonctx->value);
assert_int_equal(7, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
str = "0.03594e-1";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("0.003594", jsonctx->value);
assert_int_equal(8, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
str = "0.003594e-1";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("0.0003594", jsonctx->value);
assert_int_equal(9, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
str = "0.3594e-2";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("0.003594", jsonctx->value);
assert_int_equal(8, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
str = "0.03594e-2";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("0.0003594", jsonctx->value);
assert_int_equal(9, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
str = "0.003594e-2";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("0.00003594", jsonctx->value);
assert_int_equal(10, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
/* zero */
str = "0";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_true(jsonctx->value[0] == '0');
assert_int_equal(1, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
str = "-0";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_true(jsonctx->value[0] == '-');
assert_true(jsonctx->value[1] == '0');
assert_int_equal(2, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
str = "94E0";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_true(jsonctx->value[0] == '9');
assert_true(jsonctx->value[1] == '4');
assert_int_equal(2, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
str = "0E2";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_true(jsonctx->value[0] == '0');
assert_int_equal(1, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
str = "-0E2";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_true(jsonctx->value[0] == '-');
assert_true(jsonctx->value[1] == '0');
assert_int_equal(2, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
str = "5.320e+2";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("532", jsonctx->value);
assert_int_equal(3, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
str = "5.320e-1";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx));
assert_string_equal("0.532", jsonctx->value);
assert_int_equal(5, jsonctx->value_len);
assert_int_equal(1, jsonctx->dynamic);
lyjson_ctx_free(jsonctx);
/* various invalid inputs */
str = "-x";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
CHECK_LOG_CTX("Invalid character in JSON Number value (\"x\").", NULL, 1);
str = " -";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
CHECK_LOG_CTX("Unexpected end-of-input.", NULL, 1);
str = "--1";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
CHECK_LOG_CTX("Invalid character in JSON Number value (\"-\").", NULL, 1);
str = "+1";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
CHECK_LOG_CTX("Invalid character sequence \"+1\", expected a JSON value.", NULL, 1);
str = " 1.x ";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
CHECK_LOG_CTX("Invalid character in JSON Number value (\"x\").", NULL, 1);
str = "1.";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
CHECK_LOG_CTX("Unexpected end-of-input.", NULL, 1);
str = " 1eo ";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
CHECK_LOG_CTX("Invalid character in JSON Number value (\"o\").", NULL, 1);
str = "1e";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
CHECK_LOG_CTX("Unexpected end-of-input.", NULL, 1);
str = "1E1000";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
CHECK_LOG_CTX("Number encoded as a string exceeded the LY_NUMBER_MAXLEN limit.", NULL, 1);
str = "1e9999999999999999999";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
CHECK_LOG_CTX("Exponent out-of-bounds in a JSON Number value (1e9999999999999999999).", NULL, 1);
str = "1.1e66000";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
CHECK_LOG_CTX("Exponent out-of-bounds in a JSON Number value (1.1e66000).", NULL, 1);
str = "1.1e-66000";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
CHECK_LOG_CTX("Exponent out-of-bounds in a JSON Number value (1.1e-66000).", NULL, 1);
ly_in_free(in, 0);
}
/* now string is tested in file ./tests/utests/types/string.c */
static void
test_string(void **state)
{
struct lyjson_ctx *jsonctx;
struct ly_in *in = NULL;
const char *str;
str = "";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
/* unterminated string */
str = "\"unterminated string";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
CHECK_LOG_CTX("Missing quotation-mark at the end of a JSON string.", NULL, 1);
CHECK_LOG_CTX("Unexpected end-of-input.", NULL, 1);
ly_in_free(in, 0);
}
static void
test_object(void **state)
{
struct lyjson_ctx *jsonctx;
struct ly_in *in;
const char *str;
/* empty */
str = " { } ";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx));
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx));
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
lyjson_ctx_free(jsonctx);
/* simple value */
str = "{\"name\" : \"Radek\"}";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx));
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_OBJECT_NAME, lyjson_ctx_status(jsonctx));
assert_ptr_equal(&str[2], jsonctx->value);
assert_int_equal(4, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_STRING, lyjson_ctx_status(jsonctx));
assert_string_equal("Radek\"}", jsonctx->value);
assert_int_equal(5, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx));
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
lyjson_ctx_free(jsonctx);
/* two values */
str = "{\"smart\" : true,\"handsom\":false}";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx));
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_OBJECT_NAME, lyjson_ctx_status(jsonctx));
assert_string_equal("smart\" : true,\"handsom\":false}", jsonctx->value);
assert_int_equal(5, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_TRUE, lyjson_ctx_status(jsonctx));
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_OBJECT_NEXT, lyjson_ctx_status(jsonctx));
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_OBJECT_NAME, lyjson_ctx_status(jsonctx));
assert_string_equal("handsom\":false}", jsonctx->value);
assert_int_equal(7, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_FALSE, lyjson_ctx_status(jsonctx));
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx));
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
lyjson_ctx_free(jsonctx);
/* inherited objects */
str = "{\"person\" : {\"name\":\"Radek\"}}";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx));
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_OBJECT_NAME, lyjson_ctx_status(jsonctx));
assert_string_equal("person\" : {\"name\":\"Radek\"}}", jsonctx->value);
assert_int_equal(6, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx));
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_OBJECT_NAME, lyjson_ctx_status(jsonctx));
assert_string_equal("name\":\"Radek\"}}", jsonctx->value);
assert_int_equal(4, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_STRING, lyjson_ctx_status(jsonctx));
assert_string_equal("Radek\"}}", jsonctx->value);
assert_int_equal(5, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx));
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx));
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
lyjson_ctx_free(jsonctx);
/* unquoted string */
str = "{ unquoted : \"data\"}";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx));
assert_int_equal(LY_EVALID, lyjson_ctx_next(jsonctx, NULL));
CHECK_LOG_CTX("Invalid character sequence \"unquoted : \"data\"}\", expected a JSON object name.", NULL, 1);
lyjson_ctx_free(jsonctx);
ly_in_free(in, 0);
}
static void
test_array(void **state)
{
struct lyjson_ctx *jsonctx;
struct ly_in *in;
const char *str;
/* empty */
str = " [ ] ";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_ARRAY, lyjson_ctx_status(jsonctx));
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_ARRAY_CLOSED, lyjson_ctx_status(jsonctx));
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
lyjson_ctx_free(jsonctx);
/* simple value */
str = "[ null]";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_ARRAY, lyjson_ctx_status(jsonctx));
assert_null(jsonctx->value);
assert_int_equal(0, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_NULL, lyjson_ctx_status(jsonctx));
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_ARRAY_CLOSED, lyjson_ctx_status(jsonctx));
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
lyjson_ctx_free(jsonctx);
/* two values */
str = "[{\"a\":null},\"x\"]";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LYJSON_ARRAY, lyjson_ctx_status(jsonctx));
assert_null(jsonctx->value);
assert_int_equal(0, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx));
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_OBJECT_NAME, lyjson_ctx_status(jsonctx));
assert_string_equal("a\":null},\"x\"]", jsonctx->value);
assert_int_equal(1, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_NULL, lyjson_ctx_status(jsonctx));
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx));
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_ARRAY_NEXT, lyjson_ctx_status(jsonctx));
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_STRING, lyjson_ctx_status(jsonctx));
assert_string_equal("x\"]", jsonctx->value);
assert_int_equal(1, jsonctx->value_len);
assert_int_equal(0, jsonctx->dynamic);
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_ARRAY_CLOSED, lyjson_ctx_status(jsonctx));
assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL));
assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx));
lyjson_ctx_free(jsonctx);
/* new line is allowed only as escaped character in JSON */
str = "[ , null]";
assert_non_null(ly_in_memory(in, str));
assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx));
assert_int_equal(LY_EVALID, lyjson_ctx_next(jsonctx, NULL));
CHECK_LOG_CTX("Invalid character sequence \", null]\", expected a JSON value.", NULL, 1);
lyjson_ctx_free(jsonctx);
ly_in_free(in, 0);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_general),
UTEST(test_number),
UTEST(test_string),
UTEST(test_object),
UTEST(test_array),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

View file

@ -0,0 +1,153 @@
/**
* @file test_plugins.c
* @author: Radek Krejci <rkrejci@cesnet.cz>
* @brief unit tests for functions from set.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 <stdlib.h>
#include <string.h>
#include "ly_config.h"
#include "plugins.h"
#include "plugins_internal.h"
const char *simple = "module libyang-plugins-simple {"
" namespace urn:libyang:tests:plugins:simple;"
" prefix s;"
" typedef note { type string; }"
" extension hint { argument value; }"
" leaf test {"
" type s:note {length 255;}"
" s:hint \"some hint here\";"
" }"
"}";
static void
test_add_invalid(void **state)
{
(void)state;
assert_int_equal(LY_ESYS, lyplg_add(TESTS_BIN "/plugins/plugin_does_not_exist" LYPLG_SUFFIX));
}
static void
test_add_simple(void **state)
{
struct lys_module *mod;
struct lysc_node_leaf *leaf;
struct lyplg_ext_record *record_e;
struct lyplg_type *plugin_t;
assert_int_equal(LY_SUCCESS, lyplg_add(TESTS_BIN "/plugins/plugin_simple" LYPLG_SUFFIX));
UTEST_ADD_MODULE(simple, LYS_IN_YANG, NULL, &mod);
leaf = (struct lysc_node_leaf *)mod->compiled->data;
assert_int_equal(LYS_LEAF, leaf->nodetype);
assert_non_null(plugin_t = lyplg_type_plugin_find(NULL, "libyang-plugins-simple", NULL, "note"));
assert_string_equal("ly2 simple test v1", plugin_t->id);
assert_ptr_equal(leaf->type->plugin, plugin_t);
assert_int_equal(1, LY_ARRAY_COUNT(leaf->exts));
assert_non_null(record_e = lyplg_ext_record_find(NULL, "libyang-plugins-simple", NULL, "hint"));
assert_string_equal("ly2 simple test v1", record_e->plugin.id);
assert_ptr_equal(leaf->exts[0].def->plugin, &record_e->plugin);
/* the second loading of the same plugin - still success */
assert_int_equal(LY_SUCCESS, lyplg_add(TESTS_BIN "/plugins/plugin_simple" LYPLG_SUFFIX));
}
static void
test_not_implemented(void **state)
{
struct lys_module *mod;
struct lyd_node *tree;
const char *schema = "module libyang-plugins-unknown {"
" namespace urn:libyang:tests:plugins:unknown;"
" prefix u;"
" extension myext;"
" typedef mytype { type string;}"
" leaf test {"
" u:myext;"
" type mytype;"
" }"
"}";
const char *data = "<test xmlns=\"urn:libyang:tests:plugins:unknown\">xxx</test>";
char *printed = NULL;
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG_COMPILED, 0));
free(printed);
assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
CHECK_LOG_CTX(NULL, NULL, 0);
lyd_free_all(tree);
}
static LY_ERR
parse_clb(struct lysp_ctx *UNUSED(pctx), struct lysp_ext_instance *ext)
{
struct lysp_node_leaf *leaf;
leaf = (struct lysp_node_leaf *)ext->parent;
leaf->flags |= LYS_STATUS_OBSLT;
return LY_SUCCESS;
}
struct lyplg_ext_record memory_recs[] = {
{
.module = "libyang-plugins-simple",
.revision = NULL,
.name = "hint",
.plugin.id = "memory-plugin-v1",
.plugin.parse = parse_clb,
.plugin.compile = NULL,
.plugin.printer_info = NULL,
.plugin.node = NULL,
.plugin.snode = NULL,
.plugin.validate = NULL,
.plugin.pfree = NULL,
.plugin.cfree = NULL
},
{0} /* terminating zeroed item */
};
static void
test_simple_from_memory(void **state)
{
struct lys_module *mod;
struct lysc_node_leaf *leaf;
lyplg_add_extension_plugin(UTEST_LYCTX, LYPLG_EXT_API_VERSION, memory_recs);
UTEST_ADD_MODULE(simple, LYS_IN_YANG, NULL, &mod);
leaf = (struct lysc_node_leaf *)mod->compiled->data;
assert_int_equal(LYS_LEAF, leaf->nodetype);
assert_true(leaf->flags & LYS_STATUS_OBSLT);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_add_invalid),
UTEST(test_add_simple),
UTEST(test_not_implemented),
UTEST(test_simple_from_memory),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

View file

@ -0,0 +1,276 @@
/**
* @file test_set.c
* @author: Radek Krejci <rkrejci@cesnet.cz>
* @brief unit tests for functions from set.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 _POSIX_C_SOURCE 200809L /* strdup */
#define _UTEST_MAIN_
#include "utests.h"
#include <stdlib.h>
#include <string.h>
#include "set.h"
static void
test_basics(void **UNUSED(state))
{
struct ly_set *set;
char *str;
unsigned int u;
void *ptr;
uint32_t index;
/* creation - everything is empty */
assert_int_equal(LY_SUCCESS, ly_set_new(&set));
assert_non_null(set);
assert_int_equal(0, set->count);
assert_int_equal(0, set->size);
assert_null(set->objs);
/* add a testing object */
str = strdup("test string");
assert_non_null(str);
assert_int_equal(LY_SUCCESS, ly_set_add(set, str, 0, NULL));
assert_int_not_equal(0, set->size);
assert_int_equal(1, set->count);
assert_non_null(set->objs);
assert_non_null(set->objs[0]);
/* check the presence of the testing data */
assert_int_equal(1, ly_set_contains(set, str, &index));
assert_int_equal(0, index);
assert_int_equal(0, ly_set_contains(set, str - 1, NULL));
/* remove data, but keep the set */
u = set->size;
ptr = set->objs;
ly_set_clean(set, free);
assert_int_equal(0, set->count);
assert_int_equal(u, set->size);
assert_ptr_equal(ptr, set->objs);
/* remove buffer, but keep the set object */
ly_set_erase(set, NULL);
assert_int_equal(0, set->count);
assert_int_equal(0, set->size);
assert_ptr_equal(NULL, set->objs);
/* final cleanup */
ly_set_free(set, NULL);
}
static void
test_inval(void **UNUSED(state))
{
struct ly_set set = {0};
assert_int_equal(LY_EINVAL, ly_set_dup(NULL, NULL, NULL));
CHECK_LOG_LASTMSG("Invalid argument set (ly_set_dup()).");
assert_int_equal(LY_EINVAL, ly_set_add(NULL, NULL, 0, NULL));
CHECK_LOG_LASTMSG("Invalid argument set (ly_set_add()).");
assert_int_equal(LY_EINVAL, ly_set_merge(NULL, NULL, 0, NULL));
CHECK_LOG_LASTMSG("Invalid argument trg (ly_set_merge()).");
assert_int_equal(LY_SUCCESS, ly_set_merge(&set, NULL, 0, NULL));
assert_int_equal(LY_EINVAL, ly_set_rm_index(NULL, 0, NULL));
CHECK_LOG_LASTMSG("Invalid argument set (ly_set_rm_index()).");
assert_int_equal(LY_EINVAL, ly_set_rm_index(&set, 1, NULL));
CHECK_LOG_LASTMSG("Invalid argument index (ly_set_rm_index()).");
assert_int_equal(LY_EINVAL, ly_set_rm(NULL, NULL, NULL));
CHECK_LOG_LASTMSG("Invalid argument set (ly_set_rm()).");
assert_int_equal(LY_EINVAL, ly_set_rm(&set, NULL, NULL));
CHECK_LOG_LASTMSG("Invalid argument object (ly_set_rm()).");
assert_int_equal(LY_EINVAL, ly_set_rm(&set, &set, NULL));
CHECK_LOG_LASTMSG("Invalid argument object (ly_set_rm()).");
}
static void
test_duplication(void **UNUSED(state))
{
struct ly_set *orig, *new;
char *str;
uint32_t index;
assert_int_equal(LY_SUCCESS, ly_set_new(&orig));
assert_non_null(orig);
/* add a testing object */
str = strdup("test string");
assert_non_null(str);
assert_int_equal(LY_SUCCESS, ly_set_add(orig, str, 0, &index));
assert_int_equal(0, index);
/* duplicate the set - without duplicator, so the new set will point to the same string */
assert_int_equal(LY_SUCCESS, ly_set_dup(orig, NULL, &new));
assert_non_null(new);
assert_ptr_not_equal(orig, new);
assert_int_equal(orig->count, new->count);
assert_ptr_equal(orig->objs[0], new->objs[0]);
ly_set_free(new, NULL);
/* duplicate the set - with duplicator, so the new set will point to a different buffer with the same content */
assert_int_equal(LY_SUCCESS, ly_set_dup(orig, (void *(*)(const void *))strdup, &new));
assert_non_null(new);
assert_ptr_not_equal(orig, new);
assert_int_equal(orig->count, new->count);
assert_ptr_not_equal(orig->objs[0], new->objs[0]);
assert_string_equal(orig->objs[0], new->objs[0]);
/* cleanup */
ly_set_free(new, free);
ly_set_free(orig, free);
}
static void
test_add(void **UNUSED(state))
{
uint32_t u, index;
char *str = "test string";
struct ly_set set;
memset(&set, 0, sizeof set);
/* add a testing object */
assert_int_equal(LY_SUCCESS, ly_set_add(&set, str, 0, &index));
assert_int_equal(0, index);
/* test avoiding data duplicities */
assert_int_equal(LY_SUCCESS, ly_set_add(&set, str, 0, &index));
assert_int_equal(0, index);
assert_int_equal(1, set.count);
assert_int_equal(LY_SUCCESS, ly_set_add(&set, str, 1, &index));
assert_int_equal(1, index);
assert_int_equal(2, set.count);
/* test array resizing */
u = set.size;
for (uint32_t expected_index = 2; expected_index <= u; ++expected_index) {
assert_int_equal(LY_SUCCESS, ly_set_add(&set, str, 1, &index));
assert_int_equal(expected_index, index);
}
assert_true(u != set.size);
/* cleanup */
ly_set_erase(&set, NULL);
}
static void
test_merge(void **UNUSED(state))
{
char *str1, *str2;
struct ly_set one, two;
memset(&one, 0, sizeof one);
memset(&two, 0, sizeof two);
str1 = strdup("string1");
str2 = strdup("string2");
/* fill first set
* - str1 is the same as in two, so it must not be freed! */
assert_int_equal(LY_SUCCESS, ly_set_add(&one, str1, 0, NULL));
/* fill second set */
assert_int_equal(LY_SUCCESS, ly_set_add(&two, str1, 0, NULL));
assert_int_equal(LY_SUCCESS, ly_set_add(&two, str2, 0, NULL));
/* merge with checking duplicities - only one item is added into one;
* also without duplicating data, so it must not be freed at the end */
assert_int_equal(LY_SUCCESS, ly_set_merge(&one, &two, 0, NULL));
assert_int_equal(2, one.count);
assert_ptr_equal(one.objs[1], two.objs[1]);
/* clean and re-fill one (now duplicating str1, to allow testing duplicator) */
ly_set_clean(&one, NULL);
assert_int_equal(LY_SUCCESS, ly_set_add(&one, strdup(str1), 0, NULL));
/* merge without checking duplicities - two items are added into one;
* here also with duplicator */
assert_int_equal(LY_SUCCESS, ly_set_merge(&one, &two, 1, (void *(*)(const void *))strdup));
assert_int_equal(3, one.count);
assert_ptr_not_equal(one.objs[1], two.objs[0]);
assert_string_equal(one.objs[1], two.objs[0]);
/* cleanup */
ly_set_erase(&one, free);
ly_set_erase(&two, free);
}
static void
test_rm(void **UNUSED(state))
{
char *str1, *str2, *str3;
struct ly_set set;
memset(&set, 0, sizeof set);
/* fill the set */
assert_int_equal(LY_SUCCESS, ly_set_add(&set, "string1", 0, NULL));
assert_int_equal(LY_SUCCESS, ly_set_add(&set, strdup("string2"), 0, NULL));
assert_int_equal(LY_SUCCESS, ly_set_add(&set, "string3", 0, NULL));
/* remove by index ... */
/* ... in the middle ... */
assert_int_equal(LY_SUCCESS, ly_set_rm_index(&set, 1, free));
assert_int_equal(2, set.count);
assert_string_not_equal("string2", set.objs[0]);
assert_string_not_equal("string2", set.objs[1]);
/* ... last .. */
assert_int_equal(LY_SUCCESS, ly_set_rm_index(&set, 1, NULL));
assert_int_equal(1, set.count);
assert_string_not_equal("string3", set.objs[0]);
/* ... first .. */
assert_int_equal(LY_SUCCESS, ly_set_rm_index(&set, 0, NULL));
assert_int_equal(0, set.count);
/* fill the set */
assert_int_equal(LY_SUCCESS, ly_set_add(&set, str1 = "string1", 0, NULL));
assert_int_equal(LY_SUCCESS, ly_set_add(&set, str2 = "string2", 0, NULL));
assert_int_equal(LY_SUCCESS, ly_set_add(&set, str3 = strdup("string3"), 0, NULL));
/* remove by pointer ... */
/* ... in the middle ... */
assert_int_equal(LY_SUCCESS, ly_set_rm(&set, str2, NULL));
assert_int_equal(2, set.count);
assert_string_not_equal("string2", set.objs[0]);
assert_string_not_equal("string2", set.objs[1]);
/* ... last (with destructor) .. */
assert_int_equal(LY_SUCCESS, ly_set_rm(&set, str3, free));
assert_int_equal(1, set.count);
assert_string_not_equal("string3", set.objs[0]);
/* ... first .. */
assert_int_equal(LY_SUCCESS, ly_set_rm(&set, str1, NULL));
assert_int_equal(0, set.count);
/* cleanup */
ly_set_erase(&set, NULL);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_basics),
UTEST(test_duplication),
UTEST(test_add),
UTEST(test_merge),
UTEST(test_rm),
UTEST(test_inval),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

View file

@ -0,0 +1,689 @@
/**
* @file test_xml.c
* @author: Radek Krejci <rkrejci@cesnet.cz>
* @brief unit tests for functions from xml.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"
#define _POSIX_C_SOURCE 200809L /* strdup */
#include <string.h>
#include "context.h"
#include "in_internal.h"
#include "xml.h"
LY_ERR lyxml_ns_add(struct lyxml_ctx *xmlctx, const char *prefix, size_t prefix_len, char *uri);
static void
test_element(void **state)
{
struct lyxml_ctx *xmlctx;
struct ly_in *in;
const char *str;
/* empty */
str = "";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
assert_int_equal(LYXML_END, xmlctx->status);
lyxml_ctx_free(xmlctx);
ly_in_free(in, 0);
/* end element */
str = "</element>";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
assert_int_equal(LY_EVALID, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
CHECK_LOG_CTX("Stray closing element tag (\"element\").", NULL, 1);
ly_in_free(in, 0);
/* no element */
str = "no data present";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
assert_int_equal(LY_EVALID, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
CHECK_LOG_CTX("Invalid character sequence \"no data present\", expected element tag start ('<').", NULL, 1);
ly_in_free(in, 0);
/* not supported DOCTYPE */
str = "<!DOCTYPE greeting SYSTEM \"hello.dtd\"><greeting/>";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
assert_int_equal(LY_EVALID, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
CHECK_LOG_CTX("Document Type Declaration not supported.", NULL, 1);
ly_in_free(in, 0);
/* invalid XML */
str = "<!NONSENSE/>";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
assert_int_equal(LY_EVALID, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
CHECK_LOG_CTX("Unknown XML section \"<!NONSENSE/>\".", NULL, 1);
ly_in_free(in, 0);
/* namespace ambiguity */
str = "<element xmlns=\"urn1\" xmlns=\"urn2\"/>";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
assert_int_equal(LY_EVALID, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
CHECK_LOG_CTX("Duplicate default XML namespaces \"urn1\" and \"urn2\".", NULL, 1);
ly_in_free(in, 0);
/* prefix duplicate */
str = "<element xmlns:a=\"urn1\" xmlns:a=\"urn2\"/>";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
assert_int_equal(LY_EVALID, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
CHECK_LOG_CTX("Duplicate XML NS prefix \"a\" used for namespaces \"urn1\" and \"urn2\".", NULL, 1);
ly_in_free(in, 0);
/* unqualified element */
str = " < element/>";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
assert_int_equal(LYXML_ELEMENT, xmlctx->status);
assert_null(xmlctx->prefix);
assert_true(!strncmp("element", xmlctx->name, xmlctx->name_len));
assert_int_equal(1, xmlctx->elements.count);
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status);
assert_true(!strncmp("", xmlctx->value, xmlctx->value_len));
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ELEM_CLOSE, xmlctx->status);
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_END, xmlctx->status);
lyxml_ctx_free(xmlctx);
ly_in_free(in, 0);
/* element with attribute */
str = " < element attr=\'x\'/>";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
assert_int_equal(LYXML_ELEMENT, xmlctx->status);
assert_true(!strncmp("element", xmlctx->name, xmlctx->name_len));
assert_null(xmlctx->prefix);
assert_int_equal(1, xmlctx->elements.count);
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ATTRIBUTE, xmlctx->status);
assert_true(!strncmp("attr", xmlctx->name, xmlctx->name_len));
assert_null(xmlctx->prefix);
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ATTR_CONTENT, xmlctx->status);
assert_int_equal(1, xmlctx->elements.count);
assert_true(!strncmp("x", xmlctx->value, xmlctx->value_len));
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status);
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ELEM_CLOSE, xmlctx->status);
assert_int_equal(0, xmlctx->elements.count);
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_END, xmlctx->status);
lyxml_ctx_free(xmlctx);
ly_in_free(in, 0);
/* headers and comments */
str = "<?xml version=\"1.0\"?> <!-- comment --> <?TEST xxx?> <element/>";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
assert_int_equal(LYXML_ELEMENT, xmlctx->status);
assert_true(!strncmp("element", xmlctx->name, xmlctx->name_len));
assert_null(xmlctx->prefix);
assert_int_equal(1, xmlctx->elements.count);
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status);
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ELEM_CLOSE, xmlctx->status);
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_END, xmlctx->status);
lyxml_ctx_free(xmlctx);
ly_in_free(in, 0);
/* separate opening and closing tags, neamespaced parsed internally */
str = "<element xmlns=\"urn\"></element>";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
assert_int_equal(LYXML_ELEMENT, xmlctx->status);
assert_true(!strncmp("element", xmlctx->name, xmlctx->name_len));
assert_null(xmlctx->prefix);
assert_int_equal(1, xmlctx->elements.count);
assert_int_equal(1, xmlctx->ns.count);
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status);
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ELEM_CLOSE, xmlctx->status);
assert_int_equal(0, xmlctx->elements.count);
assert_int_equal(0, xmlctx->ns.count);
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_END, xmlctx->status);
lyxml_ctx_free(xmlctx);
ly_in_free(in, 0);
/* qualified element */
str = " < yin:element/>";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
assert_int_equal(LYXML_ELEMENT, xmlctx->status);
assert_true(!strncmp("element", xmlctx->name, xmlctx->name_len));
assert_true(!strncmp("yin", xmlctx->prefix, xmlctx->prefix_len));
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status);
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ELEM_CLOSE, xmlctx->status);
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_END, xmlctx->status);
lyxml_ctx_free(xmlctx);
ly_in_free(in, 0);
/* non-matching closing tag */
str = "<yin:element xmlns=\"urn\"></element>";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
assert_int_equal(LYXML_ELEMENT, xmlctx->status);
assert_true(!strncmp("element", xmlctx->name, xmlctx->name_len));
assert_true(!strncmp("yin", xmlctx->prefix, xmlctx->prefix_len));
assert_int_equal(1, xmlctx->elements.count);
assert_int_equal(1, xmlctx->ns.count);
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status);
assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx));
CHECK_LOG_CTX("Opening (\"yin:element\") and closing (\"element\") elements tag mismatch.", NULL, 1);
lyxml_ctx_free(xmlctx);
ly_in_free(in, 0);
/* invalid closing tag */
str = "<yin:element xmlns=\"urn\"></yin:element/>";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx));
CHECK_LOG_CTX("Invalid character sequence \"/>\", expected element tag termination ('>').", NULL, 1);
lyxml_ctx_free(xmlctx);
ly_in_free(in, 0);
/* UTF8 characters */
str = "<𠜎€𠜎Øn:𠜎€𠜎Øn/>";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
assert_true(!strncmp("𠜎€𠜎Øn", xmlctx->name, xmlctx->name_len));
assert_true(!strncmp("𠜎€𠜎Øn", xmlctx->prefix, xmlctx->prefix_len));
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status);
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ELEM_CLOSE, xmlctx->status);
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_END, xmlctx->status);
lyxml_ctx_free(xmlctx);
ly_in_free(in, 0);
/* invalid UTF-8 characters */
str = "<¢:element>";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
assert_int_equal(LY_EVALID, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
CHECK_LOG_CTX("Identifier \"¢:element>\" starts with an invalid character.", NULL, 1);
ly_in_free(in, 0);
str = "<yin:c⁐element>";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx));
CHECK_LOG_CTX("Invalid character sequence \"⁐element>\", expected element tag end ('>' or '/>') or an attribute.", NULL, 1);
lyxml_ctx_free(xmlctx);
ly_in_free(in, 0);
/* mixed content */
str = "<a>text <b>x</b></a>";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
assert_int_equal(LYXML_ELEMENT, xmlctx->status);
assert_true(!strncmp("a", xmlctx->name, xmlctx->name_len));
assert_null(xmlctx->prefix);
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status);
assert_true(!strncmp("text ", xmlctx->value, xmlctx->value_len));
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ELEMENT, xmlctx->status);
assert_true(!strncmp("b", xmlctx->name, xmlctx->name_len));
assert_null(xmlctx->prefix);
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status);
assert_true(!strncmp("x", xmlctx->value, xmlctx->value_len));
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ELEM_CLOSE, xmlctx->status);
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ELEM_CLOSE, xmlctx->status);
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_END, xmlctx->status);
lyxml_ctx_free(xmlctx);
ly_in_free(in, 0);
/* tag mismatch */
str = "<a>text</b>";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
assert_int_equal(LYXML_ELEMENT, xmlctx->status);
assert_true(!strncmp("a", xmlctx->name, xmlctx->name_len));
assert_null(xmlctx->prefix);
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status);
assert_true(!strncmp("text", xmlctx->value, xmlctx->value_len));
assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx));
CHECK_LOG_CTX("Opening (\"a\") and closing (\"b\") elements tag mismatch.", NULL, 1);
lyxml_ctx_free(xmlctx);
ly_in_free(in, 0);
}
static void
test_attribute(void **state)
{
const char *str;
struct lyxml_ctx *xmlctx;
struct ly_in *in;
struct lyxml_ns *ns;
/* not an attribute */
str = "<e unknown/>";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
assert_int_equal(LY_EVALID, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
CHECK_LOG_CTX("Invalid character sequence \"/>\", expected '='.", NULL, 1);
ly_in_free(in, 0);
str = "<e xxx=/>";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
assert_int_equal(LY_EVALID, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
CHECK_LOG_CTX("Invalid character sequence \"/>\", expected either single or double quotation mark.", NULL, 1);
ly_in_free(in, 0);
str = "<e xxx\n = yyy/>";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
assert_int_equal(LY_EVALID, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
CHECK_LOG_CTX("Invalid character sequence \"yyy/>\", expected either single or double quotation mark.", NULL, 2);
ly_in_free(in, 0);
/* valid attribute */
str = "<e attr=\"val\"";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
assert_int_equal(LYXML_ELEMENT, xmlctx->status);
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ATTRIBUTE, xmlctx->status);
assert_true(!strncmp("attr", xmlctx->name, xmlctx->name_len));
assert_null(xmlctx->prefix);
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ATTR_CONTENT, xmlctx->status);
assert_true(!strncmp("val", xmlctx->value, xmlctx->value_len));
assert_int_equal(xmlctx->ws_only, 0);
assert_int_equal(xmlctx->dynamic, 0);
lyxml_ctx_free(xmlctx);
ly_in_free(in, 0);
/* valid namespace with prefix */
str = "<e xmlns:nc\n = \'urn\'/>";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
assert_int_equal(LYXML_ELEMENT, xmlctx->status);
assert_int_equal(1, xmlctx->ns.count);
ns = (struct lyxml_ns *)xmlctx->ns.objs[0];
assert_string_equal(ns->prefix, "nc");
assert_string_equal(ns->uri, "urn");
lyxml_ctx_free(xmlctx);
ly_in_free(in, 0);
}
static void
test_text(void **state)
{
const char *str;
struct lyxml_ctx *xmlctx;
struct ly_in *in;
/* empty attribute value */
str = "<e a=\"\"";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
assert_int_equal(LYXML_ELEMENT, xmlctx->status);
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ATTRIBUTE, xmlctx->status);
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ATTR_CONTENT, xmlctx->status);
assert_true(!strncmp("", xmlctx->value, xmlctx->value_len));
assert_int_equal(xmlctx->ws_only, 1);
assert_int_equal(xmlctx->dynamic, 0);
ly_in_free(in, 0);
/* empty value but in single quotes */
assert_int_equal(LY_SUCCESS, ly_in_new_memory("=\'\'", &in));
xmlctx->in = in;
ly_log_location(NULL, NULL, NULL, in);
xmlctx->status = LYXML_ATTRIBUTE;
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ATTR_CONTENT, xmlctx->status);
assert_true(!strncmp("", xmlctx->value, xmlctx->value_len));
assert_int_equal(xmlctx->ws_only, 1);
assert_int_equal(xmlctx->dynamic, 0);
ly_in_free(in, 0);
/* empty element content - only formating before defining child */
assert_int_equal(LY_SUCCESS, ly_in_new_memory(">\n <y>", &in));
xmlctx->in = in;
ly_log_location(NULL, NULL, NULL, in);
xmlctx->status = LYXML_ELEMENT;
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status);
assert_true(!strncmp("\n ", xmlctx->value, xmlctx->value_len));
assert_int_equal(xmlctx->ws_only, 1);
assert_int_equal(xmlctx->dynamic, 0);
ly_in_free(in, 0);
/* empty element content is invalid - missing content terminating character < */
assert_int_equal(LY_SUCCESS, ly_in_new_memory("", &in));
xmlctx->in = in;
ly_log_location(NULL, NULL, NULL, in);
xmlctx->status = LYXML_ELEM_CONTENT;
assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx));
CHECK_LOG_CTX("Unexpected end-of-input.", NULL, 1);
ly_in_free(in, 0);
assert_int_equal(LY_SUCCESS, ly_in_new_memory("xxx", &in));
xmlctx->in = in;
ly_log_location(NULL, NULL, NULL, in);
xmlctx->status = LYXML_ELEM_CONTENT;
assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx));
CHECK_LOG_CTX("Invalid character sequence \"xxx\", expected element tag start ('<').", NULL, 1);
ly_in_free(in, 0);
lyxml_ctx_free(xmlctx);
ly_log_location_revert(0, 0, 0, 4);
/* valid strings */
str = "<a>€𠜎Øn \n&lt;&amp;&quot;&apos;&gt; &#82;&#x4f;&#x4B;</a>";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
assert_int_equal(LYXML_ELEMENT, xmlctx->status);
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status);
assert_true(!strncmp("€𠜎Øn \n<&\"\'> ROK", xmlctx->value, xmlctx->value_len));
assert_int_equal(xmlctx->ws_only, 0);
assert_int_equal(xmlctx->dynamic, 1);
free((char *)xmlctx->value);
ly_in_free(in, 0);
/* test using n-bytes UTF8 hexadecimal code points */
assert_int_equal(LY_SUCCESS, ly_in_new_memory("=\'&#x0024;&#x00A2;&#x20ac;&#x10348;\'", &in));
xmlctx->in = in;
ly_log_location(NULL, NULL, NULL, in);
xmlctx->status = LYXML_ATTRIBUTE;
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ATTR_CONTENT, xmlctx->status);
assert_true(!strncmp("$¢€𐍈", xmlctx->value, xmlctx->value_len));
assert_int_equal(xmlctx->ws_only, 0);
assert_int_equal(xmlctx->dynamic, 1);
ly_in_free(in, 0);
/* CDATA value */
assert_int_equal(LY_SUCCESS, ly_in_new_memory("> <![CDATA[ special non-escaped chars <>&\"' ]]> </a>", &in));
xmlctx->in = in;
ly_log_location(NULL, NULL, NULL, in);
xmlctx->status = LYXML_ATTR_CONTENT;
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status);
assert_true(!strncmp(" special non-escaped chars <>&\"' ", xmlctx->value, xmlctx->value_len));
assert_int_equal(xmlctx->ws_only, 0);
assert_int_equal(xmlctx->dynamic, 1);
free((char *)xmlctx->value);
ly_in_free(in, 0);
/* invalid characters in string */
assert_int_equal(LY_SUCCESS, ly_in_new_memory("=\'&#x52\'", &in));
xmlctx->in = in;
ly_log_location(NULL, NULL, NULL, in);
xmlctx->status = LYXML_ATTRIBUTE;
assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx));
CHECK_LOG_CTX("Invalid character sequence \"'\", expected ;.", NULL, 1);
ly_in_free(in, 0);
assert_int_equal(LY_SUCCESS, ly_in_new_memory("=\"&#82\"", &in));
xmlctx->in = in;
ly_log_location(NULL, NULL, NULL, in);
xmlctx->status = LYXML_ATTRIBUTE;
assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx));
CHECK_LOG_CTX("Invalid character sequence \"\"\", expected ;.", NULL, 1);
ly_in_free(in, 0);
assert_int_equal(LY_SUCCESS, ly_in_new_memory("=\"&nonsense;\"", &in));
xmlctx->in = in;
ly_log_location(NULL, NULL, NULL, in);
xmlctx->status = LYXML_ATTRIBUTE;
assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx));
CHECK_LOG_CTX("Entity reference \"&nonsense;\" not supported, only predefined references allowed.", NULL, 1);
ly_in_free(in, 0);
assert_int_equal(LY_SUCCESS, ly_in_new_memory(">&#o122;", &in));
xmlctx->in = in;
ly_log_location(NULL, NULL, NULL, in);
xmlctx->status = LYXML_ELEMENT;
assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx));
CHECK_LOG_CTX("Invalid character reference \"&#o122;\".", NULL, 1);
ly_in_free(in, 0);
assert_int_equal(LY_SUCCESS, ly_in_new_memory("=\'&#x06;\'", &in));
xmlctx->in = in;
ly_log_location(NULL, NULL, NULL, in);
xmlctx->status = LYXML_ATTRIBUTE;
assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx));
CHECK_LOG_CTX("Invalid character reference \"&#x06;\'\" (0x00000006).", NULL, 1);
ly_in_free(in, 0);
assert_int_equal(LY_SUCCESS, ly_in_new_memory("=\'&#xfdd0;\'", &in));
xmlctx->in = in;
ly_log_location(NULL, NULL, NULL, in);
xmlctx->status = LYXML_ATTRIBUTE;
assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx));
CHECK_LOG_CTX("Invalid character reference \"&#xfdd0;\'\" (0x0000fdd0).", NULL, 1);
ly_in_free(in, 0);
assert_int_equal(LY_SUCCESS, ly_in_new_memory("=\'&#xffff;\'", &in));
xmlctx->in = in;
ly_log_location(NULL, NULL, NULL, in);
xmlctx->status = LYXML_ATTRIBUTE;
assert_int_equal(LY_EVALID, lyxml_ctx_next(xmlctx));
CHECK_LOG_CTX("Invalid character reference \"&#xffff;\'\" (0x0000ffff).", NULL, 1);
ly_in_free(in, 0);
lyxml_ctx_free(xmlctx);
ly_log_location_revert(0, 0, 0, 9);
}
static void
test_ns(void **state)
{
const char *str;
struct lyxml_ctx *xmlctx;
struct ly_in *in;
const struct lyxml_ns *ns;
/* opening element1 */
str = "<element1/>";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
/* processing namespace definitions */
assert_int_equal(LY_SUCCESS, lyxml_ns_add(xmlctx, NULL, 0, strdup("urn:default")));
assert_int_equal(LY_SUCCESS, lyxml_ns_add(xmlctx, "nc", 2, strdup("urn:nc1")));
/* simulate adding open element2 into context */
xmlctx->elements.count++;
/* processing namespace definitions */
assert_int_equal(LY_SUCCESS, lyxml_ns_add(xmlctx, "nc", 2, strdup("urn:nc2")));
assert_int_equal(3, xmlctx->ns.count);
assert_int_not_equal(0, xmlctx->ns.size);
ns = lyxml_ns_get(&xmlctx->ns, NULL, 0);
assert_non_null(ns);
assert_null(ns->prefix);
assert_string_equal("urn:default", ns->uri);
ns = lyxml_ns_get(&xmlctx->ns, "nc", 2);
assert_non_null(ns);
assert_string_equal("nc", ns->prefix);
assert_string_equal("urn:nc2", ns->uri);
/* simulate closing element2 */
xmlctx->elements.count--;
lyxml_ns_rm(xmlctx);
assert_int_equal(2, xmlctx->ns.count);
ns = lyxml_ns_get(&xmlctx->ns, "nc", 2);
assert_non_null(ns);
assert_string_equal("nc", ns->prefix);
assert_string_equal("urn:nc1", ns->uri);
/* close element1 */
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(0, xmlctx->ns.count);
assert_null(lyxml_ns_get(&xmlctx->ns, "nc", 2));
assert_null(lyxml_ns_get(&xmlctx->ns, NULL, 0));
lyxml_ctx_free(xmlctx);
ly_in_free(in, 0);
}
static void
test_ns2(void **state)
{
const char *str;
struct lyxml_ctx *xmlctx;
struct ly_in *in;
/* opening element1 */
str = "<element1/>";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
/* default namespace defined in parent element1 */
assert_int_equal(LY_SUCCESS, lyxml_ns_add(xmlctx, NULL, 0, strdup("urn:default")));
assert_int_equal(1, xmlctx->ns.count);
/* going into child element1 */
/* simulate adding open element1 into context */
xmlctx->elements.count++;
/* no namespace defined, going out (first, simulate closing of so far open element) */
xmlctx->elements.count--;
lyxml_ns_rm(xmlctx);
assert_int_equal(1, xmlctx->ns.count);
/* nothing else, going out of the parent element1 */
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(0, xmlctx->ns.count);
lyxml_ctx_free(xmlctx);
ly_in_free(in, 0);
}
static void
test_simple_xml(void **state)
{
struct lyxml_ctx *xmlctx;
struct ly_in *in;
const char *test_input = "<elem1 attr1=\"value\"> <elem2 attr2=\"value\" /> </elem1>";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(test_input, &in));
assert_int_equal(LY_SUCCESS, lyxml_ctx_new(UTEST_LYCTX, in, &xmlctx));
assert_int_equal(LYXML_ELEMENT, xmlctx->status);
assert_string_equal(xmlctx->in->current, "attr1=\"value\"> <elem2 attr2=\"value\" /> </elem1>");
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ATTRIBUTE, xmlctx->status);
assert_string_equal(xmlctx->in->current, "=\"value\"> <elem2 attr2=\"value\" /> </elem1>");
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ATTR_CONTENT, xmlctx->status);
assert_string_equal(xmlctx->in->current, "> <elem2 attr2=\"value\" /> </elem1>");
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status);
assert_string_equal(xmlctx->in->current, "<elem2 attr2=\"value\" /> </elem1>");
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ELEMENT, xmlctx->status);
assert_string_equal(xmlctx->in->current, "attr2=\"value\" /> </elem1>");
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ATTRIBUTE, xmlctx->status);
assert_string_equal(xmlctx->in->current, "=\"value\" /> </elem1>");
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ATTR_CONTENT, xmlctx->status);
assert_string_equal(xmlctx->in->current, " /> </elem1>");
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ELEM_CONTENT, xmlctx->status);
assert_string_equal(xmlctx->in->current, "/> </elem1>");
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ELEM_CLOSE, xmlctx->status);
assert_string_equal(xmlctx->in->current, " </elem1>");
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_ELEM_CLOSE, xmlctx->status);
assert_string_equal(xmlctx->in->current, "");
assert_int_equal(LY_SUCCESS, lyxml_ctx_next(xmlctx));
assert_int_equal(LYXML_END, xmlctx->status);
assert_string_equal(xmlctx->in->current, "");
lyxml_ctx_free(xmlctx);
ly_in_free(in, 0);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_element),
UTEST(test_attribute),
UTEST(test_text),
UTEST(test_ns),
UTEST(test_ns2),
UTEST(test_simple_xml),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,144 @@
/**
* @file test_yanglib.c
* @author: Michal Vasko <mvasko@cesnet.cz>
* @brief unit tests for ietf-yang-library data
*
* Copyright (c) 2020 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 <string.h>
#include "context.h"
#include "in.h"
#include "log.h"
#include "set.h"
#include "tests_config.h"
#include "tree_data.h"
#include "tree_schema.h"
const char *schema_a =
"module a {\n"
" namespace urn:tests:a;\n"
" prefix a;\n"
" yang-version 1.1;\n"
"\n"
" include a_sub;\n"
"\n"
" list l2 {\n"
" key \"a\";\n"
" leaf a {\n"
" type uint16;\n"
" }\n"
" leaf b {\n"
" type uint16;\n"
" }\n"
" }\n"
"}";
const char *schema_b =
"module b {\n"
" namespace urn:tests:b;\n"
" prefix b;\n"
" yang-version 1.1;\n"
"\n"
" import a {\n"
" prefix a;\n"
" }\n"
"\n"
" deviation /a:l2 {\n"
" deviate add {\n"
" max-elements 40;\n"
" }\n"
" }\n"
"\n"
" leaf foo {\n"
" type string;\n"
" }\n"
"}";
static LY_ERR
test_imp_clb(const char *mod_name, const char *mod_rev, const char *submod_name, const char *sub_rev, void *user_data,
LYS_INFORMAT *format, const char **module_data, void (**free_module_data)(void *model_data, void *user_data))
{
const char *schema_a_sub =
"submodule a_sub {\n"
" belongs-to a {\n"
" prefix a;\n"
" }\n"
" yang-version 1.1;\n"
"\n"
" feature feat1;\n"
"\n"
" list l3 {\n"
" key \"a\";\n"
" leaf a {\n"
" type uint16;\n"
" }\n"
" leaf b {\n"
" type uint16;\n"
" }\n"
" }\n"
"}\n";
assert_string_equal(mod_name, "a");
assert_null(mod_rev);
if (!submod_name) {
return LY_ENOTFOUND;
}
assert_string_equal(submod_name, "a_sub");
assert_null(sub_rev);
assert_null(user_data);
*format = LYS_IN_YANG;
*module_data = schema_a_sub;
*free_module_data = NULL;
return LY_SUCCESS;
}
static void
test_yanglib(void **state)
{
const char *feats[] = {"feat1", NULL};
struct lyd_node *tree;
struct ly_set *set;
LY_ERR ret;
ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, NULL);
UTEST_ADD_MODULE(schema_a, LYS_IN_YANG, feats, NULL);
UTEST_ADD_MODULE(schema_b, LYS_IN_YANG, NULL, NULL);
assert_int_equal(LY_SUCCESS, ly_ctx_get_yanglib_data(UTEST_LYCTX, &tree, "<<%u>>", ly_ctx_get_change_count(UTEST_LYCTX)));
lyd_free_all(tree);
assert_int_equal(LY_SUCCESS, ly_ctx_get_yanglib_data(UTEST_LYCTX, &tree, "%u", -10));
lyd_free_all(tree);
assert_int_equal(LY_SUCCESS, ly_ctx_get_yanglib_data(UTEST_LYCTX, &tree, ""));
lyd_free_all(tree);
assert_int_equal(LY_SUCCESS, ly_ctx_get_yanglib_data(UTEST_LYCTX, &tree, "%u", ly_ctx_get_change_count(UTEST_LYCTX)));
/* make sure there is "a" with a submodule and deviation */
ret = lyd_find_xpath(tree, "/ietf-yang-library:yang-library/module-set/module[name='a'][submodule/name='a_sub']"
"[feature='feat1'][deviation='b']", &set);
assert_int_equal(ret, LY_SUCCESS);
assert_int_equal(set->count, 1);
ly_set_free(set, NULL);
lyd_free_all(tree);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_yanglib),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

File diff suppressed because it is too large Load diff

2841
tests/utests/data/test_lyb.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,756 @@
/**
* @file test_merge.c
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief tests for complex data merges.
*
* Copyright (c) 2020 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 "libyang.h"
#define LYD_TREE_CREATE(INPUT, MODEL) \
CHECK_PARSE_LYD_PARAM(INPUT, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, MODEL)
#define CONTEXT_CREATE \
CONTEXT_CREATE_PATH(NULL)
#define LYD_TREE_CHECK_CHAR(MODEL, TEXT, PARAMS) \
CHECK_LYD_STRING_PARAM(MODEL, TEXT, LYD_XML, LYD_PRINT_WITHSIBLINGS | PARAMS)
static void
test_batch(void **state)
{
const char *start =
"<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
" <module>\n"
" <name>yang</name>\n"
" <revision>2016-02-11</revision>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
"</modules-state>\n";
const char *data[] = {
"<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
" <module>\n"
" <name>ietf-yang-library</name>\n"
" <revision>2016-02-01</revision>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
"</modules-state>\n",
"<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
" <module>\n"
" <name>ietf-netconf-acm</name>\n"
" <revision>2012-02-22</revision>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
"</modules-state>\n",
"<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
" <module>\n"
" <name>ietf-netconf</name>\n"
" <revision>2011-06-01</revision>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
"</modules-state>\n",
"<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
" <module>\n"
" <name>ietf-netconf-monitoring</name>\n"
" <revision>2010-10-04</revision>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
"</modules-state>\n",
"<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
" <module>\n"
" <name>ietf-netconf-with-defaults</name>\n"
" <revision>2011-06-01</revision>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
"</modules-state>\n",
"<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
" <module>\n"
" <name>yang</name>\n"
" <revision>2016-02-11</revision>\n"
" <namespace>urn:ietf:params:xml:ns:yang:1</namespace>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
"</modules-state>\n",
"<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
" <module>\n"
" <name>ietf-yang-library</name>\n"
" <revision>2016-02-01</revision>\n"
" <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
"</modules-state>\n",
"<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
" <module>\n"
" <name>ietf-netconf-acm</name>\n"
" <revision>2012-02-22</revision>\n"
" <namespace>urn:ietf:params:xml:ns:yang:ietf-netconf-acm</namespace>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
"</modules-state>\n",
"<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
" <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>rollback-on-error</feature>\n"
" <feature>validate</feature>\n"
" <feature>startup</feature>\n"
" <feature>xpath</feature>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
"</modules-state>\n",
"<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
" <module>\n"
" <name>ietf-netconf-monitoring</name>\n"
" <revision>2010-10-04</revision>\n"
" <namespace>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring</namespace>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
"</modules-state>\n",
"<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
" <module>\n"
" <name>ietf-netconf-with-defaults</name>\n"
" <revision>2011-06-01</revision>\n"
" <namespace>urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults</namespace>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
"</modules-state>\n"
};
const char *output_template =
"<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">\n"
" <module>\n"
" <name>yang</name>\n"
" <revision>2016-02-11</revision>\n"
" <namespace>urn:ietf:params:xml:ns:yang:1</namespace>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
" <module>\n"
" <name>ietf-yang-library</name>\n"
" <revision>2016-02-01</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-netconf-acm</name>\n"
" <revision>2012-02-22</revision>\n"
" <namespace>urn:ietf:params:xml:ns:yang:ietf-netconf-acm</namespace>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
" <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>rollback-on-error</feature>\n"
" <feature>validate</feature>\n"
" <feature>startup</feature>\n"
" <feature>xpath</feature>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
" <module>\n"
" <name>ietf-netconf-monitoring</name>\n"
" <revision>2010-10-04</revision>\n"
" <namespace>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring</namespace>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
" <module>\n"
" <name>ietf-netconf-with-defaults</name>\n"
" <revision>2011-06-01</revision>\n"
" <namespace>urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults</namespace>\n"
" <conformance-type>implement</conformance-type>\n"
" </module>\n"
"</modules-state>\n";
struct lyd_node *target;
CHECK_PARSE_LYD_PARAM(start, LYD_XML, LYD_PARSE_ONLY, 0, LY_SUCCESS, target);
for (int32_t i = 0; i < 11; ++i) {
struct lyd_node *source;
CHECK_PARSE_LYD_PARAM(data[i], LYD_XML, LYD_PARSE_ONLY, 0, LY_SUCCESS, source);
assert_int_equal(LY_SUCCESS, lyd_merge_siblings(&target, source, LYD_MERGE_DESTRUCT));
}
LYD_TREE_CHECK_CHAR(target, output_template, 0);
lyd_free_all(target);
}
static void
test_leaf(void **state)
{
const char *sch = "module x {"
" namespace urn:x;"
" prefix x;"
" container A {"
" leaf f1 {type string;}"
" container B {"
" leaf f2 {type string;}"
" }"
" }"
" }";
const char *trg = "<A xmlns=\"urn:x\"> <f1>block</f1> </A>";
const char *src = "<A xmlns=\"urn:x\"> <f1>aa</f1> <B> <f2>bb</f2> </B> </A>";
const char *result = "<A xmlns=\"urn:x\"><f1>aa</f1><B><f2>bb</f2></B></A>";
struct lyd_node *source, *target;
UTEST_ADD_MODULE(sch, LYS_IN_YANG, NULL, NULL);
LYD_TREE_CREATE(src, source);
LYD_TREE_CREATE(trg, target);
/* merge them */
assert_int_equal(lyd_merge_siblings(&target, source, 0), LY_SUCCESS);
assert_int_equal(lyd_validate_all(&target, NULL, LYD_VALIDATE_PRESENT, NULL), LY_SUCCESS);
/* check the result */
LYD_TREE_CHECK_CHAR(target, result, LYD_PRINT_SHRINK);
lyd_free_all(target);
lyd_free_all(source);
}
static void
test_container(void **state)
{
const char *sch =
"module A {\n"
" namespace \"aa:A\";\n"
" prefix A;\n"
" container A {\n"
" leaf f1 {type string;}\n"
" container B {\n"
" leaf f2 {type string;}\n"
" }\n"
" container C {\n"
" leaf f3 {type string;}\n"
" }\n"
" }\n"
"}\n";
const char *trg = "<A xmlns=\"aa:A\"> <B> <f2>aaa</f2> </B> </A>";
const char *src = "<A xmlns=\"aa:A\"> <C> <f3>bbb</f3> </C> </A>";
const char *result = "<A xmlns=\"aa:A\"><B><f2>aaa</f2></B><C><f3>bbb</f3></C></A>";
struct lyd_node *source, *target;
UTEST_ADD_MODULE(sch, LYS_IN_YANG, NULL, NULL);
LYD_TREE_CREATE(src, source);
LYD_TREE_CREATE(trg, target);
/* merge them */
assert_int_equal(lyd_merge_siblings(&target, source, 0), LY_SUCCESS);
assert_int_equal(lyd_validate_all(&target, NULL, LYD_VALIDATE_PRESENT, NULL), LY_SUCCESS);
/* check the result */
LYD_TREE_CHECK_CHAR(target, result, LYD_PRINT_SHRINK);
/* destroy */
lyd_free_all(source);
lyd_free_all(target);
}
static void
test_list(void **state)
{
const char *sch =
"module merge {\n"
" namespace \"http://test/merge\";\n"
" prefix merge;\n"
"\n"
" container inner1 {\n"
" list b-list1 {\n"
" key p1;\n"
" leaf p1 {\n"
" type uint8;\n"
" }\n"
" leaf p2 {\n"
" type string;\n"
" }\n"
" leaf p3 {\n"
" type boolean;\n"
" default false;\n"
" }\n"
" }\n"
" }\n"
"}\n";
const char *trg =
"<inner1 xmlns=\"http://test/merge\">\n"
" <b-list1>\n"
" <p1>1</p1>\n"
" <p2>a</p2>\n"
" <p3>true</p3>\n"
" </b-list1>\n"
"</inner1>\n";
const char *src =
"<inner1 xmlns=\"http://test/merge\">\n"
" <b-list1>\n"
" <p1>1</p1>\n"
" <p2>b</p2>\n"
" </b-list1>\n"
"</inner1>\n";
const char *result =
"<inner1 xmlns=\"http://test/merge\">\n"
" <b-list1>\n"
" <p1>1</p1>\n"
" <p2>b</p2>\n"
" <p3>true</p3>\n"
" </b-list1>\n"
"</inner1>\n";
struct lyd_node *source, *target;
UTEST_ADD_MODULE(sch, LYS_IN_YANG, NULL, NULL);
LYD_TREE_CREATE(src, source);
LYD_TREE_CREATE(trg, target);
/* merge them */
assert_int_equal(lyd_merge_siblings(&target, source, 0), LY_SUCCESS);
assert_int_equal(lyd_validate_all(&target, NULL, LYD_VALIDATE_PRESENT, NULL), LY_SUCCESS);
/* check the result */
LYD_TREE_CHECK_CHAR(target, result, 0);
lyd_free_all(target);
lyd_free_all(source);
}
static void
test_list2(void **state)
{
const char *sch =
"module merge {\n"
" namespace \"http://test/merge\";\n"
" prefix merge;\n"
"\n"
" container inner1 {\n"
" list b-list1 {\n"
" key p1;\n"
" leaf p1 {\n"
" type uint8;\n"
" }\n"
" leaf p2 {\n"
" type string;\n"
" }\n"
" container inner2 {\n"
" leaf p3 {\n"
" type boolean;\n"
" default false;\n"
" }\n"
" leaf p4 {\n"
" type string;\n"
" }\n"
" }\n"
" }\n"
" }\n"
"}\n";
const char *trg =
"<inner1 xmlns=\"http://test/merge\">\n"
" <b-list1>\n"
" <p1>1</p1>\n"
" <p2>a</p2>\n"
" <inner2>\n"
" <p4>val</p4>\n"
" </inner2>\n"
" </b-list1>\n"
"</inner1>\n";
const char *src =
"<inner1 xmlns=\"http://test/merge\">\n"
" <b-list1>\n"
" <p1>1</p1>\n"
" <p2>b</p2>\n"
" </b-list1>\n"
"</inner1>\n";
const char *result =
"<inner1 xmlns=\"http://test/merge\">\n"
" <b-list1>\n"
" <p1>1</p1>\n"
" <p2>b</p2>\n"
" <inner2>\n"
" <p4>val</p4>\n"
" </inner2>\n"
" </b-list1>\n"
"</inner1>\n";
struct lyd_node *source, *target;
UTEST_ADD_MODULE(sch, LYS_IN_YANG, NULL, NULL);
LYD_TREE_CREATE(src, source);
LYD_TREE_CREATE(trg, target);
/* merge them */
assert_int_equal(lyd_merge_siblings(&target, source, 0), LY_SUCCESS);
assert_int_equal(lyd_validate_all(&target, NULL, LYD_VALIDATE_PRESENT, NULL), LY_SUCCESS);
/* check the result */
LYD_TREE_CHECK_CHAR(target, result, 0);
lyd_free_all(source);
lyd_free_all(target);
}
static void
test_dup_inst_list(void **state)
{
const char *sch =
"module merge {\n"
" namespace \"http://test/merge\";\n"
" prefix merge;\n"
"\n"
" container inner1 {\n"
" config false;\n"
" list b-list1 {\n"
" leaf p1 {\n"
" type uint8;\n"
" }\n"
" leaf p2 {\n"
" type string;\n"
" }\n"
" container inner2 {\n"
" leaf p4 {\n"
" type string;\n"
" }\n"
" }\n"
" }\n"
" }\n"
"}\n";
const char *trg =
"<inner1 xmlns=\"http://test/merge\">\n"
" <b-list1>\n"
" <p1>1</p1>\n"
" <p2>b</p2>\n"
" </b-list1>\n"
" <b-list1>\n"
" <p1>1</p1>\n"
" <p2>a</p2>\n"
" <inner2>\n"
" <p4>val</p4>\n"
" </inner2>\n"
" </b-list1>\n"
"</inner1>\n";
const char *src =
"<inner1 xmlns=\"http://test/merge\">\n"
" <b-list1>\n"
" <p1>1</p1>\n"
" <p2>b</p2>\n"
" </b-list1>\n"
" <b-list1>\n"
" <p1>2</p1>\n"
" <p2>a</p2>\n"
" </b-list1>\n"
"</inner1>\n";
const char *result =
"<inner1 xmlns=\"http://test/merge\">\n"
" <b-list1>\n"
" <p1>1</p1>\n"
" <p2>b</p2>\n"
" </b-list1>\n"
" <b-list1>\n"
" <p1>1</p1>\n"
" <p2>a</p2>\n"
" <inner2>\n"
" <p4>val</p4>\n"
" </inner2>\n"
" </b-list1>\n"
" <b-list1>\n"
" <p1>2</p1>\n"
" <p2>a</p2>\n"
" </b-list1>\n"
"</inner1>\n";
struct lyd_node *source, *target;
UTEST_ADD_MODULE(sch, LYS_IN_YANG, NULL, NULL);
LYD_TREE_CREATE(src, source);
LYD_TREE_CREATE(trg, target);
/* merge them */
assert_int_equal(lyd_merge_siblings(&target, source, 0), LY_SUCCESS);
assert_int_equal(lyd_validate_all(&target, NULL, LYD_VALIDATE_PRESENT, NULL), LY_SUCCESS);
/* check the result */
LYD_TREE_CHECK_CHAR(target, result, 0);
lyd_free_all(source);
lyd_free_all(target);
}
static void
test_dup_inst_llist(void **state)
{
const char *sch =
"module merge {\n"
" namespace \"http://test/merge\";\n"
" prefix merge;\n"
"\n"
" container inner1 {\n"
" config false;\n"
" leaf-list b-llist1 {\n"
" type string;\n"
" }\n"
" }\n"
"}\n";
const char *trg =
"<inner1 xmlns=\"http://test/merge\">\n"
" <b-llist1>a</b-llist1>\n"
" <b-llist1>b</b-llist1>\n"
" <b-llist1>c</b-llist1>\n"
" <b-llist1>d</b-llist1>\n"
" <b-llist1>a</b-llist1>\n"
" <b-llist1>b</b-llist1>\n"
" <b-llist1>c</b-llist1>\n"
" <b-llist1>d</b-llist1>\n"
"</inner1>\n";
const char *src =
"<inner1 xmlns=\"http://test/merge\">\n"
" <b-llist1>d</b-llist1>\n"
" <b-llist1>c</b-llist1>\n"
" <b-llist1>b</b-llist1>\n"
" <b-llist1>a</b-llist1>\n"
" <b-llist1>a</b-llist1>\n"
" <b-llist1>a</b-llist1>\n"
" <b-llist1>a</b-llist1>\n"
" <b-llist1>f</b-llist1>\n"
" <b-llist1>f</b-llist1>\n"
"</inner1>\n";
const char *result =
"<inner1 xmlns=\"http://test/merge\">\n"
" <b-llist1>a</b-llist1>\n"
" <b-llist1>b</b-llist1>\n"
" <b-llist1>c</b-llist1>\n"
" <b-llist1>d</b-llist1>\n"
" <b-llist1>a</b-llist1>\n"
" <b-llist1>b</b-llist1>\n"
" <b-llist1>c</b-llist1>\n"
" <b-llist1>d</b-llist1>\n"
" <b-llist1>a</b-llist1>\n"
" <b-llist1>a</b-llist1>\n"
" <b-llist1>f</b-llist1>\n"
" <b-llist1>f</b-llist1>\n"
"</inner1>\n";
struct lyd_node *source, *target;
UTEST_ADD_MODULE(sch, LYS_IN_YANG, NULL, NULL);
LYD_TREE_CREATE(src, source);
LYD_TREE_CREATE(trg, target);
/* merge them */
assert_int_equal(lyd_merge_siblings(&target, source, 0), LY_SUCCESS);
assert_int_equal(lyd_validate_all(&target, NULL, LYD_VALIDATE_PRESENT, NULL), LY_SUCCESS);
/* check the result */
LYD_TREE_CHECK_CHAR(target, result, 0);
lyd_free_all(source);
lyd_free_all(target);
}
static void
test_case(void **state)
{
const char *sch =
"module merge {\n"
" namespace \"http://test/merge\";\n"
" prefix merge;\n"
" container cont {\n"
" choice ch {\n"
" container inner {\n"
" leaf p1 {\n"
" type string;\n"
" }\n"
" }\n"
" case c2 {\n"
" leaf p1 {\n"
" type string;\n"
" }\n"
" }\n"
" }\n"
" }\n"
"}\n";
const char *trg =
"<cont xmlns=\"http://test/merge\">\n"
" <inner>\n"
" <p1>1</p1>\n"
" </inner>\n"
"</cont>\n";
const char *src =
"<cont xmlns=\"http://test/merge\">\n"
" <p1>1</p1>\n"
"</cont>\n";
const char *result =
"<cont xmlns=\"http://test/merge\">\n"
" <p1>1</p1>\n"
"</cont>\n";
struct lyd_node *source, *target;
UTEST_ADD_MODULE(sch, LYS_IN_YANG, NULL, NULL);
LYD_TREE_CREATE(src, source);
LYD_TREE_CREATE(trg, target);
/* merge them */
assert_int_equal(lyd_merge_siblings(&target, source, 0), LY_SUCCESS);
assert_int_equal(lyd_validate_all(&target, NULL, LYD_VALIDATE_PRESENT, NULL), LY_SUCCESS);
/* check the result */
LYD_TREE_CHECK_CHAR(target, result, 0);
lyd_free_all(source);
lyd_free_all(target);
}
static void
test_dflt(void **state)
{
const char *sch =
"module merge-dflt {\n"
" namespace \"urn:merge-dflt\";\n"
" prefix md;\n"
" container top {\n"
" leaf a {\n"
" type string;\n"
" }\n"
" leaf b {\n"
" type string;\n"
" }\n"
" leaf c {\n"
" type string;\n"
" default \"c_dflt\";\n"
" }\n"
" }\n"
"}\n";
struct lyd_node *target = NULL;
struct lyd_node *source = NULL;
UTEST_ADD_MODULE(sch, LYS_IN_YANG, NULL, NULL);
assert_int_equal(lyd_new_path(NULL, UTEST_LYCTX, "/merge-dflt:top/c", "c_dflt", 0, &target), LY_SUCCESS);
assert_int_equal(lyd_validate_all(&target, NULL, LYD_VALIDATE_PRESENT, NULL), LY_SUCCESS);
assert_int_equal(lyd_new_path(NULL, UTEST_LYCTX, "/merge-dflt:top/a", "a_val", 0, &source), LY_SUCCESS);
assert_int_equal(lyd_new_path(source, UTEST_LYCTX, "/merge-dflt:top/b", "b_val", 0, NULL), LY_SUCCESS);
assert_int_equal(lyd_validate_all(&source, NULL, LYD_VALIDATE_PRESENT, NULL), LY_SUCCESS);
assert_int_equal(lyd_merge_siblings(&target, source, LYD_MERGE_DESTRUCT | LYD_MERGE_DEFAULTS), LY_SUCCESS);
source = NULL;
/* c should be replaced and now be default */
assert_string_equal(lyd_child(target)->prev->schema->name, "c");
assert_true(lyd_child(target)->prev->flags & LYD_DEFAULT);
lyd_free_all(target);
lyd_free_all(source);
}
static void
test_dflt2(void **state)
{
const char *sch =
"module merge-dflt {\n"
" namespace \"urn:merge-dflt\";\n"
" prefix md;\n"
" container top {\n"
" leaf a {\n"
" type string;\n"
" }\n"
" leaf b {\n"
" type string;\n"
" }\n"
" leaf c {\n"
" type string;\n"
" default \"c_dflt\";\n"
" }\n"
" }\n"
"}\n";
struct lyd_node *target;
struct lyd_node *source;
UTEST_ADD_MODULE(sch, LYS_IN_YANG, NULL, NULL);
assert_int_equal(lyd_new_path(NULL, UTEST_LYCTX, "/merge-dflt:top/c", "c_dflt", 0, &target), LY_SUCCESS);
assert_int_equal(lyd_validate_all(&target, NULL, LYD_VALIDATE_PRESENT, NULL), LY_SUCCESS);
assert_int_equal(lyd_new_path(NULL, UTEST_LYCTX, "/merge-dflt:top/a", "a_val", 0, &source), LY_SUCCESS);
assert_int_equal(lyd_new_path(source, UTEST_LYCTX, "/merge-dflt:top/b", "b_val", 0, NULL), LY_SUCCESS);
assert_int_equal(lyd_validate_all(&source, NULL, LYD_VALIDATE_PRESENT, NULL), LY_SUCCESS);
assert_int_equal(lyd_merge_siblings(&target, source, 0), LY_SUCCESS);
/* c should not be replaced, so c remains not default */
assert_false(lyd_child(target)->flags & LYD_DEFAULT);
lyd_free_all(target);
lyd_free_all(source);
}
static void
test_leafrefs(void **state)
{
const char *sch = "module x {"
" namespace urn:x;"
" prefix x;"
" list l {"
" key n;"
" leaf n { type string; }"
" leaf t { type string; }"
" leaf r { type leafref { path '/l/n'; } }}}";
const char *trg = "<l xmlns=\"urn:x\"><n>a</n></l>"
"<l xmlns=\"urn:x\"><n>b</n><r>a</r></l>";
const char *src = "<l xmlns=\"urn:x\"><n>c</n><r>a</r></l>"
"<l xmlns=\"urn:x\"><n>a</n><t>*</t></l>";
const char *res = "<l xmlns=\"urn:x\"><n>a</n><t>*</t></l>"
"<l xmlns=\"urn:x\"><n>b</n><r>a</r></l>"
"<l xmlns=\"urn:x\"><n>c</n><r>a</r></l>";
struct lyd_node *source, *target;
UTEST_ADD_MODULE(sch, LYS_IN_YANG, NULL, NULL);
LYD_TREE_CREATE(src, source);
LYD_TREE_CREATE(trg, target);
assert_int_equal(lyd_merge_siblings(&target, source, 0), LY_SUCCESS);
LYD_TREE_CHECK_CHAR(target, res, LYD_PRINT_SHRINK);
lyd_free_all(source);
lyd_free_all(target);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_batch),
UTEST(test_leaf),
UTEST(test_container),
UTEST(test_list),
UTEST(test_list2),
UTEST(test_dup_inst_list),
UTEST(test_dup_inst_llist),
UTEST(test_case),
UTEST(test_dflt),
UTEST(test_dflt2),
UTEST(test_leafrefs),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

View file

@ -0,0 +1,536 @@
/**
* @file test_new.c
* @author: Michal Vasko <mvasko@cesnet.cz>
* @brief unit tests for functions for creating data
*
* Copyright (c) 2020 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 "libyang.h"
/* common module for the tests */
const char *schema_a = "module a {\n"
" namespace urn:tests:a;\n"
" prefix a;yang-version 1.1;\n"
" list l1 {\n"
" key \"a b\";\n"
" leaf a {\n"
" type string;\n"
" }\n"
" leaf b {\n"
" type string;\n"
" }\n"
" leaf c {\n"
" type string;\n"
" }\n"
" }\n"
" list l11 {\n"
" key \"a\";\n"
" leaf a {\n"
" type uint32;\n"
" }\n"
" leaf b {\n"
" type uint32;\n"
" }\n"
" }\n"
" leaf foo {\n"
" type uint16;\n"
" }\n"
" leaf-list ll {\n"
" type string;\n"
" }\n"
" container c {\n"
" leaf-list x {\n"
" type string;\n"
" }\n"
" }\n"
" anydata any {\n"
" config false;\n"
" }\n"
" anyxml anyx;\n"
" leaf-list ll2 {\n"
" config false;\n"
" type string;\n"
" }\n"
" list l2 {\n"
" config false;\n"
" container c {\n"
" leaf x {\n"
" type string;\n"
" }\n"
" }\n"
" }\n"
" container c2 {\n"
" config false;\n"
" list l3 {\n"
" leaf x {\n"
" type string;\n"
" }\n"
" leaf y {\n"
" type string;\n"
" }\n"
" }\n"
" }\n"
" rpc oper {\n"
" input {\n"
" leaf param {\n"
" type string;\n"
" }\n"
" }\n"
" output {\n"
" leaf param {\n"
" type int8;\n"
" }\n"
" }\n"
" }\n"
"}\n";
static void
test_top_level(void **state)
{
struct lys_module *mod;
struct lyd_node *node, *rpc;
UTEST_ADD_MODULE(schema_a, LYS_IN_YANG, NULL, &mod);
/* list */
assert_int_equal(lyd_new_list(NULL, mod, "l1", 0, &node, "val_a", "val_b"), LY_SUCCESS);
lyd_free_tree(node);
assert_int_equal(lyd_new_list2(NULL, mod, "l1", "[]", 0, &node), LY_EVALID);
CHECK_LOG_CTX("Unexpected XPath token \"]\" (\"]\").", "/a:l1", 0);
assert_int_equal(lyd_new_list2(NULL, mod, "l1", "[key1='a'][key2='b']", 0, &node), LY_ENOTFOUND);
CHECK_LOG_CTX("Not found node \"key1\" in path.", "/a:l1", 0);
assert_int_equal(lyd_new_list2(NULL, mod, "l1", "[a='a'][b='b'][c='c']", 0, &node), LY_EVALID);
CHECK_LOG_CTX("Key expected instead of leaf \"c\" in path.", "/a:l1", 0);
assert_int_equal(lyd_new_list2(NULL, mod, "c", "[a='a'][b='b']", 0, &node), LY_ENOTFOUND);
CHECK_LOG_CTX("List node \"c\" not found.", NULL, 0);
assert_int_equal(lyd_new_list2(NULL, mod, "l1", "[a='a'][b='b']", 0, &node), LY_SUCCESS);
lyd_free_tree(node);
assert_int_equal(lyd_new_list2(NULL, mod, "l1", "[a=''][b='']", 0, &node), LY_SUCCESS);
lyd_free_tree(node);
assert_int_equal(lyd_new_list2(NULL, mod, "l1", "[a:a='a'][a:b='b']", 0, &node), LY_SUCCESS);
lyd_free_tree(node);
assert_int_equal(lyd_new_list2(NULL, mod, "l1", "[a= 'a']\n[b =\t'b']", 0, &node), LY_SUCCESS);
lyd_free_tree(node);
const char *key_vals[] = {"a", "b"};
assert_int_equal(lyd_new_list3(NULL, mod, "l1", key_vals, NULL, 0, &node), LY_SUCCESS);
lyd_free_tree(node);
uint32_t val_lens[] = {1, 1};
assert_int_equal(lyd_new_list3(NULL, mod, "l1", key_vals, val_lens, LYD_NEW_VAL_BIN, &node), LY_SUCCESS);
lyd_free_tree(node);
assert_int_equal(lyd_new_list3(NULL, mod, "l1", key_vals, val_lens, LYD_NEW_VAL_CANON, &node), LY_SUCCESS);
lyd_free_tree(node);
assert_int_equal(lyd_new_list3(NULL, mod, "l1", key_vals, val_lens, LYD_NEW_VAL_CANON | LYD_NEW_VAL_STORE_ONLY, &node), LY_EINVAL);
CHECK_LOG_CTX("Invalid argument !(store_only && (format == LY_VALUE_CANON || format == LY_VALUE_LYB)) (lyd_new_list3()).", NULL, 0);
assert_int_equal(lyd_new_list(NULL, mod, "l1", LYD_NEW_VAL_BIN, &node, "val_a", 5, "val_b", 5), LY_SUCCESS);
lyd_free_tree(node);
assert_int_equal(lyd_new_list(NULL, mod, "l1", LYD_NEW_VAL_BIN | LYD_NEW_VAL_STORE_ONLY, &node, "val_a", 5, "val_b", 5), LY_EINVAL);
CHECK_LOG_CTX("Invalid argument !(store_only && (format == LY_VALUE_CANON || format == LY_VALUE_LYB)) (lyd_new_list()).", NULL, 0);
assert_int_equal(lyd_new_list(NULL, mod, "l1", LYD_NEW_VAL_CANON, &node, "val_a", "val_b"), LY_SUCCESS);
lyd_free_tree(node);
assert_int_equal(lyd_new_list(NULL, mod, "l1", LYD_NEW_VAL_CANON | LYD_NEW_VAL_STORE_ONLY, &node, "val_a", "val_b"), LY_EINVAL);
CHECK_LOG_CTX("Invalid argument !(store_only && (format == LY_VALUE_CANON || format == LY_VALUE_LYB)) (lyd_new_list()).", NULL, 0);
/* leaf */
assert_int_equal(lyd_new_term(NULL, mod, "foo", "[a='a'][b='b'][c='c']", 0, &node), LY_EVALID);
CHECK_LOG_CTX("Invalid type uint16 value \"[a='a'][b='b'][c='c']\".", "/a:foo", 0);
assert_int_equal(lyd_new_term(NULL, mod, "c", "value", 0, &node), LY_ENOTFOUND);
CHECK_LOG_CTX("Term node \"c\" not found.", NULL, 0);
assert_int_equal(lyd_new_term(NULL, mod, "foo", "256", 0, &node), LY_SUCCESS);
lyd_free_tree(node);
assert_int_equal(lyd_new_term(NULL, mod, "foo", "25", LYD_NEW_VAL_BIN, &node), LY_EINVAL);
CHECK_LOG_CTX("Invalid argument !(options & 0x04) (lyd_new_term()).", NULL, 0);
assert_int_equal(lyd_new_term_bin(NULL, mod, "foo", "25", 2, LYD_NEW_VAL_BIN, &node), LY_SUCCESS);
lyd_free_tree(node);
assert_int_equal(lyd_new_term_bin(NULL, mod, "foo", "25", 2, LYD_NEW_VAL_STORE_ONLY, &node), LY_EINVAL);
CHECK_LOG_CTX("Invalid argument !(store_only && (format == LY_VALUE_CANON || format == LY_VALUE_LYB)) (_lyd_new_term()).", NULL, 0);
assert_int_equal(lyd_new_term(NULL, mod, "foo", "25", LYD_NEW_VAL_CANON, &node), LY_SUCCESS);
lyd_free_tree(node);
assert_int_equal(lyd_new_term(NULL, mod, "foo", "25", LYD_NEW_VAL_CANON | LYD_NEW_VAL_STORE_ONLY, &node), LY_EINVAL);
CHECK_LOG_CTX("Invalid argument !(store_only && (format == LY_VALUE_CANON || format == LY_VALUE_LYB)) (_lyd_new_term()).", NULL, 0);
/* leaf-list */
assert_int_equal(lyd_new_term(NULL, mod, "ll", "ahoy", 0, &node), LY_SUCCESS);
lyd_free_tree(node);
/* container */
assert_int_equal(lyd_new_inner(NULL, mod, "c", 0, &node), LY_SUCCESS);
lyd_free_tree(node);
assert_int_equal(lyd_new_inner(NULL, mod, "l1", 0, &node), LY_ENOTFOUND);
CHECK_LOG_CTX("Inner node (container, notif, RPC, or action) \"l1\" not found.", NULL, 0);
assert_int_equal(lyd_new_inner(NULL, mod, "l2", 0, &node), LY_ENOTFOUND);
CHECK_LOG_CTX("Inner node (container, notif, RPC, or action) \"l2\" not found.", NULL, 0);
/* anydata */
assert_int_equal(lyd_new_any(NULL, mod, "any", "{\"node\":\"val\"}", LYD_ANYDATA_STRING, 0, &node), LY_SUCCESS);
lyd_free_tree(node);
assert_int_equal(lyd_new_any(NULL, mod, "any", "<node>val</node>", LYD_ANYDATA_STRING, 0, &node), LY_SUCCESS);
lyd_free_tree(node);
/* key-less list */
assert_int_equal(lyd_new_list2(NULL, mod, "l2", "[a='a'][b='b']", 0, &node), LY_EVALID);
CHECK_LOG_CTX("List predicate defined for keyless list \"l2\" in path.", "/a:l2", 0);
assert_int_equal(lyd_new_list2(NULL, mod, "l2", "", 0, &node), LY_SUCCESS);
lyd_free_tree(node);
assert_int_equal(lyd_new_list2(NULL, mod, "l2", NULL, 0, &node), LY_SUCCESS);
lyd_free_tree(node);
assert_int_equal(lyd_new_list(NULL, mod, "l2", 0, &node), LY_SUCCESS);
lyd_free_tree(node);
/* RPC */
assert_int_equal(lyd_new_inner(NULL, mod, "oper", 0, &rpc), LY_SUCCESS);
assert_int_equal(lyd_new_term(rpc, mod, "param", "22", 0, &node), LY_SUCCESS);
assert_int_equal(LY_TYPE_STRING, ((struct lysc_node_leaf *)node->schema)->type->basetype);
assert_int_equal(lyd_new_term(rpc, mod, "param", "22", LYD_NEW_VAL_OUTPUT, &node), LY_SUCCESS);
assert_int_equal(LY_TYPE_INT8, ((struct lysc_node_leaf *)node->schema)->type->basetype);
lyd_free_tree(rpc);
}
static void
test_opaq(void **state)
{
struct lyd_node *root, *node;
struct lyd_node_opaq *opq;
UTEST_ADD_MODULE(schema_a, LYS_IN_YANG, NULL, NULL);
assert_int_equal(lyd_new_opaq(NULL, UTEST_LYCTX, "node1", NULL, NULL, "my-module", &root), LY_SUCCESS);
assert_null(root->schema);
opq = (struct lyd_node_opaq *)root;
assert_string_equal(opq->name.name, "node1");
assert_string_equal(opq->name.module_name, "my-module");
assert_string_equal(opq->value, "");
assert_int_equal(lyd_new_opaq(root, NULL, "node2", "value", NULL, "my-module2", &node), LY_SUCCESS);
assert_null(node->schema);
opq = (struct lyd_node_opaq *)node;
assert_string_equal(opq->name.name, "node2");
assert_string_equal(opq->name.module_name, "my-module2");
assert_string_equal(opq->value, "value");
assert_ptr_equal(opq->parent, root);
lyd_free_tree(root);
}
static void
test_path(void **state)
{
LY_ERR ret;
struct lyd_node *root, *node, *parent;
struct lys_module *mod;
char *str;
UTEST_ADD_MODULE(schema_a, LYS_IN_YANG, NULL, &mod);
/* create 2 nodes */
ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:c/x[.='val']", "vvv", 0, 0, 0, &root, &node);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(root);
assert_string_equal(root->schema->name, "c");
assert_non_null(node);
assert_string_equal(node->schema->name, "x");
assert_string_equal("val", lyd_get_value(node));
/* append another */
ret = lyd_new_path2(root, NULL, "/a:c/x", "val2", 0, 0, 0, &parent, &node);
assert_int_equal(ret, LY_SUCCESS);
assert_ptr_equal(parent, node);
assert_string_equal(node->schema->name, "x");
assert_string_equal("val2", lyd_get_value(node));
/* and a last one */
ret = lyd_new_path2(root, NULL, "x", "val3", 0, 0, 0, &parent, &node);
assert_int_equal(ret, LY_SUCCESS);
assert_ptr_equal(parent, node);
assert_string_equal(node->schema->name, "x");
assert_string_equal("val3", lyd_get_value(node));
lyd_free_tree(root);
/* try LYD_NEWOPT_OPAQ */
ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:l1", NULL, 0, 0, 0, NULL, NULL);
assert_int_equal(ret, LY_EINVAL);
CHECK_LOG_CTX("Predicate missing for list \"l1\" in path \"/a:l1\".", "/a:l1", 0);
ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:l1", NULL, 0, 0, LYD_NEW_PATH_OPAQ, NULL, &root);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(root);
assert_null(root->schema);
lyd_free_tree(root);
ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:foo", NULL, 0, 0, 0, NULL, NULL);
assert_int_equal(ret, LY_EVALID);
CHECK_LOG_CTX("Invalid type uint16 empty value.", "/a:foo", 0);
ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:foo", NULL, 0, 0, LYD_NEW_PATH_OPAQ, NULL, &root);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(root);
assert_null(root->schema);
lyd_free_tree(root);
ret = lyd_new_path(NULL, UTEST_LYCTX, "/a:l11", NULL, LYD_NEW_PATH_OPAQ, &root);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(root);
assert_null(root->schema);
ret = lyd_new_path(root, NULL, "a", NULL, LYD_NEW_PATH_OPAQ, NULL);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(lyd_child(root));
assert_null(lyd_child(root)->schema);
ret = lyd_new_path(root, NULL, "b", NULL, LYD_NEW_PATH_OPAQ, NULL);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(lyd_child(root)->next);
assert_null(lyd_child(root)->next->schema);
lyd_free_tree(root);
/* key-less list */
ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:c2/l3/x", "val1", 0, 0, 0, &root, &node);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(root);
assert_string_equal(node->schema->name, "x");
assert_string_equal("val1", lyd_get_value(node));
ret = lyd_new_path2(root, NULL, "/a:c2/l3[1]", NULL, 0, 0, 0, NULL, &node);
assert_int_equal(ret, LY_EEXIST);
CHECK_LOG_CTX("Path \"/a:c2/l3[1]\" already exists.", "/a:c2/l3[1]", 0);
ret = lyd_new_path2(root, NULL, "/a:c2/l3[2]/x", "val2", 0, 0, 0, NULL, &node);
assert_int_equal(ret, LY_SUCCESS);
ret = lyd_new_path2(root, NULL, "/a:c2/l3/x", "val3", 0, 0, 0, NULL, &node);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(node);
ret = lyd_new_path2(root, NULL, "/a:c2/l3[4]/x", "empty", 0, 0, 0, NULL, &node);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(node);
ret = lyd_new_path2(root, NULL, "/a:c2/l3[4]/x", "val4", 0, 0, LYD_NEW_PATH_UPDATE, NULL, &node);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(node);
ret = lyd_new_path2(root, NULL, "/a:c2/l3[5]/x", "val5", 0, 0, 0, NULL, &node);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(node);
ret = lyd_new_path2(root, NULL, "/a:c2/l3[6]/x", "val6", 0, 0, 0, NULL, &node);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(node);
lyd_print_mem(&str, root, LYD_XML, LYD_PRINT_WITHSIBLINGS);
assert_string_equal(str,
"<c2 xmlns=\"urn:tests:a\">\n"
" <l3>\n"
" <x>val1</x>\n"
" </l3>\n"
" <l3>\n"
" <x>val2</x>\n"
" </l3>\n"
" <l3>\n"
" <x>val3</x>\n"
" </l3>\n"
" <l3>\n"
" <x>val4</x>\n"
" </l3>\n"
" <l3>\n"
" <x>val5</x>\n"
" </l3>\n"
" <l3>\n"
" <x>val6</x>\n"
" </l3>\n"
"</c2>\n");
free(str);
lyd_free_siblings(root);
/* state leaf-list */
ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:ll2", "val_first", 0, 0, 0, &root, &node);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(root);
assert_string_equal(node->schema->name, "ll2");
assert_string_equal("val_first", lyd_get_value(node));
ret = lyd_new_path2(root, NULL, "/a:ll2[1]", "", 0, 0, 0, NULL, &node);
assert_int_equal(ret, LY_EEXIST);
CHECK_LOG_CTX("Path \"/a:ll2[1]\" already exists.", "/a:ll2[1]", 0);
ret = lyd_new_path2(root, NULL, "/a:ll2[2]", "val2", 0, 0, 0, NULL, &node);
assert_int_equal(ret, LY_SUCCESS);
ret = lyd_new_path2(root, NULL, "/a:ll2[1]", "val", 0, 0, LYD_NEW_PATH_UPDATE, NULL, &node);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(node);
ret = lyd_new_path2(root, UTEST_LYCTX, "/a:ll2", "val3", 0, 0, 0, NULL, &node);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(node);
ret = lyd_new_path2(root, NULL, "/a:ll2[3][.='val3']", NULL, 0, 0, 0, NULL, &node);
assert_int_equal(ret, LY_EVALID);
CHECK_LOG_CTX("Unparsed characters \"[.='val3']\" left at the end of path.", NULL, 0);
lyd_print_mem(&str, root, LYD_XML, LYD_PRINT_WITHSIBLINGS);
assert_string_equal(str,
"<ll2 xmlns=\"urn:tests:a\">val</ll2>\n"
"<ll2 xmlns=\"urn:tests:a\">val2</ll2>\n"
"<ll2 xmlns=\"urn:tests:a\">val3</ll2>\n");
free(str);
lyd_free_siblings(root);
/* anydata */
ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:any", "<elem>val</elem>", 0, LYD_ANYDATA_XML, 0, &root, NULL);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(root);
lyd_print_mem(&str, root, LYD_XML, LYD_PRINT_WITHSIBLINGS);
assert_string_equal(str,
"<any xmlns=\"urn:tests:a\">\n"
" <elem>val</elem>\n"
"</any>\n");
free(str);
lyd_print_mem(&str, root, LYD_JSON, LYD_PRINT_WITHSIBLINGS);
assert_string_equal(str,
"{\n"
" \"a:any\": {\n"
" \"elem\": \"val\"\n"
" }\n"
"}\n");
free(str);
lyd_free_siblings(root);
/* anyxml */
ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:anyx", "<a/><b/><c/>", 0, LYD_ANYDATA_XML, 0, &root, NULL);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(root);
lyd_print_mem(&str, root, LYD_XML, LYD_PRINT_WITHSIBLINGS);
assert_string_equal(str,
"<anyx xmlns=\"urn:tests:a\">\n"
" <a/>\n"
" <b/>\n"
" <c/>\n"
"</anyx>\n");
free(str);
lyd_print_mem(&str, root, LYD_JSON, LYD_PRINT_WITHSIBLINGS);
assert_string_equal(str,
"{\n"
" \"a:anyx\": {\n"
" \"a\": [null],\n"
" \"b\": [null],\n"
" \"c\": [null]\n"
" }\n"
"}\n");
free(str);
lyd_free_siblings(root);
ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:anyx", "{\"a\":[null],\"b\":[null],\"c\":[null]}", 0, LYD_ANYDATA_JSON, 0, &root, NULL);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(root);
lyd_print_mem(&str, root, LYD_XML, LYD_PRINT_WITHSIBLINGS);
assert_string_equal(str,
"<anyx xmlns=\"urn:tests:a\">\n"
" <a/>\n"
" <b/>\n"
" <c/>\n"
"</anyx>\n");
free(str);
lyd_print_mem(&str, root, LYD_JSON, LYD_PRINT_WITHSIBLINGS);
assert_string_equal(str,
"{\n"
" \"a:anyx\": {\n"
" \"a\": [null],\n"
" \"b\": [null],\n"
" \"c\": [null]\n"
" }\n"
"}\n");
free(str);
lyd_free_siblings(root);
}
static void
test_path_ext(void **state)
{
LY_ERR ret;
struct lyd_node *root, *node;
struct lys_module *mod;
const char *mod_str = "module ext {yang-version 1.1; namespace urn:tests:extensions:ext; prefix e;"
"import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
"rc:yang-data template {container c {leaf x {type string;} leaf y {type string;} leaf z {type string;}}}}";
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(mod_str, LYS_IN_YANG, NULL, &mod);
/* create x */
ret = lyd_new_ext_path(NULL, &mod->compiled->exts[0], "/ext:c/x", "xxx", 0, &root);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(root);
assert_string_equal(root->schema->name, "c");
assert_non_null(node = lyd_child(root));
assert_string_equal(node->schema->name, "x");
assert_string_equal("xxx", lyd_get_value(node));
/* append y */
ret = lyd_new_ext_path(root, &mod->compiled->exts[0], "/ext:c/y", "yyy", 0, &node);
assert_int_equal(ret, LY_SUCCESS);
assert_string_equal(node->schema->name, "y");
assert_string_equal("yyy", lyd_get_value(node));
/* append z */
ret = lyd_new_path(root, NULL, "ext:z", "zzz", 0, &node);
assert_int_equal(ret, LY_SUCCESS);
assert_string_equal(node->schema->name, "z");
assert_string_equal("zzz", lyd_get_value(node));
lyd_free_tree(root);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_top_level),
UTEST(test_opaq),
UTEST(test_path),
UTEST(test_path_ext),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

View file

@ -0,0 +1,945 @@
/**
* @file test_parser_json.c
* @author Radek Krejci <rkrejci@cesnet.cz>
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief unit tests for JSON parser
*
* Copyright (c) 2019 - 2023 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 "out.h"
#include "parser_data.h"
#include "printer_data.h"
#include "tests_config.h"
#include "tree_data_internal.h"
#include "tree_schema.h"
static int
setup(void **state)
{
const char *schema = "module a {namespace urn:tests:a;prefix a;yang-version 1.1; import ietf-yang-metadata {prefix md;}"
"md:annotation hint { type int8;}"
"list l1 { key \"a b c\"; leaf a {type string;} leaf b {type string;} leaf c {type int16;}"
" leaf d {type string;}"
" container cont {leaf e {type boolean;}}"
"}"
"leaf foo { type string;}"
"container c {"
" leaf x {type string;}"
" action act { input { leaf al {type string;} } output { leaf al {type uint8;} } }"
" notification n1 { leaf nl {type string;} }"
"}"
"container cp {presence \"container switch\"; leaf y {type string;} leaf z {type int8;}}"
"anydata any {config false;}"
"anyxml axml;"
"leaf-list ll1 { type uint8; }"
"leaf foo2 { type string; default \"default-val\"; }"
"leaf foo3 { type uint32; }"
"leaf foo4 { type uint64; }"
"rpc r1 {input {leaf l1 {type string;} leaf l2 {type string;}}}"
"notification n2;"
"}";
UTEST_SETUP;
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_DIR_MODULES_YANG));
return 0;
}
#define CHECK_PARSE_LYD(INPUT, PARSE_OPTION, VALIDATE_OPTION, TREE) \
CHECK_PARSE_LYD_PARAM(INPUT, LYD_JSON, PARSE_OPTION, VALIDATE_OPTION, LY_SUCCESS, TREE)
#define PARSER_CHECK_ERROR(INPUT, PARSE_OPTION, VALIDATE_OPTION, MODEL, RET_VAL, ERR_MESSAGE, ERR_PATH, ERR_LINE) \
assert_int_equal(RET_VAL, lyd_parse_data_mem(UTEST_LYCTX, INPUT, LYD_JSON, PARSE_OPTION, VALIDATE_OPTION, &MODEL));\
CHECK_LOG_CTX(ERR_MESSAGE, ERR_PATH, ERR_LINE);\
assert_null(MODEL)
#define CHECK_LYD_STRING(IN_MODEL, PRINT_OPTION, TEXT) \
CHECK_LYD_STRING_PARAM(IN_MODEL, TEXT, LYD_JSON, PRINT_OPTION)
static void
test_leaf(void **state)
{
struct lyd_node *tree;
struct lyd_node_term *leaf;
const char *data;
assert_non_null(ly_ctx_load_module(UTEST_LYCTX, "ietf-netconf-with-defaults", "2011-06-01", NULL));
data = "{\"a:foo\":\"foo value\"}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "foo", 1, LYS_LEAF, 0, 0, NULL, 0);
leaf = (struct lyd_node_term *)tree;
CHECK_LYD_VALUE(leaf->value, STRING, "foo value");
CHECK_LYSC_NODE(tree->next->next->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_SET_DFLT, 1, "foo2",
1, LYS_LEAF, 0, 0, NULL, 0);
leaf = (struct lyd_node_term *)tree->next->next;
CHECK_LYD_VALUE(leaf->value, STRING, "default-val");
assert_true(leaf->flags & LYD_DEFAULT);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
/* make foo2 explicit */
data = "{\"a:foo2\":\"default-val\"}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_SET_DFLT, 1, "foo2",
1, LYS_LEAF, 0, 0, NULL, 0);
leaf = (struct lyd_node_term *)tree;
CHECK_LYD_VALUE(leaf->value, STRING, "default-val");
assert_false(leaf->flags & LYD_DEFAULT);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
/* parse foo2 but make it implicit */
data = "{\"a:foo2\":\"default-val\",\"@a:foo2\":{\"ietf-netconf-with-defaults:default\":true}}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_SET_DFLT, 1, "foo2",
1, LYS_LEAF, 0, 0, NULL, 0);
leaf = (struct lyd_node_term *)tree;
CHECK_LYD_VALUE(leaf->value, STRING, "default-val");
assert_true(leaf->flags & LYD_DEFAULT);
/* print default values */
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS | LYD_PRINT_WD_ALL_TAG, data);
lyd_free_all(tree);
/* skip leaf */
data = "{\"a:cp\":{\"x\":\"val\",\"y\":\"valy\",\"z\":5}}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, "{\"a:cp\":{\"y\":\"valy\",\"z\":5}}");
lyd_free_all(tree);
/* multiple meatadata hint and unknown metadata xxx supposed to be skipped since it is from missing schema */
data = "{\"@a:foo\":{\"a:hint\":1,\"a:hint\":2,\"x:xxx\":{\"value\":\"/x:no/x:yes\"}},\"a:foo\":\"xxx\"}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "foo", 1, LYS_LEAF, 0, 0, NULL, 0);
CHECK_LYD_META(tree->meta, 1, "hint", 1, 1, INT8, "1", 1);
CHECK_LYD_META(tree->meta->next, 1, "hint", 0, 1, INT8, "2", 2);
assert_null(tree->meta->next->next);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS,
"{\"a:foo\":\"xxx\",\"@a:foo\":{\"a:hint\":1,\"a:hint\":2}}");
lyd_free_all(tree);
PARSER_CHECK_ERROR(data, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"Unknown (or not implemented) YANG module \"x\" of metadata \"x:xxx\".", "/@a:foo", 1);
/* missing referenced metadata node */
PARSER_CHECK_ERROR("{\"@a:foo\" : { \"a:hint\" : 1 }}", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"Missing JSON data instance to be coupled with @a:foo metadata.", "/@a:foo", 1);
/* missing namespace for meatadata*/
PARSER_CHECK_ERROR("{\"a:foo\" : \"value\", \"@a:foo\" : { \"hint\" : 1 }}", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"Metadata in JSON must be namespace-qualified, missing prefix for \"hint\".", "/a:foo", 1);
/* invalid JSON type */
data = "{\"a:l1\" : [{ \"a\" : \"val-a\", \"b\" : \"val-b\", \"c\" : 1, \"cont\" : { \"e\" : \"0\" } }]}";
PARSER_CHECK_ERROR(data, 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"Invalid non-boolean-encoded boolean value \"0\".", "/a:l1[a='val-a'][b='val-b'][c='1']/cont/e", 1);
/* reverse solidus in JSON object member name */
data = "{\"@a:foo\":{\"a:hi\\nt\":1},\"a:foo\":\"xxx\"}";
assert_int_equal(LY_EINVAL, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
CHECK_LOG_CTX("Annotation definition for attribute \"a:hi\nt\" not found.", "/@a:foo/@a:hi\nt", 1);
data = "{\"a:foo\": null}";
PARSER_CHECK_ERROR(data, 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID, "Invalid non-string-encoded string value \"\".", "/a:foo", 1);
CHECK_PARSE_LYD(data, LYD_PARSE_JSON_NULL, LYD_VALIDATE_PRESENT, tree);
assert_null(tree);
}
static void
test_leaflist(void **state)
{
const char *data;
struct lyd_node *tree;
struct lyd_node_term *ll;
data = "{\"a:ll1\":[10,11]}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_ORDBY_SYSTEM, 1, "ll1",
1, LYS_LEAFLIST, 0, 0, NULL, 0);
ll = (struct lyd_node_term *)tree;
CHECK_LYD_VALUE(ll->value, UINT8, "10", 10);
assert_non_null(tree->next);
CHECK_LYSC_NODE(tree->next->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_ORDBY_SYSTEM, 1, "ll1",
1, LYS_LEAFLIST, 0, 0, NULL, 0);
ll = (struct lyd_node_term *)tree->next;
CHECK_LYD_VALUE(ll->value, UINT8, "11", 11);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
/* accept empty */
data = "{\"a:ll1\":[]}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_null(tree);
/* simple metadata */
data = "{\"a:ll1\":[10,11],\"@a:ll1\":[null,{\"a:hint\":2}]}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_ORDBY_SYSTEM, 1, "ll1",
1, LYS_LEAFLIST, 0, 0, NULL, 0);
ll = (struct lyd_node_term *)tree;
CHECK_LYD_VALUE(ll->value, UINT8, "10", 10);
assert_non_null(tree->next);
CHECK_LYSC_NODE(tree->next->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_ORDBY_SYSTEM, 1, "ll1",
1, LYS_LEAFLIST, 0, 0, NULL, 0);
ll = (struct lyd_node_term *)tree->next;
CHECK_LYD_VALUE(ll->value, UINT8, "11", 11);
CHECK_LYD_META(ll->meta, 1, "hint", 0, 1, INT8, "2", 2);
assert_null(ll->meta->next);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
/* multiple meatadata hint and unknown metadata xxx supposed to be skipped since it is from missing schema */
data = "{\"@a:ll1\" : [{\"a:hint\" : 1, \"x:xxx\" : { \"value\" : \"/x:no/x:yes\" }, "
"\"a:hint\" : 10},null,{\"a:hint\" : 3}], \"a:ll1\" : [1,2,3]}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_ORDBY_SYSTEM, 1, "ll1",
1, LYS_LEAFLIST, 0, 0, NULL, 0);
ll = (struct lyd_node_term *)tree;
CHECK_LYD_VALUE(ll->value, UINT8, "1", 1);
CHECK_LYD_META(ll->meta->next, 1, "hint", 1, 1, INT8, "1", 1);
CHECK_LYD_META(ll->meta->next->next, 1, "hint", 0, 1, INT8, "10", 10);
assert_non_null(tree->next);
CHECK_LYSC_NODE(tree->next->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_ORDBY_SYSTEM, 1, "ll1",
1, LYS_LEAFLIST, 0, 0, NULL, 0);
ll = (struct lyd_node_term *)tree->next;
CHECK_LYD_VALUE(ll->value, UINT8, "2", 2);
assert_null(ll->meta);
assert_non_null(tree->next->next);
CHECK_LYSC_NODE(tree->next->next->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_ORDBY_SYSTEM, 1, "ll1",
1, LYS_LEAFLIST, 0, 0, NULL, 0);
ll = (struct lyd_node_term *)tree->next->next;
CHECK_LYD_VALUE(ll->value, UINT8, "3", 3);
CHECK_LYD_META(ll->meta, 1, "hint", 0, 1, INT8, "3", 3);
assert_null(ll->meta->next);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS,
"{\"a:ll1\":[1,2,3],\"@a:ll1\":[{\"a:hint\":1,\"a:hint\":10},null,{\"a:hint\":3}]}");
lyd_free_all(tree);
/* missing referenced metadata node */
PARSER_CHECK_ERROR("{\"@a:ll1\":[{\"a:hint\":1}]}", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"Missing JSON data instance to be coupled with @a:ll1 metadata.", "/@a:ll1", 1);
PARSER_CHECK_ERROR("{\"a:ll1\":[1],\"@a:ll1\":[{\"a:hint\":1},{\"a:hint\":2}]}", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"Missing JSON data instance #2 of a:ll1 to be coupled with metadata.", "/a:ll1", 1);
PARSER_CHECK_ERROR("{\"@a:ll1\":[{\"a:hint\":1},{\"a:hint\":2},{\"a:hint\":3}],\"a:ll1\" : [1, 2]}", 0, LYD_VALIDATE_PRESENT,
tree, LY_EVALID, "Missing JSON data instance #3 to be coupled with @a:ll1 metadata.", "/@a:ll1", 1);
}
static void
test_anydata(void **state)
{
const char *data;
struct lyd_node *tree;
data = "{\"a:any\":{\"x:element1\":{\"element2\":\"/a:some/a:path\",\"list\":[{},{\"key\":\"a\"}]}}}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_R | LYS_SET_CONFIG, 1, "any",
1, LYS_ANYDATA, 0, 0, NULL, 0);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "{\"a:any\":{}}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_R | LYS_SET_CONFIG, 1, "any",
1, LYS_ANYDATA, 0, 0, NULL, 0);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "{\"a:any\":{\"node\":20}}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_R | LYS_SET_CONFIG, 1, "any",
1, LYS_ANYDATA, 0, 0, NULL, 0);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "{\"a:any\": null}";
PARSER_CHECK_ERROR(data, 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID, "Expecting JSON name/object but anydata \"any\" is represented in input data as name/null.", NULL, 1);
CHECK_PARSE_LYD(data, LYD_PARSE_JSON_NULL, LYD_VALIDATE_PRESENT, tree);
assert_null(tree);
}
static void
test_anyxml(void **state)
{
const char *data;
struct lyd_node *tree;
data = "{\"a:axml\":\"some-value in string\"}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "{\"a:axml\":\"\"}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "{\"a:axml\":55}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "{\"a:axml\":false}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "{\"a:axml\":null}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "{\"a:axml\":[null,true,false]}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "{\"a:axml\":[null,true,{\"name\":[25,40, false]}]}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
/* same as anydata tests */
data = "{\"a:axml\":{\"x:element1\":{\"element2\":\"/a:some/a:path\",\"list\":[{},{\"key\":\"a\"}]}}}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "{\"a:axml\":{}}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_W, 1, "axml", 1, LYS_ANYXML, 0, 0, NULL, 0);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
}
static void
test_list(void **state)
{
const char *data;
struct lyd_node *tree, *iter;
struct lyd_node_inner *list;
struct lyd_node_term *leaf;
/* check hashes */
data = "{\"a:l1\":[{\"a\":\"one\",\"b\":\"one\",\"c\":1}]}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_ORDBY_SYSTEM, 1, "l1",
1, LYS_LIST, 0, 0, NULL, 0);
list = (struct lyd_node_inner *)tree;
LY_LIST_FOR(list->child, iter) {
assert_int_not_equal(0, iter->hash);
}
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
/* accept empty */
data = "{\"a:l1\":[]}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_null(tree);
/* missing keys */
PARSER_CHECK_ERROR("{ \"a:l1\": [ {\"c\" : 1, \"b\" : \"b\"}]}", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"List instance is missing its key \"a\".", "/a:l1[b='b'][c='1']", 1);
PARSER_CHECK_ERROR("{ \"a:l1\": [ {\"a\" : \"a\"}]}", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"List instance is missing its key \"b\".", "/a:l1[a='a']", 1);
PARSER_CHECK_ERROR("{ \"a:l1\": [ {\"b\" : \"b\", \"a\" : \"a\"}]}", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"List instance is missing its key \"c\".", "/a:l1[a='a'][b='b']", 1);
/* key duplicate */
PARSER_CHECK_ERROR("{ \"a:l1\": [ {\"c\" : 1, \"b\" : \"b\", \"a\" : \"a\", \"c\" : 1}]}", 0, LYD_VALIDATE_PRESENT,
tree, LY_EVALID, "Duplicate instance of \"c\".", "/a:l1[a='a'][b='b'][c='1'][c='1']/c", 1);
/* keys order, in contrast to XML, JSON accepts keys in any order even in strict mode */
CHECK_PARSE_LYD("{ \"a:l1\": [ {\"d\" : \"d\", \"a\" : \"a\", \"c\" : 1, \"b\" : \"b\"}]}", 0, LYD_VALIDATE_PRESENT, tree);
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_ORDBY_SYSTEM, 1, "l1",
1, LYS_LIST, 0, 0, NULL, 0);
list = (struct lyd_node_inner *)tree;
assert_non_null(leaf = (struct lyd_node_term *)list->child);
CHECK_LYSC_NODE(leaf->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_KEY, 1, "a", 1, LYS_LEAF, 1, 0, NULL, 0);
assert_non_null(leaf = (struct lyd_node_term *)leaf->next);
CHECK_LYSC_NODE(leaf->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_KEY, 1, "b", 1, LYS_LEAF, 1, 0, NULL, 0);
assert_non_null(leaf = (struct lyd_node_term *)leaf->next);
CHECK_LYSC_NODE(leaf->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_KEY, 1, "c", 1, LYS_LEAF, 1, 0, NULL, 0);
assert_non_null(leaf = (struct lyd_node_term *)leaf->next);
CHECK_LYSC_NODE(leaf->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "d", 1, LYS_LEAF, 1, 0, NULL, 0);
CHECK_LOG_CTX(NULL, NULL, 0);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS,
"{\"a:l1\":[{\"a\":\"a\",\"b\":\"b\",\"c\":1,\"d\":\"d\"}]}");
lyd_free_all(tree);
CHECK_PARSE_LYD("{\"a:l1\":[{\"c\":1,\"b\":\"b\",\"a\":\"a\"}]}", LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, tree);
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_ORDBY_SYSTEM, 1, "l1",
1, LYS_LIST, 0, 0, NULL, 0);
list = (struct lyd_node_inner *)tree;
assert_non_null(leaf = (struct lyd_node_term *)list->child);
CHECK_LYSC_NODE(leaf->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_KEY, 1, "a",
1, LYS_LEAF, 1, 0, NULL, 0);
assert_non_null(leaf = (struct lyd_node_term *)leaf->next);
CHECK_LYSC_NODE(leaf->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_KEY, 1, "b",
1, LYS_LEAF, 1, 0, NULL, 0);
assert_non_null(leaf = (struct lyd_node_term *)leaf->next);
CHECK_LYSC_NODE(leaf->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_KEY, 1, "c",
1, LYS_LEAF, 1, 0, NULL, 0);
CHECK_LOG_CTX(NULL, NULL, 0);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS,
"{\"a:l1\":[{\"a\":\"a\",\"b\":\"b\",\"c\":1}]}");
lyd_free_all(tree);
/* skip unknown nested nodes */
data = "{\"a:l1\":[{\"a\":\"val_a\",\"b\":\"val_b\",\"c\":3,\"counters\":{\"count1\":\"c1\",\"count2\":\"c2\"}}]}";
CHECK_PARSE_LYD(data, LYD_PARSE_ONLY, 0, tree);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, "{\"a:l1\":[{\"a\":\"val_a\",\"b\":\"val_b\",\"c\":3}]}");
lyd_free_all(tree);
data = "{\"a:cp\":{\"@\":{\"a:hint\":1}}}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_PRESENCE, 1, "cp",
1, LYS_CONTAINER, 0, 0, NULL, 0);
CHECK_LYD_META(tree->meta, 1, "hint", 0, 1, INT8, "1", 1);
assert_null(tree->meta->next);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
}
static void
test_container(void **state)
{
const char *data;
struct lyd_node *tree;
struct lyd_node_inner *cont;
CHECK_PARSE_LYD("{\"a:c\":{}}", 0, LYD_VALIDATE_PRESENT, tree);
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "c",
1, LYS_CONTAINER, 0, 0, NULL, 0);
cont = (struct lyd_node_inner *)tree;
assert_true(cont->flags & LYD_DEFAULT);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, "{}");
lyd_free_all(tree);
data = "{\"a:cp\":{}}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_PRESENCE, 1, "cp",
1, LYS_CONTAINER, 0, 0, NULL, 0);
cont = (struct lyd_node_inner *)tree;
assert_false(cont->flags & LYD_DEFAULT);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
/* skip container */
CHECK_PARSE_LYD("{\"a:unknown\":{\"a\":\"val\",\"b\":5}}", 0, LYD_VALIDATE_PRESENT, tree);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, "{}");
lyd_free_all(tree);
data = "{\"a:c\": null}";
PARSER_CHECK_ERROR(data, 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID, "Expecting JSON name/object but container \"c\" is represented in input data as name/null.", NULL, 1);
CHECK_PARSE_LYD(data, LYD_PARSE_JSON_NULL, LYD_VALIDATE_PRESENT, tree);
assert_null(tree);
}
static void
test_opaq(void **state)
{
const char *data;
struct lyd_node *tree;
/* invalid value, no flags */
data = "{\"a:foo3\":[null]}";
PARSER_CHECK_ERROR(data, 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"Invalid non-number-encoded uint32 value \"\".", "/a:foo3", 1);
/* opaq flag */
CHECK_PARSE_LYD(data, LYD_PARSE_OPAQ | LYD_PARSE_ONLY, 0, tree);
CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 0, 0, LY_VALUE_JSON, "foo3", 0, 0, NULL, 0, "");
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
/* special chars */
data = "{\"a:foo3\":\"ab\\\"\\\\\\r\\t\"}";
CHECK_PARSE_LYD(data, LYD_PARSE_OPAQ | LYD_PARSE_ONLY, 0, tree);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
/* wrong encoding */
data = "{\"a:foo3\":\"25\"}";
CHECK_PARSE_LYD(data, LYD_PARSE_OPAQ | LYD_PARSE_ONLY, 0, tree);
CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 0, 0, LY_VALUE_JSON, "foo3", 0, 0, NULL, 0, "25");
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "{\"a:foo4\":25}";
CHECK_PARSE_LYD(data, LYD_PARSE_OPAQ | LYD_PARSE_ONLY, 0, tree);
CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 0, 0, LY_VALUE_JSON, "foo4", 0, 0, NULL, 0, "25");
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
/* missing key, no flags */
data = "{\"a:l1\":[{\"a\":\"val_a\",\"b\":\"val_b\",\"d\":\"val_d\"}]}";
PARSER_CHECK_ERROR(data, 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"List instance is missing its key \"c\".", "/a:l1[a='val_a'][b='val_b']", 1);
/* opaq flag */
CHECK_PARSE_LYD(data, LYD_PARSE_OPAQ | LYD_PARSE_ONLY, 0, tree);
CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 0, 0x1, LY_VALUE_JSON, "l1", 0, 0, NULL, 0, "");
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
/* invalid key, no flags */
data = "{\"a:l1\":[{\"a\":\"val_a\",\"b\":\"val_b\",\"c\":\"val_c\"}]}";
PARSER_CHECK_ERROR(data, 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"Invalid non-number-encoded int16 value \"val_c\".", "/a:l1[a='val_a'][b='val_b']/c", 1);
/* opaq flag */
CHECK_PARSE_LYD(data, LYD_PARSE_OPAQ | LYD_PARSE_ONLY, 0, tree);
CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 0, 0x1, LY_VALUE_JSON, "l1", 0, 0, NULL, 0, "");
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "{\"a:l1\":[{\"a\":\"val_a\",\"b\":\"val_b\",\"c\":{\"val\":\"val_c\"}}]}";
CHECK_PARSE_LYD(data, LYD_PARSE_OPAQ | LYD_PARSE_ONLY, 0, tree);
CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 0, 0x1, LY_VALUE_JSON, "l1", 0, 0, NULL, 0, "");
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "{\"a:l1\":[{\"a\":\"val_a\",\"b\":\"val_b\"}]}";
CHECK_PARSE_LYD(data, LYD_PARSE_OPAQ | LYD_PARSE_ONLY, 0, tree);
CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 0, 0x1, LY_VALUE_JSON, "l1", 0, 0, NULL, 0, "");
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
/* invalid metadata */
data = "{\"@a:foo\":\"str\",\"@a:foo3\":1,\"a:foo3\":2}";
PARSER_CHECK_ERROR(data, 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID, "Unknown module of node \"@a:foo\".", "/", 0);
CHECK_LOG_CTX("Missing JSON data instance to be coupled with @a:foo metadata.", "/@a:foo", 1);
/* empty name */
PARSER_CHECK_ERROR("{\"@a:foo\":{\"\":0}}", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"JSON object member name cannot be a zero-length string.", "/@a:foo", 1);
/* opaque data tree format print */
data =
"{\n"
" \"ietf-netconf-nmda:get-data\": {\n"
" \"data\": {\n"
" \"ietf-keystore:keystore\": {\n"
" \"asymmetric-keys\": {\n"
" \"asymmetric-key\": [\n"
" {\n"
" \"name\": \"genkey\",\n"
" \"algorithm\": \"rsa2048\"\n"
" }\n"
" ]\n"
" }\n"
" },\n"
" \"ietf-netconf-server:netconf-server\": {\n"
" \"listen\": {\n"
" \"idle-timeout\": 3600,\n"
" \"endpoint\": [\n"
" {\n"
" \"name\": \"default-ssh\",\n"
" \"ssh\": {\n"
" \"tcp-server-parameters\": {\n"
" \"local-address\": \"0.0.0.0\",\n"
" \"local-port\": 830\n"
" },\n"
" \"ssh-server-parameters\": {\n"
" \"server-identity\": {\n"
" \"host-key\": [\n"
" {\n"
" \"name\": \"default-key\",\n"
" \"public-key\": {\n"
" \"keystore-reference\": \"genkey\"\n"
" }\n"
" }\n"
" ]\n"
" },\n"
" \"client-authentication\": {\n"
" \"supported-authentication-methods\": {\n"
" \"publickey\": [null],\n"
" \"passsword\": [null],\n"
" \"other\": [\n"
" \"interactive\",\n"
" \"gssapi\"\n"
" ]\n"
" }\n"
" }\n"
" }\n"
" }\n"
" }\n"
" ]\n"
" }\n"
" }\n"
" }\n"
" }\n"
"}\n";
CHECK_PARSE_LYD(data, LYD_PARSE_OPAQ | LYD_PARSE_ONLY, 0, tree);
CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
}
static void
test_rpc(void **state)
{
const char *data;
char *str;
struct ly_in *in;
struct lyd_node *tree, *op;
const struct lyd_node *node;
const char *dsc = "Edit data in an NMDA datastore.\n"
"\n"
"If an error condition occurs such that an error severity\n"
"<rpc-error> element is generated, the server will stop\n"
"processing the <edit-data> operation and restore the\n"
"specified configuration to its complete state at\n"
"the start of this <edit-data> operation.";
assert_non_null((ly_ctx_load_module(UTEST_LYCTX, "ietf-netconf-nmda", "2019-01-07", NULL)));
data = "{\"ietf-netconf-nmda:edit-data\":{"
"\"datastore\":\"ietf-datastores:running\","
"\"config\":{\"a:cp\":{\"z\":[null],\"@z\":{\"ietf-netconf:operation\":\"replace\"}},"
"\"a:l1\":[{\"@\":{\"ietf-netconf:operation\":\"replace\"},\"a\":\"val_a\",\"b\":\"val_b\",\"c\":\"val_c\"}]}"
"}}";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_JSON, LYD_TYPE_RPC_YANG, &tree, &op));
ly_in_free(in, 0);
assert_non_null(op);
CHECK_LYSC_ACTION((struct lysc_node_action *)op->schema, dsc, 0, LYS_STATUS_CURR,
1, 0, 0, 1, "edit-data", LYS_RPC,
0, 0, 0, 0, 0, NULL, 0);
node = tree;
CHECK_LYSC_ACTION((struct lysc_node_action *)node->schema, dsc, 0, LYS_STATUS_CURR,
1, 0, 0, 1, "edit-data", LYS_RPC,
0, 0, 0, 0, 0, NULL, 0);
node = lyd_child(node)->next;
CHECK_LYSC_NODE(node->schema, "Inline config content.", 0, LYS_STATUS_CURR | LYS_IS_INPUT, 1, "config",
0, LYS_ANYDATA, 1, 0, NULL, 0);
node = ((struct lyd_node_any *)node)->value.tree;
CHECK_LYSC_NODE(node->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_PRESENCE, 1, "cp",
1, LYS_CONTAINER, 0, 0, NULL, 0);
node = lyd_child(node);
/* z has no value */
CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)node, 0x1, 0, LY_VALUE_JSON, "z", 0, 0, NULL, 0, "");
node = node->parent->next;
/* l1 key c has invalid value so it is at the end */
CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)node, 0x1, 0x1, LY_VALUE_JSON, "l1", 0, 0, NULL, 0, "");
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
/* append to parent */
assert_int_equal(LY_SUCCESS, lyd_new_path(NULL, UTEST_LYCTX, "/a:r1", NULL, 0, &op));
assert_int_equal(LY_SUCCESS, ly_in_new_memory("{\"l1\": \"some str\", \"l2\": \"some other str\"}", &in));
assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, op, in, LYD_JSON, LYD_TYPE_RPC_YANG, &tree, NULL));
ly_in_free(in, 0);
assert_int_equal(LY_SUCCESS, lyd_print_mem(&str, op, LYD_JSON, LYD_PRINT_WITHSIBLINGS | LYD_PRINT_SHRINK));
lyd_free_tree(op);
assert_string_equal(str, "{\"a:r1\":{\"l1\":\"some str\",\"l2\":\"some other str\"}}");
free(str);
}
static void
test_action(void **state)
{
const char *data;
struct ly_in *in;
struct lyd_node *tree, *op;
data = "{\"a:c\":{\"act\":{\"al\":\"value\"}}}";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_JSON, LYD_TYPE_RPC_YANG, &tree, &op));
ly_in_free(in, 0);
assert_non_null(op);
CHECK_LYSC_ACTION((struct lysc_node_action *)op->schema, NULL, 0, LYS_STATUS_CURR,
1, 0, 0, 1, "act", LYS_ACTION,
1, 0, 0, 1, 0, NULL, 0);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
/* wrong namespace, element name, whatever... */
/* TODO */
}
static void
test_notification(void **state)
{
const char *data;
struct ly_in *in;
struct lyd_node *tree, *ntf;
data = "{\"a:c\":{\"n1\":{\"nl\":\"value\"}}}";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_JSON, LYD_TYPE_NOTIF_YANG, &tree, &ntf));
ly_in_free(in, 0);
assert_non_null(ntf);
CHECK_LYSC_NOTIF((struct lysc_node_notif *)ntf->schema, 1, NULL, 0, 0x4, 1, 0, "n1", 1, 0, NULL, 0);
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "c", 1, LYS_CONTAINER, 0, 0, NULL, 0);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "{\"a:n2\":{}}";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_JSON, LYD_TYPE_NOTIF_YANG, &tree, &ntf));
ly_in_free(in, 0);
assert_non_null(ntf);
CHECK_LYSC_NOTIF((struct lysc_node_notif *)ntf->schema, 0, NULL, 0, 0x4, 1, 0, "n2", 0, 0, NULL, 0);
assert_non_null(tree);
assert_ptr_equal(ntf, tree);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
/* wrong namespace, element name, whatever... */
/* TODO */
}
static void
test_reply(void **state)
{
const char *data;
struct ly_in *in;
struct lyd_node *tree, *op;
const struct lyd_node *node;
data = "{\"a:c\":{\"act\":{\"al\":25}}}";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_JSON, LYD_TYPE_REPLY_YANG, &tree, &op));
ly_in_free(in, 0);
assert_non_null(op);
CHECK_LYSC_ACTION((struct lysc_node_action *)op->schema, NULL, 0, LYS_STATUS_CURR,
1, 0, 0, 1, "act", LYS_ACTION,
1, 0, 0, 1, 0, NULL, 0);
node = lyd_child(op);
CHECK_LYSC_NODE(node->schema, NULL, 0, LYS_STATUS_CURR | LYS_IS_OUTPUT, 1, "al", 0, LYS_LEAF, 1, 0, NULL, 0);
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "c", 1, LYS_CONTAINER, 0, 0, NULL, 0);
/* TODO print only rpc-reply node and then output subtree */
CHECK_LYD_STRING(lyd_child(op), LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, "{\"a:al\":25}");
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, "{\"a:c\":{\"act\":{\"al\":25}}}");
lyd_free_all(tree);
/* wrong namespace, element name, whatever... */
/* TODO */
}
static void
test_restconf_rpc(void **state)
{
const char *data;
struct ly_in *in;
struct lyd_node *tree, *envp;
assert_non_null((ly_ctx_load_module(UTEST_LYCTX, "ietf-netconf-nmda", "2019-01-07", NULL)));
assert_int_equal(LY_SUCCESS, lyd_new_path(NULL, UTEST_LYCTX, "/ietf-netconf-nmda:edit-data", NULL, 0, &tree));
data = "{\"ietf-netconf-nmda:input\":{"
"\"datastore\":\"ietf-datastores:running\","
"\"config\":{\"a:cp\":{\"z\":[null],\"@z\":{\"ietf-netconf:operation\":\"replace\"}},"
"\"a:l1\":[{\"@\":{\"ietf-netconf:operation\":\"replace\"},\"a\":\"val_a\",\"b\":\"val_b\",\"c\":\"val_c\"}]}"
"}}";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, tree, in, LYD_JSON, LYD_TYPE_RPC_RESTCONF, &envp, NULL));
ly_in_free(in, 0);
/* the same just connected to the edit-data RPC */
data = "{\"ietf-netconf-nmda:edit-data\":{"
"\"datastore\":\"ietf-datastores:running\","
"\"config\":{\"a:cp\":{\"z\":[null],\"@z\":{\"ietf-netconf:operation\":\"replace\"}},"
"\"a:l1\":[{\"@\":{\"ietf-netconf:operation\":\"replace\"},\"a\":\"val_a\",\"b\":\"val_b\",\"c\":\"val_c\"}]}"
"}}";
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
lyd_free_all(envp);
}
static void
test_restconf_notification(void **state)
{
const char *data;
struct ly_in *in;
struct lyd_node *tree, *ntf;
data = "{\"ietf-restconf:notification\":{\"eventTime\":\"2013-12-21T00:01:00Z\",\"a:c\":{\"n1\":{\"nl\":\"value\"}}}}";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_JSON, LYD_TYPE_NOTIF_RESTCONF, &tree, &ntf));
ly_in_free(in, 0);
/* envelopes separately */
data = "{\"ietf-restconf:notification\":{\"eventTime\":\"2013-12-21T00:01:00Z\"}}";
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
/* notification with the parent node */
data = "{\"a:c\":{\"n1\":{\"nl\":\"value\"}}}";
CHECK_LYD_STRING(lyd_parent(ntf), LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
lyd_free_all(ntf);
/* wrong order */
data = "{\"ietf-restconf:notification\":{\"a:n2\":{},\"eventTime\":\"2013-12-21T00:01:00Z\"}}";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_JSON, LYD_TYPE_NOTIF_RESTCONF, &tree, &ntf));
ly_in_free(in, 0);
lyd_free_all(tree);
lyd_free_all(ntf);
/* unknown notification */
data = "{\"ietf-restconf:notification\":{\"eventTime\":\"2013-12-21T00:01:00Z\",\"invalid:n2\":{}}}";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
assert_int_equal(LY_EVALID, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_JSON, LYD_TYPE_NOTIF_RESTCONF, &tree, &ntf));
UTEST_LOG_CTX_CLEAN;
ly_in_free(in, 0);
lyd_free_all(tree);
}
static void
test_restconf_reply(void **state)
{
const char *data;
struct ly_in *in;
struct lyd_node *tree, *envp;
assert_int_equal(LY_SUCCESS, lyd_new_path(NULL, UTEST_LYCTX, "/a:c/act", NULL, 0, &tree));
data = "{\"a:output\":{\"al\":25}}";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, lyd_child(tree), in, LYD_JSON, LYD_TYPE_REPLY_RESTCONF, &envp, NULL));
ly_in_free(in, 0);
/* connected to the RPC with the parent */
data = "{\"a:c\":{\"act\":{\"al\":25}}}";
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
lyd_free_all(envp);
}
static void
test_metadata(void **state)
{
const char *data;
struct lyd_node *tree;
/* invalid metadata value */
data = "{\"a:c\":{\"x\":\"xval\",\"@x\":{\"a:hint\":\"value\"}}}";
assert_int_equal(LY_EVALID, lyd_parse_data_mem(_UC->ctx, data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
assert_null(tree);
CHECK_LOG_CTX("Invalid non-number-encoded int8 value \"value\".", "/a:c/x/@a:hint", 1);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_leaf, setup),
UTEST(test_leaflist, setup),
UTEST(test_anydata, setup),
UTEST(test_anyxml, setup),
UTEST(test_list, setup),
UTEST(test_container, setup),
UTEST(test_opaq, setup),
UTEST(test_rpc, setup),
UTEST(test_action, setup),
UTEST(test_notification, setup),
UTEST(test_reply, setup),
UTEST(test_restconf_rpc, setup),
UTEST(test_restconf_notification, setup),
UTEST(test_restconf_reply, setup),
UTEST(test_metadata, setup),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,83 @@
/**
* @file test_printer_json.c
* @author: Radek Krejci <rkrejci@cesnet.cz>
* @brief unit tests for functions from printer_yang.c
*
* Copyright (c) 2019-2020 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"
static int
setup(void **state)
{
const char *schema1 = "module schema1 {namespace urn:tests:schema1;prefix schema1;yang-version 1.1;"
"revision 2014-05-08;"
"anydata data;"
"}";
const char *schema2 = "module schema2 {namespace urn:tests:schema2;prefix s2;yang-version 1.1;"
" container a {"
" container b {"
" leaf c {"
" type string;"
" default \"dflt\";"
" }"
" }"
" }"
"}";
UTEST_SETUP;
UTEST_ADD_MODULE(schema1, LYS_IN_YANG, NULL, NULL);
UTEST_ADD_MODULE(schema2, LYS_IN_YANG, NULL, NULL);
return 0;
}
static void
test_container_presence(void **state)
{
struct lyd_node *tree;
char *buffer = NULL;
const char *data = "{\"schema1:data\":{\"cont1\":{}}}";
CHECK_PARSE_LYD_PARAM(data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
assert_int_equal(LY_SUCCESS, lyd_print_mem(&buffer, tree, LYD_JSON, LYD_PRINT_SHRINK));
CHECK_STRING(buffer, data);
free(buffer);
lyd_free_all(tree);
}
static void
test_empty_container_wd_trim(void **state)
{
struct lyd_node *tree;
char *buffer = NULL;
const char *data = "{\"schema2:a\":{\"b\":{\"c\":\"dflt\"}}}";
CHECK_PARSE_LYD_PARAM(data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
assert_int_equal(LY_SUCCESS, lyd_print_mem(&buffer, tree, LYD_JSON, LYD_PRINT_SHRINK | LYD_PRINT_WD_TRIM));
CHECK_STRING(buffer, "{}");
free(buffer);
assert_int_equal(LY_SUCCESS, lyd_print_mem(&buffer, tree, LYD_JSON, LYD_PRINT_SHRINK | LYD_PRINT_WD_TRIM | LYD_PRINT_KEEPEMPTYCONT));
CHECK_STRING(buffer, "{\"schema2:a\":{\"b\":{}}}");
free(buffer);
lyd_free_all(tree);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_container_presence, setup),
UTEST(test_empty_container_wd_trim, setup),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

View file

@ -0,0 +1,344 @@
/*
* @file test_printer_xml.c
* @author: Radek Krejci <rkrejci@cesnet.cz>
* @brief unit tests for functions from printer_yang.c
*
* Copyright (c) 2019-2020 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 <string.h>
#include "context.h"
#include "out.h"
#include "parser_data.h"
#include "printer_data.h"
#include "tests_config.h"
#include "tree_schema.h"
static int
setup(void **state)
{
const char *schema_defs = "module defs {namespace urn:tests:defs;prefix d;yang-version 1.1;"
"identity crypto-alg; identity interface-type; identity ethernet {base interface-type;} identity fast-ethernet {base ethernet;}}";
const char *schema_types = "module types {namespace urn:tests:types;prefix t;yang-version 1.1; import defs {prefix defs;}"
"feature f; identity gigabit-ethernet { base defs:ethernet;}"
"container cont {leaf leaftarget {type empty;}"
" list listtarget {key id; max-elements 5;leaf id {type uint8;} leaf value {type string;}"
" action test {input {leaf a {type string;}} output {leaf b {type string;}}}}"
" leaf-list leaflisttarget {type uint8; max-elements 5;}}"
"list list {key id; leaf id {type string;} leaf value {type string;} leaf-list targets {type string;}}"
"list list2 {key \"id value\"; leaf id {type string;} leaf value {type string;}}"
"list list_inst {key id; leaf id {type instance-identifier {require-instance true;}} leaf value {type string;}}"
"list list_ident {key id; leaf id {type identityref {base defs:interface-type;}} leaf value {type string;}}"
"leaf-list leaflisttarget {type string;}"
"leaf binary {type binary {length 5 {error-message \"This base64 value must be of length 5.\";}}}"
"leaf binary-norestr {type binary;}"
"leaf int8 {type int8 {range 10..20;}}"
"leaf uint8 {type uint8 {range 150..200;}}"
"leaf int16 {type int16 {range -20..-10;}}"
"leaf uint16 {type uint16 {range 150..200;}}"
"leaf int32 {type int32;}"
"leaf uint32 {type uint32;}"
"leaf int64 {type int64;}"
"leaf uint64 {type uint64;}"
"leaf bits {type bits {bit zero; bit one {if-feature f;} bit two;}}"
"leaf enums {type enumeration {enum white; enum yellow {if-feature f;}}}"
"leaf dec64 {type decimal64 {fraction-digits 1; range 1.5..10;}}"
"leaf dec64-norestr {type decimal64 {fraction-digits 18;}}"
"leaf str {type string {length 8..10; pattern '[a-z ]*';}}"
"leaf str-norestr {type string;}"
"leaf bool {type boolean;}"
"leaf empty {type empty;}"
"leaf ident {type identityref {base defs:interface-type;}}"
"leaf inst {type instance-identifier {require-instance true;}}"
"leaf inst-noreq {type instance-identifier {require-instance false;}}"
"leaf lref {type leafref {path /leaflisttarget; require-instance true;}}"
"leaf lref2 {type leafref {path \"../list[id = current()/../str-norestr]/targets\"; require-instance true;}}"
"leaf un1 {type union {"
" type leafref {path /int8; require-instance true;}"
" type union { type identityref {base defs:interface-type;} type instance-identifier {require-instance true;} }"
" type string {length 1..20;}}}"
"anydata any;"
"rpc sum {input {leaf x {type uint8;} leaf y {type uint8;}} output {leaf result {type uint16;}}}}";
const char *schema_defaults =
"module defaults {\n"
" namespace \"urn:defaults\";\n"
" prefix d;\n"
" leaf a {\n"
" type union {\n"
" type instance-identifier;\n"
" type string;\n"
" }\n"
" default \"/d:b\";\n"
" }\n"
" leaf b {\n"
" type string;\n"
" }\n"
" leaf c {\n"
" type string;\n"
" }\n"
"}";
UTEST_SETUP;
UTEST_ADD_MODULE(schema_defs, LYS_IN_YANG, NULL, NULL);
UTEST_ADD_MODULE(schema_types, LYS_IN_YANG, NULL, NULL);
UTEST_ADD_MODULE(schema_defaults, LYS_IN_YANG, NULL, NULL);
return 0;
}
#define CHECK_PARSE_LYD(INPUT, PARSE_OPTION, VALIDATE_OPTION, TREE) \
CHECK_PARSE_LYD_PARAM(INPUT, LYD_XML, PARSE_OPTION, VALIDATE_OPTION, LY_SUCCESS, TREE)
#define CHECK_LYD_STRING(IN_MODEL, PRINT_OPTION, TEXT) \
CHECK_LYD_STRING_PARAM(IN_MODEL, TEXT, LYD_XML, PRINT_OPTION)
static void
test_anydata(void **state)
{
struct lyd_node *tree;
const char *data;
data = "<any xmlns=\"urn:tests:types\"><somexml xmlns:x=\"url:x\" xmlns=\"example.com\"><x:x/></somexml></any>";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
/* canonized */
data = "<any xmlns=\"urn:tests:types\"><somexml xmlns=\"example.com\"><x xmlns=\"url:x\"/></somexml></any>";
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "<any xmlns=\"urn:tests:types\"/>";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "<any xmlns=\"urn:tests:types\">\n"
" <cont>\n"
" <defs:elem1 xmlns:defs=\"urn:tests:defs\">\n"
" <elem2 xmlns:defaults=\"urn:defaults\" defs:attr1=\"defaults:val\" attr2=\"/defaults:node/defs:node2\">\n"
" </elem2>\n"
" </defs:elem1>\n"
" </cont>\n"
"</any>\n";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
/* cont should be normally parsed */
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "any", 0, LYS_ANYDATA, 0, 0, NULL, 0);
CHECK_LYD_NODE_ANY((struct lyd_node_any *)tree, 0, 0, 0, LYD_ANYDATA_DATATREE);
struct lyd_node *tree_tmp = ((struct lyd_node_any *)tree)->value.tree;
CHECK_LYSC_NODE(tree_tmp->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR, 1, "cont", 1, LYS_CONTAINER, 0, 0, NULL, 0);
/* but its children not */
assert_null(((struct lyd_node_inner *)tree_tmp)->child->schema);
/* canonized */
data =
"<any xmlns=\"urn:tests:types\">\n"
" <cont>\n"
" <elem1 xmlns=\"urn:tests:defs\">\n"
" <elem2 xmlns=\"urn:tests:types\" xmlns:defs=\"urn:tests:defs\" xmlns:defaults=\"urn:defaults\" "
"defs:attr1=\"defaults:val\" attr2=\"/defaults:node/defs:node2\">\n"
" </elem2>\n"
" </elem1>\n"
" </cont>\n"
"</any>\n";
CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "<any xmlns=\"urn:tests:types\">\n"
" <ahoj attr=\"&lt;test\">\n"
" ahoj jak se vede &lt; how are you"
" </ahoj>\n"
"</any>\n";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "<any xmlns=\"urn:tests:types\">\n"
" <leaflisttarget> ahoj </leaflisttarget>\n"
" <leaflisttarget> nazdar </leaflisttarget>\n"
" <leaflisttarget> Čau </leaflisttarget>\n"
"</any>\n";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "<any xmlns=\"urn:tests:types\">\n"
" <cont2/>\n"
"</any>\n";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
data = "<any xmlns=\"urn:tests:types\">\n"
" <cont>\n"
" &lt; how are you"
" </cont>\n"
"</any>\n";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
}
static void
test_defaults(void **state)
{
struct lyd_node *tree;
const char *data;
const char *data_trim;
const char *data_all;
const char *data_all_tag;
const char *data_impl_tag;
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-netconf-with-defaults", "2011-06-01", NULL));
/* standard default value */
data = "<c xmlns=\"urn:defaults\">aa</c>";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
CHECK_LYD_STRING(tree, LYD_PRINT_WD_TRIM | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
data = "<a xmlns=\"urn:defaults\" xmlns:d=\"urn:defaults\">/d:b</a><c xmlns=\"urn:defaults\">aa</c>";
CHECK_LYD_STRING(tree, LYD_PRINT_WD_ALL | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
data = "<a xmlns=\"urn:defaults\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\""
" ncwd:default=\"true\" xmlns:d=\"urn:defaults\">/d:b</a>"
"<c xmlns=\"urn:defaults\">aa</c>";
CHECK_LYD_STRING(tree, LYD_PRINT_WD_ALL_TAG | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
data = "<a xmlns=\"urn:defaults\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\""
" ncwd:default=\"true\" xmlns:d=\"urn:defaults\">/d:b</a>"
"<c xmlns=\"urn:defaults\">aa</c>";
CHECK_LYD_STRING(tree, LYD_PRINT_WD_IMPL_TAG | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
/* string value equal to the default but default is an unresolved instance-identifier, so they are not considered equal */
data = "<a xmlns=\"urn:defaults\">/d:b</a><c xmlns=\"urn:defaults\">aa</c>";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
CHECK_LYD_STRING(tree, LYD_PRINT_WD_TRIM | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
CHECK_LYD_STRING(tree, LYD_PRINT_WD_ALL | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
CHECK_LYD_STRING(tree, LYD_PRINT_WD_ALL_TAG | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
CHECK_LYD_STRING(tree, LYD_PRINT_WD_IMPL_TAG | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);
/* instance-identifier value equal to the default, should be considered equal */
data = "<a xmlns=\"urn:defaults\" xmlns:d=\"urn:defaults\">/d:b</a><b xmlns=\"urn:defaults\">val</b><c xmlns=\"urn:defaults\">aa</c>";
data_trim = "<b xmlns=\"urn:defaults\">val</b><c xmlns=\"urn:defaults\">aa</c>";
data_all = "<a xmlns=\"urn:defaults\" xmlns:d=\"urn:defaults\">/d:b</a><b xmlns=\"urn:defaults\">val</b><c xmlns=\"urn:defaults\">aa</c>";
data_all_tag = "<a xmlns=\"urn:defaults\" xmlns:ncwd=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\""
" ncwd:default=\"true\" xmlns:d=\"urn:defaults\">/d:b</a>"
"<b xmlns=\"urn:defaults\">val</b>"
"<c xmlns=\"urn:defaults\">aa</c>";
data_impl_tag = "<a xmlns=\"urn:defaults\" xmlns:d=\"urn:defaults\">/d:b</a><b xmlns=\"urn:defaults\">val</b><c xmlns=\"urn:defaults\">aa</c>";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
CHECK_LYD_STRING(tree, LYD_PRINT_WD_TRIM | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data_trim);
CHECK_LYD_STRING(tree, LYD_PRINT_WD_ALL | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data_all);
CHECK_LYD_STRING(tree, LYD_PRINT_WD_ALL_TAG | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data_all_tag);
CHECK_LYD_STRING(tree, LYD_PRINT_WD_IMPL_TAG | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data_impl_tag);
lyd_free_all(tree);
}
#if 0
static void
test_rpc(void **state)
{
struct state_s *s = (struct state_s *)(*state);
struct lyd_node *tree1;
struct lyd_node *tree2;
const struct lyd_node **trees;
const char *request;
const char *reply, *result;
char *printed;
ssize_t len;
struct ly_out *out;
s->func = test_rpc;
assert_non_null(out = ly_out_new_memory(&printed, 0));
request = "<sum xmlns=\"urn:tests:types\"><x>10</x><y>20</y></sum>";
reply = "<result xmlns=\"urn:tests:types\">30</result>";
result = "<sum xmlns=\"urn:tests:types\"><result>30</result></sum>";
assert_non_null(tree1 = lyd_parse_mem(s->ctx, request, LYD_XML, LYD_OPT_RPC, NULL));
assert_true((len = lyd_print_tree(out, tree1, LYD_XML, LYD_PRINT_SHRINK)) >= 0);
assert_int_equal(len, strlen(printed));
assert_string_equal(printed, request);
ly_out_reset(out);
assert_non_null(trees = lyd_trees_new(1, tree1));
assert_non_null(tree2 = lyd_parse_mem(s->ctx, reply, LYD_XML, LYD_OPT_RPCREPLY, trees));
assert_true((len = lyd_print_tree(out, tree2, LYD_XML, LYD_PRINT_SHRINK)) >= 0);
assert_int_equal(len, strlen(printed));
assert_string_equal(printed, result);
ly_out_reset(out);
lyd_trees_free(trees, 0);
lyd_free_all(tree1);
lyd_free_all(tree2);
/* no arguments */
request = "<sum xmlns=\"urn:tests:types\"/>";
reply = "";
result = "<sum xmlns=\"urn:tests:types\"/>";
assert_non_null(tree1 = lyd_parse_mem(s->ctx, request, LYD_XML, LYD_OPT_RPC, NULL));
assert_true((len = lyd_print_tree(out, tree1, LYD_XML, LYD_PRINT_SHRINK)) >= 0);
assert_int_equal(len, strlen(printed));
assert_string_equal(printed, request);
ly_out_reset(out);
assert_non_null(trees = lyd_trees_new(1, tree1));
assert_non_null(tree2 = lyd_parse_mem(s->ctx, reply, LYD_XML, LYD_OPT_RPCREPLY, trees));
assert_true((len = lyd_print_tree(out, tree2, LYD_XML, LYD_PRINT_SHRINK)) >= 0);
assert_int_equal(len, strlen(printed));
assert_string_equal(printed, result);
ly_out_reset(out);
lyd_trees_free(trees, 0);
lyd_free_all(tree1);
lyd_free_all(tree2);
/* action
* "container cont {leaf leaftarget {type empty;}"
"list listtarget {key id; max-elements 5;leaf id {type uint8;} leaf value {type string;}"
"action test {input {leaf a {type string;}} output {leaf b {type string;}}}}"
"leaf-list leaflisttarget {type uint8; max-elements 5;}}"
*/
request = "<cont xmlns=\"urn:tests:types\"><listtarget><id>10</id><test><a>test</a></test></listtarget></cont>";
reply = "<b xmlns=\"urn:tests:types\">test-reply</b>";
result = "<cont xmlns=\"urn:tests:types\"><listtarget><id>10</id><test><b>test-reply</b></test></listtarget></cont>";
assert_non_null(tree1 = lyd_parse_mem(s->ctx, request, LYD_XML, LYD_OPT_RPC, NULL));
assert_true((len = lyd_print_tree(out, tree1, LYD_XML, LYD_PRINT_SHRINK)) >= 0);
assert_int_equal(len, strlen(printed));
assert_string_equal(printed, request);
ly_out_reset(out);
assert_non_null(trees = lyd_trees_new(1, tree1));
assert_non_null(tree2 = lyd_parse_mem(s->ctx, reply, LYD_XML, LYD_OPT_RPCREPLY, trees));
assert_true((len = lyd_print_tree(out, tree2, LYD_XML, LYD_PRINT_SHRINK)) >= 0);
assert_int_equal(len, strlen(printed));
assert_string_equal(printed, result);
ly_out_reset(out);
lyd_trees_free(trees, 0);
lyd_free_all(tree1);
lyd_free_all(tree2);
ly_out_free(out, NULL, 1);
s->func = NULL;
}
#endif
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_anydata, setup),
UTEST(test_defaults, setup),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

View file

@ -0,0 +1,822 @@
/**
* @file test_tree_data.c
* @author Radek Krejci <rkrejci@cesnet.cz>
* @brief unit tests for functions from tree_data.c
*
* Copyright (c) 2018-2023 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 "libyang.h"
#include "ly_common.h"
#include "path.h"
#include "xpath.h"
static int
setup(void **state)
{
const char *schema1 = "module a {namespace urn:tests:a;prefix a;yang-version 1.1;"
"revision 2014-05-08;"
"leaf bar {type string;}"
"list l1 { key \"a b\"; leaf a {type string;} leaf b {type string;} leaf c {type string;}}"
"leaf foo { type string;}"
"leaf-list ll { type string;}"
"container c {leaf-list x {type string;}}"
"anydata any {config false;}"
"list l2 {config false;"
" container c{leaf x {type string;} leaf-list d {type string;}}"
"}}";
const char *schema2 = "module b {namespace urn:tests:b;prefix b;yang-version 1.1;"
"revision 2014-05-08;"
"list l2 {config false;"
" container c{leaf x {type string;}}}"
"anydata any {config false;}"
"}";
const char *schema3 = "module c {yang-version 1.1; namespace \"http://example.com/main\";prefix m;"
"import \"ietf-inet-types\" {prefix inet;}"
"typedef optional-ip-address {type union {"
" type inet:ip-address;"
" type string;"
"}}"
"container cont {"
" list nexthop {min-elements 1; key \"gateway\";"
" leaf gateway {type optional-ip-address;}"
" }"
" leaf-list pref {type inet:ipv6-prefix;}"
"}}";
UTEST_SETUP;
UTEST_ADD_MODULE(schema1, LYS_IN_YANG, NULL, NULL);
UTEST_ADD_MODULE(schema2, LYS_IN_YANG, NULL, NULL);
UTEST_ADD_MODULE(schema3, LYS_IN_YANG, NULL, NULL);
return 0;
}
#define CHECK_PARSE_LYD(INPUT, PARSE_OPTION, VALIDATE_OPTION, TREE) \
CHECK_PARSE_LYD_PARAM(INPUT, LYD_XML, PARSE_OPTION, VALIDATE_OPTION, LY_SUCCESS, TREE)
#define CHECK_PARSE_LYD_PARAM_CTX(CTX, INPUT, PARSE_OPTION, OUT_NODE) \
assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(CTX, INPUT, LYD_XML, PARSE_OPTION, LYD_VALIDATE_PRESENT, &OUT_NODE)); \
assert_non_null(OUT_NODE);
#define RECREATE_CTX_WITH_MODULE(CTX, MODULE) \
ly_ctx_destroy(CTX); \
assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &CTX)); \
assert_int_equal(LY_SUCCESS, ly_in_new_memory(MODULE, &_UC->in)); \
assert_int_equal(LY_SUCCESS, lys_parse(CTX, _UC->in, LYS_IN_YANG, NULL, NULL)); \
ly_in_free(_UC->in, 0);
static void
test_compare(void **state)
{
struct lyd_node *tree1, *tree2;
const char *data1;
const char *data2;
assert_int_equal(LY_SUCCESS, lyd_compare_single(NULL, NULL, 0));
data1 = "<l1 xmlns=\"urn:tests:a\"><a>a</a><b>b</b><c>x</c></l1>";
data2 = "<l1 xmlns=\"urn:tests:a\"><a>a</a><b>b</b><c>y</c></l1>";
CHECK_PARSE_LYD(data1, 0, LYD_VALIDATE_PRESENT, tree1);
CHECK_PARSE_LYD(data2, 0, LYD_VALIDATE_PRESENT, tree2);
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, 0));
assert_int_equal(LY_ENOT, lyd_compare_single(tree1, tree2, LYD_COMPARE_FULL_RECURSION));
assert_int_equal(LY_ENOT, lyd_compare_single(((struct lyd_node_inner *)tree1)->child, tree2, 0));
lyd_free_all(tree1);
lyd_free_all(tree2);
data1 = "<l2 xmlns=\"urn:tests:a\"><c><x>a</x></c></l2><l2 xmlns=\"urn:tests:a\"><c><x>b</x></c></l2>";
data2 = "<l2 xmlns=\"urn:tests:a\"><c><x>b</x></c></l2>";
CHECK_PARSE_LYD(data1, 0, LYD_VALIDATE_PRESENT, tree1);
CHECK_PARSE_LYD(data2, 0, LYD_VALIDATE_PRESENT, tree2);
assert_int_equal(LY_ENOT, lyd_compare_single(tree1->next, tree2->next, LYD_COMPARE_FULL_RECURSION));
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1->next->next, tree2->next, 0));
lyd_free_all(tree1);
lyd_free_all(tree2);
data1 = "<ll xmlns=\"urn:tests:a\">a</ll><ll xmlns=\"urn:tests:a\">b</ll>";
data2 = "<ll xmlns=\"urn:tests:a\">b</ll>";
CHECK_PARSE_LYD(data1, 0, LYD_VALIDATE_PRESENT, tree1);
CHECK_PARSE_LYD(data2, 0, LYD_VALIDATE_PRESENT, tree2);
assert_int_equal(LY_ENOT, lyd_compare_single(tree1, tree2, 0));
assert_int_equal(LY_ENOT, lyd_compare_single(NULL, tree2, 0));
assert_int_equal(LY_ENOT, lyd_compare_single(tree1, NULL, 0));
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1->next, tree2, 0));
lyd_free_all(tree1);
lyd_free_all(tree2);
data1 = "<c xmlns=\"urn:tests:a\"><x>x</x></c>";
data2 = "<c xmlns=\"urn:tests:a\"><x>y</x></c>";
CHECK_PARSE_LYD(data1, 0, LYD_VALIDATE_PRESENT, tree1);
CHECK_PARSE_LYD(data2, 0, LYD_VALIDATE_PRESENT, tree2);
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, 0));
assert_int_equal(LY_ENOT, lyd_compare_single(tree1, tree2, LYD_COMPARE_FULL_RECURSION));
lyd_free_all(tree1);
lyd_free_all(tree2);
data1 = "<c xmlns=\"urn:tests:a\"><x>x</x></c>";
data2 = "<c xmlns=\"urn:tests:a\"><x>x</x><x>y</x></c>";
CHECK_PARSE_LYD(data1, 0, LYD_VALIDATE_PRESENT, tree1);
CHECK_PARSE_LYD(data2, 0, LYD_VALIDATE_PRESENT, tree2);
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, 0));
assert_int_equal(LY_ENOT, lyd_compare_single(tree1, tree2, LYD_COMPARE_FULL_RECURSION));
lyd_free_all(tree1);
lyd_free_all(tree2);
data1 = "<any xmlns=\"urn:tests:a\"><x>x</x></any>";
data2 = "<any xmlns=\"urn:tests:a\"><x>x</x><x>y</x></any>";
CHECK_PARSE_LYD(data1, 0, LYD_VALIDATE_PRESENT, tree1);
CHECK_PARSE_LYD(data2, 0, LYD_VALIDATE_PRESENT, tree2);
assert_int_equal(LY_ENOT, lyd_compare_single(tree1->next, tree2->next, 0));
lyd_free_all(tree1);
data1 = "<any xmlns=\"urn:tests:a\"><x>x</x><x>y</x></any>";
CHECK_PARSE_LYD(data1, 0, LYD_VALIDATE_PRESENT, tree1);
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, 0));
lyd_free_all(tree1);
lyd_free_all(tree2);
data1 = "<c xmlns=\"urn:tests:a\"><x>c</x><x>a</x><x>b</x></c>";
data2 = "<c xmlns=\"urn:tests:a\"><x>a</x><x>b</x><x>c</x></c>";
CHECK_PARSE_LYD(data1, 0, LYD_VALIDATE_PRESENT, tree1);
CHECK_PARSE_LYD(data2, 0, LYD_VALIDATE_PRESENT, tree2);
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, LYD_COMPARE_FULL_RECURSION));
lyd_free_all(tree1);
lyd_free_all(tree2);
}
static void
test_compare_diff_ctx(void **state)
{
struct lyd_node *tree1, *tree2;
const char *data1, *data2;
struct ly_ctx *ctx2 = NULL;
const char *module;
/* create second context with the same schema */
module = "module b {namespace urn:tests:b;prefix b;yang-version 1.1;"
"revision 2014-05-08;"
"list l2 {config false;"
" container c{leaf x {type string;}}"
"}}";
RECREATE_CTX_WITH_MODULE(ctx2, module);
data1 = "<l2 xmlns=\"urn:tests:b\"><c><x>b</x></c></l2>";
data2 = "<l2 xmlns=\"urn:tests:b\"><c><x>b</x></c></l2>";
CHECK_PARSE_LYD_PARAM_CTX(UTEST_LYCTX, data1, 0, tree1);
CHECK_PARSE_LYD_PARAM_CTX(ctx2, data2, 0, tree2);
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, LYD_COMPARE_FULL_RECURSION));
lyd_free_all(tree1);
lyd_free_all(tree2);
/* recreate second context with schema that has a different name */
module = "module c {namespace urn:tests:c;prefix c;yang-version 1.1;"
"revision 2014-05-08;"
"list l2 {config false;"
" container c{leaf x {type string;}}"
"}}";
RECREATE_CTX_WITH_MODULE(ctx2, module);
data1 = "<l2 xmlns=\"urn:tests:b\"><c><x>b</x></c></l2>";
data2 = "<l2 xmlns=\"urn:tests:c\"><c><x>b</x></c></l2>";
CHECK_PARSE_LYD_PARAM_CTX(UTEST_LYCTX, data1, 0, tree1);
CHECK_PARSE_LYD_PARAM_CTX(ctx2, data2, 0, tree2);
assert_int_equal(LY_ENOT, lyd_compare_single(tree1, tree2, 0));
lyd_free_all(tree1);
lyd_free_all(tree2);
/* recreate second context with schema that has a different revision */
module = "module b {namespace urn:tests:b;prefix b;yang-version 1.1;"
"revision 2015-05-08;"
"list l2 {config false;"
" container c{leaf x {type string;}}"
"}}";
RECREATE_CTX_WITH_MODULE(ctx2, module);
data1 = "<l2 xmlns=\"urn:tests:b\"><c><x>b</x></c></l2>";
data2 = "<l2 xmlns=\"urn:tests:b\"><c><x>b</x></c></l2>";
CHECK_PARSE_LYD_PARAM_CTX(UTEST_LYCTX, data1, 0, tree1);
CHECK_PARSE_LYD_PARAM_CTX(ctx2, data2, 0, tree2);
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, 0));
lyd_free_all(tree1);
lyd_free_all(tree2);
/* recreate second context with schema that has no revision */
module = "module b {namespace urn:tests:b;prefix b;yang-version 1.1;"
"list l2 {config false;"
" container c{leaf x {type string;}}"
"}}";
RECREATE_CTX_WITH_MODULE(ctx2, module);
data1 = "<l2 xmlns=\"urn:tests:b\"><c><x>b</x></c></l2>";
data2 = "<l2 xmlns=\"urn:tests:b\"><c><x>b</x></c></l2>";
CHECK_PARSE_LYD_PARAM_CTX(UTEST_LYCTX, data1, 0, tree1);
CHECK_PARSE_LYD_PARAM_CTX(ctx2, data2, 0, tree2);
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, 0));
lyd_free_all(tree1);
lyd_free_all(tree2);
/* recreate second context with schema that has a different parent nodetype */
module = "module b {namespace urn:tests:b;prefix b;yang-version 1.1;"
"revision 2014-05-08;"
"container l2 {config false;"
" container c{leaf x {type string;}}"
"}}";
RECREATE_CTX_WITH_MODULE(ctx2, module);
data1 = "<l2 xmlns=\"urn:tests:b\"><c><x>b</x></c></l2>";
data2 = "<l2 xmlns=\"urn:tests:b\"><c><x>b</x></c></l2>";
CHECK_PARSE_LYD_PARAM_CTX(UTEST_LYCTX, data1, 0, tree1);
CHECK_PARSE_LYD_PARAM_CTX(ctx2, data2, 0, tree2);
assert_int_equal(LY_ENOT, lyd_compare_single(lyd_child(lyd_child(tree1)), lyd_child(lyd_child(tree2)), 0));
lyd_free_all(tree1);
lyd_free_all(tree2);
/* recreate second context with the same opaq data nodes */
module = "module b {namespace urn:tests:b;prefix b;yang-version 1.1;"
"revision 2014-05-08;"
"anydata any {config false;}"
"}";
RECREATE_CTX_WITH_MODULE(ctx2, module);
data1 = "<any xmlns=\"urn:tests:b\" xmlns:aa=\"urn:tests:b\"><x>aa:x</x></any>";
data2 = "<any xmlns=\"urn:tests:b\" xmlns:bb=\"urn:tests:b\"><x>bb:x</x></any>";
CHECK_PARSE_LYD_PARAM_CTX(UTEST_LYCTX, data1, LYD_PARSE_ONLY, tree1);
CHECK_PARSE_LYD_PARAM_CTX(ctx2, data2, LYD_PARSE_ONLY, tree2);
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, 0));
lyd_free_all(tree1);
lyd_free_all(tree2);
/* recreate second context with the different opaq data node value */
module = "module b {namespace urn:tests:b;prefix b;yang-version 1.1;"
"revision 2014-05-08;"
"anydata any {config false;}"
"}";
RECREATE_CTX_WITH_MODULE(ctx2, module);
data1 = "<any xmlns=\"urn:tests:b\" xmlns:aa=\"urn:tests:b\"><x>aa:x</x></any>";
data2 = "<any xmlns=\"urn:tests:b\" xmlns:bb=\"urn:tests:b\"><x>bb:y</x></any>";
CHECK_PARSE_LYD_PARAM_CTX(UTEST_LYCTX, data1, LYD_PARSE_ONLY, tree1);
CHECK_PARSE_LYD_PARAM_CTX(ctx2, data2, LYD_PARSE_ONLY, tree2);
assert_int_equal(LY_ENOT, lyd_compare_single(tree1, tree2, 0));
lyd_free_all(tree1);
lyd_free_all(tree2);
/* recreate second context with the wrong prefix in opaq data node value */
module = "module b {namespace urn:tests:b;prefix b;yang-version 1.1;"
"revision 2014-05-08;"
"anydata any {config false;}"
"}";
RECREATE_CTX_WITH_MODULE(ctx2, module);
data1 = "<any xmlns=\"urn:tests:b\" xmlns:aa=\"urn:tests:b\"><x>aa:x</x></any>";
data2 = "<any xmlns=\"urn:tests:b\" xmlns:bb=\"urn:tests:b\"><x>cc:x</x></any>";
CHECK_PARSE_LYD_PARAM_CTX(UTEST_LYCTX, data1, LYD_PARSE_ONLY, tree1);
CHECK_PARSE_LYD_PARAM_CTX(ctx2, data2, LYD_PARSE_ONLY, tree2);
assert_int_equal(LY_ENOT, lyd_compare_single(tree1, tree2, 0));
lyd_free_all(tree1);
lyd_free_all(tree2);
/* clean up */
ly_ctx_destroy(ctx2);
_UC->in = NULL;
}
static void
test_dup(void **state)
{
struct lyd_node *tree1, *tree2;
const char *result;
const char *data;
data = "<l1 xmlns=\"urn:tests:a\"><a>a</a><b>b</b><c>x</c></l1>";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree1);
assert_int_equal(LY_SUCCESS, lyd_dup_single(tree1, NULL, LYD_DUP_RECURSIVE, &tree2));
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, LYD_COMPARE_FULL_RECURSION));
lyd_free_all(tree1);
lyd_free_all(tree2);
data = "<l1 xmlns=\"urn:tests:a\"><a>a</a><b>b</b><c>x</c></l1>";
result = "<l1 xmlns=\"urn:tests:a\"><a>a</a><b>b</b></l1>";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree1);
assert_int_equal(LY_SUCCESS, lyd_dup_single(tree1, NULL, 0, &tree2));
lyd_free_all(tree1);
CHECK_PARSE_LYD(result, 0, LYD_VALIDATE_PRESENT, tree1);
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, LYD_COMPARE_FULL_RECURSION));
lyd_free_all(tree1);
lyd_free_all(tree2);
data = "<l2 xmlns=\"urn:tests:a\"><c><x>a</x></c></l2><l2 xmlns=\"urn:tests:a\"><c><x>b</x></c></l2>";
result = "<l2 xmlns=\"urn:tests:a\"><c><x>a</x></c></l2>";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree1);
assert_int_equal(LY_SUCCESS, lyd_dup_siblings(tree1, NULL, LYD_DUP_RECURSIVE, &tree2));
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1->next, tree2->next, LYD_COMPARE_FULL_RECURSION));
lyd_free_all(tree2);
assert_int_equal(LY_SUCCESS, lyd_dup_single(tree1->next, NULL, LYD_DUP_RECURSIVE, &tree2));
lyd_free_all(tree1);
CHECK_PARSE_LYD(result, 0, LYD_VALIDATE_PRESENT, tree1);
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1->next, tree2, LYD_COMPARE_FULL_RECURSION));
lyd_free_all(tree2);
assert_int_equal(LY_SUCCESS, lyd_dup_single(tree1->next, NULL, 0, &tree2));
lyd_free_all(tree1);
result = "<l2 xmlns=\"urn:tests:a\"/>";
CHECK_PARSE_LYD_PARAM(result, LYD_XML, LYD_PARSE_ONLY, 0, LY_SUCCESS, tree1);
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, LYD_COMPARE_FULL_RECURSION));
lyd_free_all(tree1);
lyd_free_all(tree2);
data = "<any xmlns=\"urn:tests:a\"><c><a>a</a></c></any>";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree1);
assert_int_equal(LY_SUCCESS, lyd_dup_single(tree1, NULL, 0, &tree2));
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, LYD_COMPARE_FULL_RECURSION));
lyd_free_all(tree1);
lyd_free_all(tree2);
data = "<l2 xmlns=\"urn:tests:a\"><c><x>b</x></c></l2>";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree1);
assert_int_equal(LY_SUCCESS, lyd_dup_single(lyd_child(lyd_child(tree1->next)), NULL, LYD_DUP_WITH_PARENTS, &tree2));
int unsigned flag = LYS_CONFIG_R | LYS_SET_ENUM;
CHECK_LYSC_NODE(tree2->schema, NULL, 0, flag, 1, "x", 1, LYS_LEAF, 1, 0, NULL, 0);
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1->next, (struct lyd_node *)tree2->parent->parent,
LYD_COMPARE_FULL_RECURSION));
lyd_free_all(tree1);
lyd_free_all(tree2);
data = "<l1 xmlns=\"urn:tests:a\"><a>a</a><b>b</b><c>c</c></l1>";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree1);
assert_int_equal(LY_SUCCESS, lyd_dup_single(((struct lyd_node_inner *)tree1)->child->prev, NULL,
LYD_DUP_WITH_PARENTS, &tree2));
flag = LYS_CONFIG_W | LYS_SET_ENUM;
CHECK_LYSC_NODE(tree2->schema, NULL, 0, flag, 1, "c", 0, LYS_LEAF, 1, 0, NULL, 0);
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, (struct lyd_node *)tree2->parent, LYD_COMPARE_FULL_RECURSION));
lyd_free_all(tree1);
lyd_free_all(tree2);
data = "<l2 xmlns=\"urn:tests:a\"><c><x>b</x></c></l2>";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree1);
assert_int_equal(LY_SUCCESS, lyd_dup_single(tree1->next, NULL, 0, &tree2));
assert_int_equal(LY_SUCCESS, lyd_dup_single(lyd_child(lyd_child(tree1->next)), (struct lyd_node_inner *)tree2,
LYD_DUP_WITH_PARENTS, NULL));
assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1->next, tree2, LYD_COMPARE_FULL_RECURSION));
lyd_free_all(tree1);
lyd_free_all(tree2);
/* invalid */
data = "<l1 xmlns=\"urn:tests:a\"><a>a</a><b>b</b><c>c</c></l1><l2 xmlns=\"urn:tests:a\"><c><x>b</x></c></l2>";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree1);
assert_int_equal(LY_EINVAL, lyd_dup_single(((struct lyd_node_inner *)tree1)->child->prev,
(struct lyd_node_inner *)tree1->next, LYD_DUP_WITH_PARENTS, NULL));
CHECK_LOG_CTX("None of the duplicated node \"c\" schema parents match the provided parent \"c\".", NULL, 0);
lyd_free_all(tree1);
}
static void
test_target(void **state)
{
const struct lyd_node_term *term;
struct lyd_node *tree;
struct lyxp_expr *exp;
struct ly_path *path;
const char *path_str = "/a:l2[2]/c/d[3]";
const char *data =
"<l2 xmlns=\"urn:tests:a\"><c>"
" <d>a</d>"
" </c></l2>"
"<l2 xmlns=\"urn:tests:a\"><c>"
" <d>a</d>"
" <d>b</d>"
" <d>b</d>"
" <d>c</d>"
"</c></l2>"
"<l2 xmlns=\"urn:tests:a\"><c>"
"</c></l2>";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
assert_int_equal(LY_SUCCESS, ly_path_parse(UTEST_LYCTX, NULL, path_str, strlen(path_str), 0, LY_PATH_BEGIN_EITHER,
LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_SIMPLE, &exp));
assert_int_equal(LY_SUCCESS, ly_path_compile(UTEST_LYCTX, NULL, NULL, NULL, exp, LY_PATH_OPER_INPUT,
LY_PATH_TARGET_SINGLE, 1, LY_VALUE_JSON, NULL, &path));
assert_int_equal(LY_SUCCESS, lyd_find_target(path, tree, (struct lyd_node **)&term));
const int unsigned flag = LYS_CONFIG_R | LYS_SET_ENUM | LYS_ORDBY_USER;
CHECK_LYSC_NODE(term->schema, NULL, 0, flag, 1, "d", 0, LYS_LEAFLIST, 1, 0, NULL, 0);
assert_string_equal(lyd_get_value(&term->node), "b");
assert_string_equal(lyd_get_value(term->prev), "b");
lyd_free_all(tree);
ly_path_free(UTEST_LYCTX, path);
lyxp_expr_free(UTEST_LYCTX, exp);
}
static void
test_list_pos(void **state)
{
const char *data;
struct lyd_node *tree;
data = "<bar xmlns=\"urn:tests:a\">test</bar>"
"<l1 xmlns=\"urn:tests:a\"><a>one</a><b>one</b></l1>"
"<l1 xmlns=\"urn:tests:a\"><a>two</a><b>two</b></l1>"
"<foo xmlns=\"urn:tests:a\">test</foo>";
assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
assert_int_equal(0, lyd_list_pos(tree));
assert_int_equal(1, lyd_list_pos(tree->next));
assert_int_equal(2, lyd_list_pos(tree->next->next));
assert_int_equal(0, lyd_list_pos(tree->next->next->next));
lyd_free_all(tree);
data = "<ll xmlns=\"urn:tests:a\">one</ll>"
"<ll xmlns=\"urn:tests:a\">two</ll>"
"<ll xmlns=\"urn:tests:a\">three</ll>";
assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
assert_int_equal(1, lyd_list_pos(tree));
assert_int_equal(2, lyd_list_pos(tree->next));
assert_int_equal(3, lyd_list_pos(tree->next->next));
lyd_free_all(tree);
data = "<ll xmlns=\"urn:tests:a\">one</ll>"
"<l1 xmlns=\"urn:tests:a\"><a>one</a><b>one</b></l1>"
"<ll xmlns=\"urn:tests:a\">two</ll>"
"<l1 xmlns=\"urn:tests:a\"><a>two</a><b>two</b></l1>"
"<ll xmlns=\"urn:tests:a\">three</ll>"
"<l1 xmlns=\"urn:tests:a\"><a>three</a><b>three</b></l1>";
assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
assert_string_equal("l1", tree->schema->name);
assert_int_equal(1, lyd_list_pos(tree));
assert_int_equal(2, lyd_list_pos(tree->next));
assert_int_equal(3, lyd_list_pos(tree->next->next));
assert_string_equal("ll", tree->next->next->next->schema->name);
assert_int_equal(1, lyd_list_pos(tree->next->next->next));
assert_int_equal(2, lyd_list_pos(tree->next->next->next->next));
assert_int_equal(3, lyd_list_pos(tree->next->next->next->next->next));
lyd_free_all(tree);
}
static void
test_first_sibling(void **state)
{
const char *data;
struct lyd_node *tree;
struct lyd_node_inner *parent;
data = "<bar xmlns=\"urn:tests:a\">test</bar>"
"<l1 xmlns=\"urn:tests:a\"><a>one</a><b>one</b><c>one</c></l1>"
"<foo xmlns=\"urn:tests:a\">test</foo>";
assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
assert_ptr_equal(tree, lyd_first_sibling(tree->next));
assert_ptr_equal(tree, lyd_first_sibling(tree));
assert_ptr_equal(tree, lyd_first_sibling(tree->prev));
parent = (struct lyd_node_inner *)tree->next;
assert_int_equal(LYS_LIST, parent->schema->nodetype);
assert_ptr_equal(parent->child, lyd_first_sibling(parent->child->next));
assert_ptr_equal(parent->child, lyd_first_sibling(parent->child));
assert_ptr_equal(parent->child, lyd_first_sibling(parent->child->prev));
lyd_free_all(tree);
}
static void
test_find_path(void **state)
{
struct lyd_node *root;
const struct lys_module *mod;
mod = ly_ctx_get_module_implemented(UTEST_LYCTX, "c");
assert_non_null(mod);
assert_int_equal(LY_SUCCESS, lyd_new_inner(NULL, mod, "cont", 0, &root));
assert_int_equal(LY_SUCCESS, lyd_new_path(root, NULL, "/c:cont/nexthop[gateway='10.0.0.1']", NULL, LYD_NEW_PATH_UPDATE, NULL));
assert_int_equal(LY_SUCCESS, lyd_new_path(root, NULL, "/c:cont/nexthop[gateway='2100::1']", NULL, LYD_NEW_PATH_UPDATE, NULL));
assert_int_equal(LY_SUCCESS, lyd_new_path(root, NULL, "/c:cont/pref[.='fc00::/64']", NULL, 0, NULL));
assert_int_equal(LY_SUCCESS, lyd_find_path(root, "/c:cont/nexthop[gateway='10.0.0.1']", 0, NULL));
assert_int_equal(LY_SUCCESS, lyd_find_path(root, "/c:cont/nexthop[gateway='2100::1']", 0, NULL));
assert_int_equal(LY_SUCCESS, lyd_find_path(root, "/c:cont/pref[.='fc00::/64']", 0, NULL));
assert_int_equal(LY_EVALID, lyd_find_path(root, "/cont", 0, NULL));
CHECK_LOG_CTX("Prefix missing for \"cont\" in path.", "/c:cont", 0);
assert_int_equal(LY_SUCCESS, lyd_find_path(root, "nexthop[gateway='2100::1']", 0, NULL));
lyd_free_all(root);
}
static void
test_data_hash(void **state)
{
struct lyd_node *tree;
const char *schema, *data;
schema =
"module test-data-hash {"
" yang-version 1.1;"
" namespace \"urn:tests:tdh\";"
" prefix t;"
" container c {"
" leaf-list ll {"
" type string;"
" }"
" }"
"}";
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
/* The number of <ll/> must be greater or equal to LYD_HT_MIN_ITEMS
* for the correct test run. It should guarantee the creation of a hash table.
*/
assert_true(LYD_HT_MIN_ITEMS <= 4);
data =
"<c xmlns='urn:tests:tdh'>"
" <ll/>"
" <ll/>"
" <ll/>"
" <ll/>"
"</c>";
/* The run must not crash due to the assert that checks the hash. */
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
CHECK_LOG_CTX("Duplicate instance of \"ll\".", "/test-data-hash:c/ll[.='']", 1);
lyd_free_all(tree);
}
static void
test_lyxp_vars(void **UNUSED(state))
{
struct lyxp_var *vars;
/* Test free. */
vars = NULL;
lyxp_vars_free(vars);
/* Bad arguments for lyxp_vars_add(). */
assert_int_equal(LY_EINVAL, lyxp_vars_set(NULL, "var1", "val1"));
assert_int_equal(LY_EINVAL, lyxp_vars_set(&vars, NULL, "val1"));
assert_int_equal(LY_EINVAL, lyxp_vars_set(&vars, "var1", NULL));
lyxp_vars_free(vars);
vars = NULL;
/* Add one item. */
assert_int_equal(LY_SUCCESS, lyxp_vars_set(&vars, "var1", "val1"));
assert_int_equal(LY_ARRAY_COUNT(vars), 1);
assert_string_equal(vars[0].name, "var1");
assert_string_equal(vars[0].value, "val1");
lyxp_vars_free(vars);
vars = NULL;
/* Add three items. */
assert_int_equal(LY_SUCCESS, lyxp_vars_set(&vars, "var1", "val1"));
assert_int_equal(LY_SUCCESS, lyxp_vars_set(&vars, "var2", "val2"));
assert_int_equal(LY_SUCCESS, lyxp_vars_set(&vars, "var3", "val3"));
assert_int_equal(LY_ARRAY_COUNT(vars), 3);
assert_string_equal(vars[0].name, "var1");
assert_string_equal(vars[0].value, "val1");
assert_string_equal(vars[1].name, "var2");
assert_string_equal(vars[1].value, "val2");
assert_string_equal(vars[2].name, "var3");
assert_string_equal(vars[2].value, "val3");
lyxp_vars_free(vars);
vars = NULL;
/* Change value of a variable. */
assert_int_equal(LY_SUCCESS, lyxp_vars_set(&vars, "var1", "val1"));
assert_int_equal(LY_SUCCESS, lyxp_vars_set(&vars, "var2", "val2"));
assert_int_equal(LY_SUCCESS, lyxp_vars_set(&vars, "var1", "new_value"));
assert_string_equal(vars[0].name, "var1");
assert_string_equal(vars[0].value, "new_value");
assert_string_equal(vars[1].name, "var2");
assert_string_equal(vars[1].value, "val2");
lyxp_vars_free(vars);
vars = NULL;
}
static void
test_data_leafref_nodes(void **state)
{
struct lyd_node *tree, *iter;
struct lyd_node_term *target_node = NULL, *leafref_node;
const struct lyd_leafref_links_rec *rec;
const char *schema, *data, *value;
ly_ctx_set_options(UTEST_LYCTX, LY_CTX_LEAFREF_LINKING);
schema =
"module test-data-hash {"
" yang-version 1.1;"
" namespace \"urn:tests:tdh\";"
" prefix t;"
" leaf-list ll {"
" type string;"
" }"
" container c1 {"
" leaf ref1 {"
" type leafref {"
" path \"../../ll\";"
" }"
" }"
" }"
" leaf ref2 {"
" type leafref {"
" path \"../ll\";"
" }"
" }"
"}";
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
data =
"{"
" \"test-data-hash:ll\": [\"qwe\", \"asd\"],"
" \"test-data-hash:c1\": { \"ref1\": \"qwe\"},"
" \"test-data-hash:ref2\": \"asd\""
"}";
/* The run must not crash due to the assert that checks the hash. */
CHECK_PARSE_LYD_PARAM(data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
LY_LIST_FOR(tree, iter) {
if (strcmp(iter->schema->name, "ll") == 0) {
value = lyd_get_value(iter);
if (strcmp(value, "asd") == 0) {
target_node = (struct lyd_node_term *)iter;
}
}
if (strcmp(iter->schema->name, "ref2") == 0) {
leafref_node = (struct lyd_node_term *)iter;
}
}
/* verify state after leafref plugin validation */
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(target_node, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->leafref_nodes));
assert_ptr_equal(rec->leafref_nodes[0], leafref_node);
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(leafref_node, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->target_nodes));
assert_ptr_equal(rec->target_nodes[0], target_node);
/* value modification of target */
assert_int_equal(LY_SUCCESS, lyd_change_term((struct lyd_node *)target_node, "ASD"));
assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(target_node, &rec));
assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(leafref_node, &rec));
/* change back to original value */
assert_int_equal(LY_SUCCESS, lyd_change_term((struct lyd_node *)target_node, "asd"));
assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(target_node, &rec));
assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(leafref_node, &rec));
/* linking the whole tree again */
assert_int_equal(LY_SUCCESS, lyd_leafref_link_node_tree(tree));
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(target_node, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->leafref_nodes));
assert_ptr_equal(rec->leafref_nodes[0], leafref_node);
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(leafref_node, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->target_nodes));
assert_ptr_equal(rec->target_nodes[0], target_node);
/* value modification of leafref */
assert_int_equal(LY_SUCCESS, lyd_change_term((struct lyd_node *)leafref_node, "qwe"));
assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(target_node, &rec));
assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(leafref_node, &rec));
assert_int_equal(LY_SUCCESS, lyd_change_term((struct lyd_node *)leafref_node, "asd"));
assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(target_node, &rec));
assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(leafref_node, &rec));
/* linking the whole tree again */
assert_int_equal(LY_SUCCESS, lyd_leafref_link_node_tree(tree));
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(target_node, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->leafref_nodes));
assert_ptr_equal(rec->leafref_nodes[0], leafref_node);
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(leafref_node, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->target_nodes));
assert_ptr_equal(rec->target_nodes[0], target_node);
/* freeing whole tree */
lyd_free_all(tree);
}
static void
test_data_leafref_nodes2(void **state)
{
struct lyd_node *tree, *iter;
const char *schema, *data;
struct lyd_node_term *leafref_node = NULL;
const struct lyd_node_term *target_node1, *target_node2;
const struct lyd_leafref_links_rec *rec;
ly_ctx_set_options(UTEST_LYCTX, LY_CTX_LEAFREF_LINKING);
schema =
"module test-data-hash {"
" yang-version 1.1;"
" namespace \"urn:tests:tdh\";"
" prefix t;"
" list l1 {"
" key \"l1 l2\";"
" leaf l1 {"
" type string;"
" }"
" leaf l2 {"
" type string;"
" }"
" }"
" leaf ref1 {"
" type leafref {"
" path \"../l1/l1\";"
" }"
" }"
" leaf-list ll1 {"
" type string;"
" config false;"
" }"
" leaf ref2 {"
" type leafref {"
" path \"../ll1\";"
" }"
" config false;"
" }"
"}";
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
data =
"{"
" \"test-data-hash:l1\": ["
" {\"l1\": \"A\", \"l2\": \"B\"},"
" {\"l1\": \"A\", \"l2\": \"C\"}"
" ],"
" \"test-data-hash:ref1\": \"A\","
" \"test-data-hash:ll1\": [\"asd\", \"qwe\", \"asd\"],"
" \"test-data-hash:ref2\": \"asd\""
"}";
/* The run must not crash due to the assert that checks the hash. */
CHECK_PARSE_LYD_PARAM(data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
LY_LIST_FOR(tree, iter) {
if (strcmp(iter->schema->name, "ref1") == 0) {
leafref_node = (struct lyd_node_term *)iter;
}
}
/* verify state after leafref plugin validation */
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(leafref_node, &rec));
assert_int_equal(2, LY_ARRAY_COUNT(rec->target_nodes));
target_node1 = rec->target_nodes[0];
target_node2 = rec->target_nodes[1];
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(target_node1, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->leafref_nodes));
assert_ptr_equal(rec->leafref_nodes[0], leafref_node);
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(target_node2, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->leafref_nodes));
assert_ptr_equal(rec->leafref_nodes[0], leafref_node);
/* value modification of leafref to remove all links*/
assert_int_equal(LY_SUCCESS, lyd_change_term((struct lyd_node *)leafref_node, "qwe"));
assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(leafref_node, &rec));
assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(target_node1, &rec));
assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(target_node2, &rec));
/* linking the whole tree again */
assert_int_equal(LY_SUCCESS, lyd_change_term((struct lyd_node *)leafref_node, "A"));
assert_int_equal(LY_SUCCESS, lyd_leafref_link_node_tree(tree));
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(leafref_node, &rec));
assert_int_equal(2, LY_ARRAY_COUNT(rec->target_nodes));
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(target_node1, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->leafref_nodes));
assert_ptr_equal(rec->leafref_nodes[0], leafref_node);
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(target_node2, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->leafref_nodes));
assert_ptr_equal(rec->leafref_nodes[0], leafref_node);
/* verify duplicated value in leaf-list */
LY_LIST_FOR(tree, iter) {
if (strcmp(iter->schema->name, "ref2") == 0) {
leafref_node = (struct lyd_node_term *)iter;
}
}
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(leafref_node, &rec));
assert_int_equal(2, LY_ARRAY_COUNT(rec->target_nodes));
target_node1 = rec->target_nodes[0];
target_node2 = rec->target_nodes[1];
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(target_node1, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->leafref_nodes));
assert_ptr_equal(rec->leafref_nodes[0], leafref_node);
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(target_node2, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->leafref_nodes));
assert_ptr_equal(rec->leafref_nodes[0], leafref_node);
/* freeing whole tree */
lyd_free_all(tree);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_compare, setup),
UTEST(test_compare_diff_ctx, setup),
UTEST(test_dup, setup),
UTEST(test_target, setup),
UTEST(test_list_pos, setup),
UTEST(test_first_sibling, setup),
UTEST(test_find_path, setup),
UTEST(test_data_hash, setup),
UTEST(test_lyxp_vars),
UTEST(test_data_leafref_nodes),
UTEST(test_data_leafref_nodes2),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,205 @@
/**
* @file test_metadata.c
* @author Radek Krejci <rkrejci@cesnet.cz>
* @brief unit tests for Metadata extension (annotation) support
*
* Copyright (c) 2019 - 2022 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 "libyang.h"
#include "plugins_exts.h"
#include "plugins_exts/metadata.h"
static void
test_yang(void **state)
{
struct lys_module *mod;
struct lysc_ext_instance *e;
const char *units;
const char *data = "module a {yang-version 1.1; namespace urn:tests:extensions:metadata:a; prefix a;"
"import ietf-yang-metadata {prefix md;}"
"feature f;"
"md:annotation x {"
" description \"test\";"
" if-feature f;"
" reference \"test\";"
" status \"current\";"
" type uint8;"
" units meters;"
"}}";
const char *feats[] = {"f", NULL};
UTEST_ADD_MODULE(data, LYS_IN_YANG, feats, &mod);
assert_int_equal(1, LY_ARRAY_COUNT(mod->compiled->exts));
e = &mod->compiled->exts[0];
assert_non_null(e->compiled);
assert_non_null(e->substmts);
lyplg_ext_get_storage(e, LY_STMT_UNITS, sizeof units, (const void **)&units);
assert_string_equal("meters", units);
/* invalid */
/* missing mandatory type substatement */
data = "module aa {yang-version 1.1; namespace urn:tests:extensions:metadata:aa; prefix aa;"
"import ietf-yang-metadata {prefix md;}"
"md:annotation aa;}";
assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
CHECK_LOG_CTX("Ext plugin \"ly2 metadata v1\": Missing mandatory keyword \"type\" as a child of \"md:annotation aa\".",
"/aa:{extension='md:annotation'}/aa", 0);
/* not allowed substatement */
data = "module aa {yang-version 1.1; namespace urn:tests:extensions:metadata:aa; prefix aa;"
"import ietf-yang-metadata {prefix md;}"
"md:annotation aa {default x;}}";
assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
CHECK_LOG_CTX("Invalid keyword \"default\" as a child of \"md:annotation aa\" extension instance.",
"/aa:{extension='md:annotation'}/aa", 0);
/* invalid cardinality of units substatement */
data = "module aa {yang-version 1.1; namespace urn:tests:extensions:metadata:aa; prefix aa;"
"import ietf-yang-metadata {prefix md;}"
"md:annotation aa {type string; units x; units y;}}";
assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
CHECK_LOG_CTX("Duplicate keyword \"units\".", "/aa:{extension='md:annotation'}/aa", 0);
/* invalid cardinality of status substatement */
data = "module aa {yang-version 1.1; namespace urn:tests:extensions:metadata:aa; prefix aa;"
"import ietf-yang-metadata {prefix md;}"
"md:annotation aa {type string; status current; status obsolete;}}";
assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
CHECK_LOG_CTX("Duplicate keyword \"status\".", "/aa:{extension='md:annotation'}/aa", 0);
/* invalid cardinality of status substatement */
data = "module aa {yang-version 1.1; namespace urn:tests:extensions:metadata:aa; prefix aa;"
"import ietf-yang-metadata {prefix md;}"
"md:annotation aa {type string; type uint8;}}";
assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
CHECK_LOG_CTX("Duplicate keyword \"type\".", "/aa:{extension='md:annotation'}/aa", 0);
/* duplication of the same annotation */
data = "module aa {yang-version 1.1; namespace urn:tests:extensions:metadata:aa; prefix aa;"
"import ietf-yang-metadata {prefix md;}"
"md:annotation aa {type string;} md:annotation aa {type uint8;}}";
assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
CHECK_LOG_CTX("Ext plugin \"ly2 metadata v1\": Extension md:annotation is instantiated multiple times.",
"/aa:{extension='md:annotation'}/aa", 0);
}
static void
test_yin(void **state)
{
struct lys_module *mod;
struct lysc_ext_instance *e;
const char *data, *units;
data = "<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" xmlns:md=\"urn:ietf:params:xml:ns:yang:ietf-yang-metadata\" name=\"a\">\n"
"<yang-version value=\"1.1\"/><namespace uri=\"urn:tests:extensions:metadata:a\"/><prefix value=\"a\"/>\n"
"<import module=\"ietf-yang-metadata\"><prefix value=\"md\"/></import>\n"
"<feature name=\"f\"/>\n"
"<md:annotation name=\"x\">\n"
" <description><text>test</text></description>\n"
" <reference><text>test</text></reference>\n"
" <if-feature name=\"f\"/>\n"
" <status value=\"current\"/>\n"
" <type name=\"uint8\"/>\n"
" <units name=\"meters\"/>\n"
"</md:annotation></module>";
const char *feats[] = {"f", NULL};
UTEST_ADD_MODULE(data, LYS_IN_YIN, feats, &mod);
assert_int_equal(1, LY_ARRAY_COUNT(mod->compiled->exts));
e = &mod->compiled->exts[0];
assert_non_null(e->compiled);
assert_non_null(e->substmts);
lyplg_ext_get_storage(e, LY_STMT_UNITS, sizeof units, (const void **)&units);
assert_string_equal("meters", units);
/* invalid */
/* missing mandatory type substatement */
data = "<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" xmlns:md=\"urn:ietf:params:xml:ns:yang:ietf-yang-metadata\" name=\"aa\">\n"
"<yang-version value=\"1.1\"/><namespace uri=\"urn:tests:extensions:metadata:aa\"/><prefix value=\"aa\"/>\n"
"<import module=\"ietf-yang-metadata\"><prefix value=\"md\"/></import>\n"
"<md:annotation name=\"aa\"/>\n"
"</module>";
assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YIN, NULL));
CHECK_LOG_CTX("Ext plugin \"ly2 metadata v1\": Missing mandatory keyword \"type\" as a child of \"md:annotation aa\".",
"/aa:{extension='md:annotation'}/aa", 0);
/* not allowed substatement */
data = "<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" xmlns:md=\"urn:ietf:params:xml:ns:yang:ietf-yang-metadata\" name=\"aa\">\n"
"<yang-version value=\"1.1\"/><namespace uri=\"urn:tests:extensions:metadata:aa\"/><prefix value=\"aa\"/>\n"
"<import module=\"ietf-yang-metadata\"><prefix value=\"md\"/></import>\n"
"<md:annotation name=\"aa\">\n"
" <default value=\"x\"/>\n"
"</md:annotation></module>";
assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YIN, NULL));
CHECK_LOG_CTX("Invalid keyword \"default\" as a child of \"md:annotation aa\" extension instance.",
"/aa:{extension='md:annotation'}/aa", 0);
/* invalid cardinality of units substatement */
data = "<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" xmlns:md=\"urn:ietf:params:xml:ns:yang:ietf-yang-metadata\" name=\"aa\">\n"
"<yang-version value=\"1.1\"/><namespace uri=\"urn:tests:extensions:metadata:aa\"/><prefix value=\"aa\"/>\n"
"<import module=\"ietf-yang-metadata\"><prefix value=\"md\"/></import>\n"
"<md:annotation name=\"aa\">\n"
" <type name=\"string\"/>\n"
" <units name=\"x\"/>\n"
" <units name=\"y\"/>\n"
"</md:annotation></module>";
assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YIN, NULL));
CHECK_LOG_CTX("Duplicate keyword \"units\".", "/aa:{extension='md:annotation'}/aa", 0);
/* invalid cardinality of status substatement */
data = "<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" xmlns:md=\"urn:ietf:params:xml:ns:yang:ietf-yang-metadata\" name=\"aa\">\n"
"<yang-version value=\"1.1\"/><namespace uri=\"urn:tests:extensions:metadata:aa\"/><prefix value=\"aa\"/>\n"
"<import module=\"ietf-yang-metadata\"><prefix value=\"md\"/></import>\n"
"<md:annotation name=\"aa\">\n"
" <type name=\"string\"/>\n"
" <status value=\"current\"/>\n"
" <status value=\"obsolete\"/>\n"
"</md:annotation></module>";
assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YIN, NULL));
CHECK_LOG_CTX("Duplicate keyword \"status\".", "/aa:{extension='md:annotation'}/aa", 0);
/* invalid cardinality of status substatement */
data = "<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" xmlns:md=\"urn:ietf:params:xml:ns:yang:ietf-yang-metadata\" name=\"aa\">\n"
"<yang-version value=\"1.1\"/><namespace uri=\"urn:tests:extensions:metadata:aa\"/><prefix value=\"aa\"/>\n"
"<import module=\"ietf-yang-metadata\"><prefix value=\"md\"/></import>\n"
"<md:annotation name=\"aa\">\n"
" <type name=\"string\"/>\n"
" <type name=\"uint8\"/>\n"
"</md:annotation></module>";
assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YIN, NULL));
CHECK_LOG_CTX("Duplicate keyword \"type\".", "/aa:{extension='md:annotation'}/aa", 0);
/* duplication of the same annotation */
data = "<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" xmlns:md=\"urn:ietf:params:xml:ns:yang:ietf-yang-metadata\" name=\"aa\">\n"
"<yang-version value=\"1.1\"/><namespace uri=\"urn:tests:extensions:metadata:aa\"/><prefix value=\"aa\"/>\n"
"<import module=\"ietf-yang-metadata\"><prefix value=\"md\"/></import>\n"
"<md:annotation name=\"aa\">\n"
" <type name=\"string\"/>\n"
"</md:annotation><md:annotation name=\"aa\">\n"
" <type name=\"uint8\"/>\n"
"</md:annotation></module>";
assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YIN, NULL));
CHECK_LOG_CTX("Ext plugin \"ly2 metadata v1\": Extension md:annotation is instantiated multiple times.",
"/aa:{extension='md:annotation'}/aa", 0);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_yang),
UTEST(test_yin),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

View file

@ -0,0 +1,124 @@
/*
* @file test_nacm.c
* @author: Radek Krejci <rkrejci@cesnet.cz>
* @brief unit tests for NACM extensions support
*
* Copyright (c) 2019-2020 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 "libyang.h"
static int
setup(void **state)
{
UTEST_SETUP;
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-netconf-acm", "2018-02-14", NULL));
return 0;
}
static void
test_deny_all(void **state)
{
struct lys_module *mod;
struct lysc_node_container *cont;
struct lysc_node_leaf *leaf;
struct lysc_ext_instance *e;
const char *data = "module a {yang-version 1.1; namespace urn:tests:extensions:nacm:a; prefix en;"
"import ietf-netconf-acm {revision-date 2018-02-14; prefix nacm;}"
"container a { nacm:default-deny-all; leaf aa {type string;}}"
"leaf b {type string;}}";
/* valid data */
assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, &mod));
assert_non_null(cont = (struct lysc_node_container *)mod->compiled->data);
assert_non_null(leaf = (struct lysc_node_leaf *)cont->child);
assert_non_null(e = &cont->exts[0]);
assert_int_equal(LY_ARRAY_COUNT(cont->exts), 1);
assert_int_equal(LY_ARRAY_COUNT(leaf->exts), 1); /* NACM extensions inherit */
assert_ptr_equal(e->def, leaf->exts[0].def);
assert_int_equal(1, *((uint8_t *)e->compiled)); /* plugin's value for default-deny-all */
assert_null(cont->next->exts);
/* ignored - valid with warning */
data = "module b {yang-version 1.1; namespace urn:tests:extensions:nacm:b; prefix en;"
"import ietf-netconf-acm {revision-date 2018-02-14; prefix nacm;}"
"nacm:default-deny-all;}";
assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
CHECK_LOG_CTX("Ext plugin \"ly2 NACM v1\": "
"Extension nacm:default-deny-all is allowed only in a data nodes, but it is placed in \"module\" statement.",
"/b:{extension='nacm:default-deny-all'}", 0);
/* invalid */
data = "module aa {yang-version 1.1; namespace urn:tests:extensions:nacm:aa; prefix en;"
"import ietf-netconf-acm {revision-date 2018-02-14; prefix nacm;}"
"leaf l { type string; nacm:default-deny-all; nacm:default-deny-write;}}";
assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
CHECK_LOG_CTX("Ext plugin \"ly2 NACM v1\": "
"Extension nacm:default-deny-write is mixed with nacm:default-deny-all.",
"/aa:l/{extension='nacm:default-deny-all'}", 0);
}
static void
test_deny_write(void **state)
{
struct lys_module *mod;
struct lysc_node_container *cont;
struct lysc_node_leaf *leaf;
struct lysc_ext_instance *e;
const char *data = "module a {yang-version 1.1; namespace urn:tests:extensions:nacm:a; prefix en;"
"import ietf-netconf-acm {revision-date 2018-02-14; prefix nacm;}"
"container a { nacm:default-deny-write; leaf aa {type string;}}"
"leaf b {type string;}}";
/* valid data */
assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, &mod));
assert_non_null(cont = (struct lysc_node_container *)mod->compiled->data);
assert_non_null(leaf = (struct lysc_node_leaf *)cont->child);
assert_non_null(e = &cont->exts[0]);
assert_int_equal(LY_ARRAY_COUNT(cont->exts), 1);
assert_int_equal(LY_ARRAY_COUNT(leaf->exts), 1); /* NACM extensions inherit */
assert_ptr_equal(e->def, leaf->exts[0].def);
assert_int_equal(2, *((uint8_t *)e->compiled)); /* plugin's value for default-deny-write */
/* ignored - valid with warning */
data = "module b {yang-version 1.1; namespace urn:tests:extensions:nacm:b; prefix en;"
"import ietf-netconf-acm {revision-date 2018-02-14; prefix nacm;}"
"notification notif {nacm:default-deny-write;}}";
assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
CHECK_LOG_CTX("Ext plugin \"ly2 NACM v1\": "
"Extension nacm:default-deny-write is not allowed in notification statement.",
"/b:notif/{extension='nacm:default-deny-write'}", 0);
/* invalid */
data = "module aa {yang-version 1.1; namespace urn:tests:extensions:nacm:aa; prefix en;"
"import ietf-netconf-acm {revision-date 2018-02-14; prefix nacm;}"
"leaf l { type string; nacm:default-deny-write; nacm:default-deny-write;}}";
assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
CHECK_LOG_CTX("Ext plugin \"ly2 NACM v1\": "
"Extension nacm:default-deny-write is instantiated multiple times.",
"/aa:l/{extension='nacm:default-deny-write'}", 0);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_deny_all, setup),
UTEST(test_deny_write, setup),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,255 @@
/**
* @file test_structure.c
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief unit tests for structure extensions support
*
* Copyright (c) 2022 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 "libyang.h"
static void
test_schema(void **state)
{
struct lys_module *mod;
struct lysc_ext_instance *e;
char *printed = NULL;
const char *data, *info;
/* valid data */
data = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix a;"
"import ietf-yang-structure-ext {prefix sx;}"
"sx:structure struct {"
" must \"/n2/l\";"
" status deprecated;"
" description desc;"
" reference no-ref;"
" typedef my-type {type string;}"
" grouping my-grp {leaf gl {type my-type;}}"
" container n1 {leaf l {config false; type uint32;}}"
" list n2 {leaf l {type leafref {path /n1/l;}}}"
" uses my-grp;"
"}}";
UTEST_ADD_MODULE(data, LYS_IN_YANG, NULL, &mod);
assert_non_null(e = mod->compiled->exts);
assert_int_equal(LY_ARRAY_COUNT(mod->compiled->exts), 1);
/* valid augment data */
data = "module b {yang-version 1.1; namespace urn:tests:extensions:structure:b; prefix b;"
"import ietf-yang-structure-ext {prefix sx;}"
"import a {prefix a;}"
"sx:augment-structure \"/a:struct/a:n1\" {"
" status obsolete;"
" reference none;"
" leaf aug-leaf {type string;}"
"}}";
UTEST_ADD_MODULE(data, LYS_IN_YANG, NULL, &mod);
assert_non_null(e = mod->compiled->exts);
assert_int_equal(LY_ARRAY_COUNT(mod->compiled->exts), 1);
/* yang compiled print */
info = "module a {\n"
" namespace \"urn:tests:extensions:structure:a\";\n"
" prefix a;\n"
"\n"
" ietf-yang-structure-ext:structure \"struct\" {\n"
" must \"/n2/l\";\n"
" status deprecated;\n"
" description\n"
" \"desc\";\n"
" reference\n"
" \"no-ref\";\n"
" container n1 {\n"
" status deprecated;\n"
" leaf l {\n"
" type uint32;\n"
" status deprecated;\n"
" }\n"
" leaf aug-leaf {\n"
" type string;\n"
" status obsolete;\n"
" }\n"
" }\n"
" list n2 {\n"
" min-elements 0;\n"
" max-elements 4294967295;\n"
" ordered-by user;\n"
" status deprecated;\n"
" leaf l {\n"
" type leafref {\n"
" path \"/n1/l\";\n"
" require-instance true;\n"
" type uint32;\n"
" }\n"
" status deprecated;\n"
" }\n"
" }\n"
" leaf gl {\n"
" type string;\n"
" status deprecated;\n"
" }\n"
" }\n"
"}\n";
assert_non_null(mod = ly_ctx_get_module_implemented(UTEST_LYCTX, "a"));
assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG_COMPILED, 0));
assert_string_equal(printed, info);
free(printed);
info = "module b {\n"
" namespace \"urn:tests:extensions:structure:b\";\n"
" prefix b;\n"
"\n"
" ietf-yang-structure-ext:augment-structure \"/a:struct/a:n1\";\n"
"}\n";
assert_non_null(mod = ly_ctx_get_module_implemented(UTEST_LYCTX, "b"));
assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG_COMPILED, 0));
assert_string_equal(printed, info);
free(printed);
/* no substatements */
data = "module c {yang-version 1.1; namespace urn:tests:extensions:structure:c; prefix c;"
"import ietf-yang-structure-ext {prefix sx;}"
"sx:structure struct;}";
info = "module c {\n"
" namespace \"urn:tests:extensions:structure:c\";\n"
" prefix c;\n"
"\n"
" ietf-yang-structure-ext:structure \"struct\";\n"
"}\n";
UTEST_ADD_MODULE(data, LYS_IN_YANG, NULL, &mod);
assert_non_null(e = mod->compiled->exts);
assert_int_equal(LY_ARRAY_COUNT(mod->compiled->exts), 1);
assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG_COMPILED, 0));
assert_string_equal(printed, info);
free(printed);
}
static void
test_schema_invalid(void **state)
{
const char *data;
/* structure */
data = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix self;"
"import ietf-yang-structure-ext {prefix sx;}"
"sx:structure struct {import yang;}}";
UTEST_INVALID_MODULE(data, LYS_IN_YANG, NULL, LY_EVALID);
CHECK_LOG_CTX("Invalid keyword \"import\" as a child of \"sx:structure struct\" extension instance.",
"/a:{extension='sx:structure'}/struct", 0);
data = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix self;"
"import ietf-yang-structure-ext {prefix sx;}"
"container b { sx:structure struct { container x { leaf x {type string;}}}}}";
UTEST_INVALID_MODULE(data, LYS_IN_YANG, NULL, LY_EVALID);
CHECK_LOG_CTX("Ext plugin \"ly2 structure v1\": "
"Extension sx:structure must not be used as a non top-level statement in \"container\" statement.",
"/a:b/{extension='sx:structure'}/struct", 0);
data = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix self;"
"import ietf-yang-structure-ext {prefix sx;}"
"sx:structure { container x { leaf x {type string;}}}}";
UTEST_INVALID_MODULE(data, LYS_IN_YANG, NULL, LY_EVALID);
CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, 0);
CHECK_LOG_CTX("Extension instance \"sx:structure\" missing argument element \"name\".", NULL, 0);
data = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix self;"
"import ietf-yang-structure-ext {prefix sx;}"
"sx:structure struct { container x { leaf x {type string;}}}"
"sx:structure struct { container y { leaf y {type string;}}}}";
UTEST_INVALID_MODULE(data, LYS_IN_YANG, NULL, LY_EVALID);
CHECK_LOG_CTX("Ext plugin \"ly2 structure v1\": Extension sx:structure is instantiated multiple times.",
"/a:{extension='sx:structure'}/struct", 0);
data = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix self;"
"import ietf-yang-structure-ext {prefix sx;}"
"sx:structure struct { container x { leaf x {type string;}}}"
"choice struct { container y { leaf y {type string;}}}}";
UTEST_INVALID_MODULE(data, LYS_IN_YANG, NULL, LY_EVALID);
CHECK_LOG_CTX("Ext plugin \"ly2 structure v1\": Extension sx:structure collides with a choice with the same identifier.",
"/a:{extension='sx:structure'}/struct", 0);
/* augment-structure */
data = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix a;"
"import ietf-yang-structure-ext {prefix sx;}"
"sx:structure struct {"
" container n1 {leaf l {config false; type uint32;}}"
" list n2 {leaf l {type string;}}"
"}"
"container n1 {leaf l2 {type uint8;}}}";
UTEST_ADD_MODULE(data, LYS_IN_YANG, NULL, NULL);
data = "module b {yang-version 1.1; namespace urn:tests:extensions:structure:b; prefix b;"
"import ietf-yang-structure-ext {prefix sx;}"
"import a {prefix a;}"
"sx:augment-structure \"/a:n1\" {"
" leaf aug-leaf {type string;}"
"}}";
UTEST_INVALID_MODULE(data, LYS_IN_YANG, NULL, LY_ENOTFOUND);
CHECK_LOG_CTX("Augment extension target node \"/a:n1\" from module \"b\" was not found.",
"/b:{extension='sx:augment-structure'}/{augment='/a:n1'}", 0);
}
static void
test_parse(void **state)
{
struct lys_module *mod;
struct lysc_ext_instance *e;
struct lyd_node *tree = NULL;
const char *yang;
const char *xml = "<x xmlns=\"urn:tests:extensions:structure:a\">"
"<x>test</x>"
"<x2 xmlns=\"urn:tests:extensions:structure:b\">25</x2>"
"</x>";
const char *json = "{\"a:x\":{\"x\":\"test\",\"b:x2\":25}}";
yang = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix a;"
"import ietf-yang-structure-ext {prefix sx;}"
"sx:structure struct { container x { leaf x { type string;}}}}";
UTEST_ADD_MODULE(yang, LYS_IN_YANG, NULL, &mod);
yang = "module b {yang-version 1.1; namespace urn:tests:extensions:structure:b; prefix b;"
"import ietf-yang-structure-ext {prefix sx;}"
"import a {prefix a;}"
"sx:augment-structure \"/a:struct/a:x\" {"
" leaf x2 {type uint32;}"
"}}";
UTEST_ADD_MODULE(yang, LYS_IN_YANG, NULL, NULL);
/* get extension after recompilation */
assert_non_null(e = mod->compiled->exts);
assert_int_equal(LY_SUCCESS, ly_in_new_memory(xml, &UTEST_IN));
assert_int_equal(LY_SUCCESS, lyd_parse_ext_data(e, NULL, UTEST_IN, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &tree));
CHECK_LYD_STRING_PARAM(tree, xml, LYD_XML, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS);
lyd_free_all(tree);
ly_in_memory(UTEST_IN, json);
assert_int_equal(LY_SUCCESS, lyd_parse_ext_data(e, NULL, UTEST_IN, LYD_JSON, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &tree));
CHECK_LYD_STRING_PARAM(tree, json, LYD_JSON, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS);
lyd_free_all(tree);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_schema),
UTEST(test_schema_invalid),
UTEST(test_parse),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

View file

@ -0,0 +1,267 @@
/*
* @file test_yangdata.c
* @author: Radek Krejci <rkrejci@cesnet.cz>
* @brief unit tests for yang-data extensions support
*
* Copyright (c) 2019-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
*/
#define _UTEST_MAIN_
#include "utests.h"
#include "libyang.h"
static int
setup(void **state)
{
UTEST_SETUP;
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));
return 0;
}
static void
test_schema(void **state)
{
struct lys_module *mod;
struct lysc_ext_instance *e;
char *printed = NULL;
const char *data = "module a {yang-version 1.1; namespace urn:tests:extensions:yangdata:a; prefix self;"
"import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
"feature x;"
"rc:yang-data template { container x { list l { leaf x { type string;}} leaf y {if-feature x; type string; config false;}}}}";
const char *info = "module a {\n"
" namespace \"urn:tests:extensions:yangdata:a\";\n"
" prefix self;\n\n"
" ietf-restconf:yang-data \"template\" {\n"
" container x {\n"
" status current;\n"
" list l {\n" /* no key */
" min-elements 0;\n"
" max-elements 4294967295;\n"
" ordered-by user;\n"
" status current;\n"
" leaf x {\n"
" type string;\n"
" status current;\n"
" }\n"
" }\n"
" leaf y {\n" /* config and if-feature are ignored */
" type string;\n"
" status current;\n"
" }\n"
" }\n"
" }\n"
"}\n";
/* valid data */
assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, &mod));
assert_non_null(e = mod->compiled->exts);
assert_int_equal(LY_ARRAY_COUNT(mod->compiled->exts), 1);
assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG_COMPILED, 0));
assert_string_equal(printed, info);
free(printed);
data = "module c {yang-version 1.1; namespace urn:tests:extensions:yangdata:c; prefix self;"
"import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
"grouping g { choice ch { container a {presence a; config false;} container b {presence b; config true;}}}"
"rc:yang-data template { uses g;}}";
info = "module c {\n"
" namespace \"urn:tests:extensions:yangdata:c\";\n"
" prefix self;\n\n"
" ietf-restconf:yang-data \"template\" {\n"
" choice ch {\n"
" status current;\n"
" case a {\n"
" status current;\n"
" container a {\n"
" presence \"true\";\n"
" status current;\n"
" }\n"
" }\n"
" case b {\n"
" status current;\n"
" container b {\n"
" presence \"true\";\n"
" status current;\n"
" }\n"
" }\n"
" }\n"
" }\n"
"}\n";
assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, &mod));
assert_non_null(e = mod->compiled->exts);
assert_int_equal(LY_ARRAY_COUNT(mod->compiled->exts), 1);
assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG_COMPILED, 0));
assert_string_equal(printed, info);
free(printed);
/* ignored - valid with warning */
data = "module b {yang-version 1.1; namespace urn:tests:extensions:yangdata:b; prefix self;"
"import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
"container b { rc:yang-data template { container x { leaf x {type string;}}}}}";
info = "module b {\n"
" namespace \"urn:tests:extensions:yangdata:b\";\n"
" prefix self;\n\n"
" container b {\n"
" config true;\n"
" status current;\n"
" }\n"
"}\n";
assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, &mod));
assert_null(mod->compiled->exts);
CHECK_LOG_CTX("Ext plugin \"ly2 yang-data v1\": "
"Extension rc:yang-data is ignored since it appears as a non top-level statement in \"container\" statement.",
"/b:b/{extension='rc:yang-data'}/template", 0);
assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG_COMPILED, 0));
assert_string_equal(printed, info);
free(printed);
/* sama data nodes name, but not conflicting */
data = "module d {yang-version 1.1; namespace urn:tests:extensions:yangdata:d; prefix self;"
"import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
"leaf d { type string;}"
"rc:yang-data template1 { container d {presence d;}}"
"rc:yang-data template2 { container d {presence d;}}}";
info = "module d {\n"
" namespace \"urn:tests:extensions:yangdata:d\";\n"
" prefix self;\n\n"
" ietf-restconf:yang-data \"template1\" {\n"
" container d {\n"
" presence \"true\";\n"
" status current;\n"
" }\n"
" }\n"
" ietf-restconf:yang-data \"template2\" {\n"
" container d {\n"
" presence \"true\";\n"
" status current;\n"
" }\n"
" }\n\n"
" leaf d {\n"
" type string;\n"
" config true;\n"
" status current;\n"
" }\n"
"}\n";
assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, &mod));
assert_non_null(e = mod->compiled->exts);
assert_int_equal(LY_ARRAY_COUNT(mod->compiled->exts), 2);
assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG_COMPILED, 0));
assert_string_equal(printed, info);
free(printed);
}
static void
test_schema_invalid(void **state)
{
const char *data = "module a {yang-version 1.1; namespace urn:tests:extensions:yangdata:a; prefix self;"
"import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
"rc:yang-data template { leaf x {type string;}}}";
assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
CHECK_LOG_CTX("Invalid keyword \"leaf\" as a child of \"rc:yang-data template\" extension instance.",
"/a:{extension='rc:yang-data'}/template", 0);
data = "module a {yang-version 1.1; namespace urn:tests:extensions:yangdata:a; prefix self;"
"import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
"rc:yang-data template { choice x { leaf x {type string;}}}}";
assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
CHECK_LOG_CTX("Ext plugin \"ly2 yang-data v1\": "
"Extension rc:yang-data is instantiated with leaf top level data node (inside a choice), "
"but only a single container data node is allowed.", "/a:{extension='rc:yang-data'}/template", 0);
data = "module a {yang-version 1.1; namespace urn:tests:extensions:yangdata:a; prefix self;"
"import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
"rc:yang-data template { choice x { case x { container z {presence ppp;} leaf x {type string;}}}}}";
assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
CHECK_LOG_CTX("Ext plugin \"ly2 yang-data v1\": "
"Extension rc:yang-data is instantiated with multiple top level data nodes (inside a single choice's case), "
"but only a single container data node is allowed.", "/a:{extension='rc:yang-data'}/template", 0);
data = "module a {yang-version 1.1; namespace urn:tests:extensions:yangdata:a; prefix self;"
"import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
"rc:yang-data template { container x { leaf x {type string;}} container y { leaf y {type string;}}}}";
assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
CHECK_LOG_CTX("Ext plugin \"ly2 yang-data v1\": "
"Extension rc:yang-data is instantiated with multiple top level data nodes, "
"but only a single container data node is allowed.", "/a:{extension='rc:yang-data'}/template", 0);
data = "module a {yang-version 1.1; namespace urn:tests:extensions:yangdata:a; prefix self;"
"import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
"rc:yang-data template;}";
assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
CHECK_LOG_CTX("Ext plugin \"ly2 yang-data v1\": "
"Extension rc:yang-data is instantiated without any top level data node, "
"but exactly one container data node is expected.", "/a:{extension='rc:yang-data'}/template", 0);
data = "module a {yang-version 1.1; namespace urn:tests:extensions:yangdata:a; prefix self;"
"import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
"rc:yang-data { container x { leaf x {type string;}}}}";
assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, 0);
CHECK_LOG_CTX("Extension instance \"rc:yang-data\" missing argument element \"name\".", NULL, 0);
data = "module a {yang-version 1.1; namespace urn:tests:extensions:yangdata:a; prefix self;"
"import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
"rc:yang-data template { container x { leaf x {type string;}}}"
"rc:yang-data template { container y { leaf y {type string;}}}}";
assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
CHECK_LOG_CTX("Ext plugin \"ly2 yang-data v1\": "
"Extension rc:yang-data is instantiated multiple times.", "/a:{extension='rc:yang-data'}/template", 0);
data = "module a {yang-version 1.1; namespace urn:tests:extensions:yangdata:a; prefix self;"
"import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
"grouping t { leaf-list x {type string;}}"
"rc:yang-data template { uses t;}}";
assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
CHECK_LOG_CTX("Ext plugin \"ly2 yang-data v1\": "
"Extension rc:yang-data is instantiated with leaf-list top level data node, "
"but only a single container data node is allowed.", "/a:{extension='rc:yang-data'}/template", 0);
}
static void
test_parse(void **state)
{
struct lys_module *mod;
struct lysc_ext_instance *e;
struct lyd_node *tree = NULL;
const char *schema = "module a {yang-version 1.1; namespace urn:tests:extensions:yangdata:a; prefix self;"
"import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
"rc:yang-data template { container x { leaf x { type string;}}}}";
const char *xml = "<x xmlns=\"urn:tests:extensions:yangdata:a\"><x>test</x></x>";
const char *json = "{\"a:x\":{\"x\":\"test\"}}";
assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, schema, LYS_IN_YANG, &mod));
assert_non_null(e = mod->compiled->exts);
assert_int_equal(LY_SUCCESS, ly_in_new_memory(xml, &UTEST_IN));
assert_int_equal(LY_SUCCESS, lyd_parse_ext_data(e, NULL, UTEST_IN, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
CHECK_LYD_STRING_PARAM(tree, xml, LYD_XML, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS);
lyd_free_all(tree);
ly_in_memory(UTEST_IN, json);
assert_int_equal(LY_SUCCESS, lyd_parse_ext_data(e, NULL, UTEST_IN, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
CHECK_LYD_STRING_PARAM(tree, json, LYD_JSON, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS);
lyd_free_all(tree);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_schema, setup),
UTEST(test_schema_invalid, setup),
UTEST(test_parse, setup),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

1625
tests/utests/node/list.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,394 @@
/**
* @file test_pattern.c
* @author Radek Iša <isa@cesnet.cz>
* @brief test for int8 values
*
* Copyright (c) 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 UTEST HEADER */
#define _UTEST_MAIN_
#include "../utests.h"
/* GLOBAL INCLUDE HEADERS */
#include <ctype.h>
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
#include "path.h"
#define MODULE_CREATE_YIN(MOD_NAME, NODES) \
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" \
"<module name=\"" MOD_NAME "\"\n" \
" xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"\n" \
" xmlns:pref=\"urn:tests:" MOD_NAME "\">\n" \
" <yang-version value=\"1.1\"/>\n" \
" <namespace uri=\"urn:tests:" MOD_NAME "\"/>\n" \
" <prefix value=\"pref\"/>\n" \
NODES \
"</module>\n"
#define MODULE_CREATE_YANG(MOD_NAME, NODES) \
"module " MOD_NAME " {\n" \
" yang-version 1.1;\n" \
" namespace \"urn:tests:" MOD_NAME "\";\n" \
" prefix pref;\n" \
NODES \
"}\n"
#define TEST_SUCCESS_XML(MOD_NAME, DATA, TYPE, ...) \
{ \
struct lyd_node *tree; \
const char *data = "<port xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</port>"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree); \
CHECK_LYSC_NODE(tree->schema, NULL, 0, 0x5, 1, "port", 0, LYS_LEAF, 0, 0, 0, 0); \
CHECK_LYD_NODE_TERM((struct lyd_node_term *)tree, 0, 0, 0, 0, 1, TYPE, __VA_ARGS__); \
lyd_free_all(tree); \
}
#define TEST_SUCCESS_JSON(MOD_NAME, DATA, TYPE, ...) \
{ \
struct lyd_node *tree; \
const char *data = "{\"" MOD_NAME ":port\":" DATA "}"; \
CHECK_PARSE_LYD_PARAM(data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree); \
CHECK_LYSC_NODE(tree->schema, NULL, 0, 0x5, 1, "port", 0, LYS_LEAF, 0, 0, 0, 0); \
CHECK_LYD_NODE_TERM((struct lyd_node_term *)tree, 0, 0, 0, 0, 1, TYPE, __VA_ARGS__); \
lyd_free_all(tree); \
}
#define TEST_ERROR_XML(MOD_NAME, DATA) \
{\
struct lyd_node *tree; \
const char *data = "<port xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</port>"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); \
assert_null(tree); \
}
#define TEST_ERROR_JSON(MOD_NAME, DATA) \
{ \
struct lyd_node *tree; \
const char *data = "{\"" MOD_NAME ":port\":" DATA "}"; \
CHECK_PARSE_LYD_PARAM(data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); \
assert_null(tree); \
}
static void
test_schema_yang(void **state)
{
const char *schema;
struct lys_module *mod;
struct lysc_node_leaf *lysc_leaf;
struct lysp_node_leaf *lysp_leaf;
struct lysc_pattern *pattern;
schema = MODULE_CREATE_YANG("T0", "leaf port {type string {"
"pattern \"[A-Za-z]*\"{"
"description \"pattern description\";"
"error-app-tag \"pattern err-apt-tag\";"
"error-message \"pattern error message\";}}}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
assert_non_null(mod);
lysc_leaf = (void *) mod->compiled->data;
CHECK_LYSC_NODE_LEAF(lysc_leaf, NULL, 0, 0x5, 1, "port", 0, 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSC_TYPE_STR((struct lysc_type_str *)lysc_leaf->type, 0, 0, 1);
pattern = ((struct lysc_type_str *)lysc_leaf->type)->patterns[0];
CHECK_LYSC_PATTERN(pattern, "pattern description", "pattern err-apt-tag",
"pattern error message", "[A-Za-z]*", 0, 0, NULL);
lysp_leaf = (void *) mod->parsed->data;
CHECK_LYSP_NODE_LEAF(lysp_leaf, NULL, 0, 0x0, 0, "port", 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSP_TYPE(&(lysp_leaf->type), 0, 0, 0, 0, 0, 0x40, 0, 0, "string", 0, 1, 1, 0, 0, 0);
CHECK_LYSP_RESTR(&(lysp_leaf->type.patterns[0]), "\x6" "[A-Za-z]*", "pattern description",
"pattern err-apt-tag", "pattern error message", 0, NULL);
/* heredity */
schema = MODULE_CREATE_YANG("T1", "typedef my_type {type string {"
"pattern \"[A-Za-z]*\"{"
"description \"pattern description\";"
"error-app-tag \"pattern err-apt-tag\";"
"error-message \"pattern error message\";}}}"
"leaf port {type my_type;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
assert_non_null(mod);
lysc_leaf = (void *) mod->compiled->data;
CHECK_LYSC_NODE_LEAF(lysc_leaf, NULL, 0, 0x5, 1, "port", 0, 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSC_TYPE_STR((struct lysc_type_str *)lysc_leaf->type, 0, 0, 1);
pattern = ((struct lysc_type_str *)lysc_leaf->type)->patterns[0];
CHECK_LYSC_PATTERN(pattern, "pattern description", "pattern err-apt-tag",
"pattern error message", "[A-Za-z]*", 0, 0, NULL);
lysp_leaf = (void *) mod->parsed->data;
CHECK_LYSP_NODE_LEAF(lysp_leaf, NULL, 0, 0x0, 0, "port", 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSP_TYPE(&(lysp_leaf->type), 0, 0, 0, 0, 0, 0x0, 0, 0, "my_type", 0, 0, 1, 0, 0, 0);
/* heredity new pattern */
schema = MODULE_CREATE_YANG("T2", "typedef my_type {type string {"
"pattern \"[A-Za-z]*\"{"
"description \"pattern description\";"
"error-app-tag \"pattern err-apt-tag\";"
"error-message \"pattern error message\";}}}"
"leaf port {type my_type{pattern \"[A-Z]*\";}}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
assert_non_null(mod);
lysc_leaf = (void *) mod->compiled->data;
CHECK_LYSC_NODE_LEAF(lysc_leaf, NULL, 0, 0x5, 1, "port", 0, 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSC_TYPE_STR((struct lysc_type_str *)lysc_leaf->type, 0, 0, 2);
pattern = ((struct lysc_type_str *)lysc_leaf->type)->patterns[0];
CHECK_LYSC_PATTERN(pattern, "pattern description", "pattern err-apt-tag",
"pattern error message", "[A-Za-z]*", 0, 0, NULL);
pattern = ((struct lysc_type_str *)lysc_leaf->type)->patterns[1];
CHECK_LYSC_PATTERN(pattern, NULL, NULL, NULL, "[A-Z]*", 0, 0, NULL);
lysp_leaf = (void *) mod->parsed->data;
CHECK_LYSP_NODE_LEAF(lysp_leaf, NULL, 0, 0x0, 0, "port", 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSP_TYPE(&(lysp_leaf->type), 0, 0, 0, 0, 0, 0x40, 0, 0, "my_type", 0, 1, 1, 0, 0, 0);
CHECK_LYSP_RESTR(&(lysp_leaf->type.patterns[0]), "\x6" "[A-Z]*", NULL, NULL, NULL, 0, NULL);
/* heredity new pattern */
schema = MODULE_CREATE_YANG("T3", "typedef my_type {type string {"
"pattern \"[A-Za-z]*\"{"
" description \"pattern 0 description\";"
" error-app-tag \"pattern 0 err-apt-tag\";"
" error-message \"pattern 0 error message\";}}}"
"leaf port {type my_type{pattern \"[A-Z]*\"{"
" description \"pattern 1 description\";"
" error-app-tag \"pattern 1 err-apt-tag\";"
" error-message \"pattern 1 error message\";"
"}}}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
assert_non_null(mod);
lysc_leaf = (void *) mod->compiled->data;
CHECK_LYSC_NODE_LEAF(lysc_leaf, NULL, 0, 0x5, 1, "port", 0, 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSC_TYPE_STR((struct lysc_type_str *)lysc_leaf->type, 0, 0, 2);
pattern = ((struct lysc_type_str *)lysc_leaf->type)->patterns[0];
CHECK_LYSC_PATTERN(pattern, "pattern 0 description", "pattern 0 err-apt-tag",
"pattern 0 error message", "[A-Za-z]*", 0, 0, NULL);
pattern = ((struct lysc_type_str *)lysc_leaf->type)->patterns[1];
CHECK_LYSC_PATTERN(pattern, "pattern 1 description", "pattern 1 err-apt-tag",
"pattern 1 error message", "[A-Z]*", 0, 0, NULL);
lysp_leaf = (void *) mod->parsed->data;
CHECK_LYSP_NODE_LEAF(lysp_leaf, NULL, 0, 0x0, 0, "port", 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSP_TYPE(&(lysp_leaf->type), 0, 0, 0, 0, 0, 0x40, 0, 0, "my_type", 0, 1, 1, 0, 0, 0);
CHECK_LYSP_RESTR(&(lysp_leaf->type.patterns[0]), "\x6" "[A-Z]*", "pattern 1 description",
"pattern 1 err-apt-tag", "pattern 1 error message", 0, NULL);
}
static void
test_schema_yin(void **state)
{
const char *schema;
struct lys_module *mod;
struct lysc_node_leaf *lysc_leaf;
struct lysp_node_leaf *lysp_leaf;
struct lysc_pattern *pattern;
schema = MODULE_CREATE_YIN("T0", "<leaf name=\"port\"> <type name=\"string\">"
"<pattern value=\"[A-Za-z]*\">"
" <description><text>pattern description</text></description>"
" <error-app-tag value=\"pattern err-apt-tag\"/>"
" <error-message> <value>pattern error message</value></error-message>"
"</pattern></type></leaf>");
UTEST_ADD_MODULE(schema, LYS_IN_YIN, NULL, &mod);
assert_non_null(mod);
lysc_leaf = (void *) mod->compiled->data;
CHECK_LYSC_NODE_LEAF(lysc_leaf, NULL, 0, 0x5, 1, "port", 0, 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSC_TYPE_STR((struct lysc_type_str *)lysc_leaf->type, 0, 0, 1);
pattern = ((struct lysc_type_str *)lysc_leaf->type)->patterns[0];
CHECK_LYSC_PATTERN(pattern, "pattern description", "pattern err-apt-tag",
"pattern error message", "[A-Za-z]*", 0, 0, NULL);
lysp_leaf = (void *) mod->parsed->data;
CHECK_LYSP_NODE_LEAF(lysp_leaf, NULL, 0, 0x0, 0, "port", 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSP_TYPE(&(lysp_leaf->type), 0, 0, 0, 0, 0, 0x40, 0, 0, "string", 0, 1, 1, 0, 0, 0);
CHECK_LYSP_RESTR(&(lysp_leaf->type.patterns[0]), "\x6" "[A-Za-z]*", "pattern description",
"pattern err-apt-tag", "pattern error message", 0, NULL);
/* heredity */
schema = MODULE_CREATE_YIN("T1", "<typedef name=\"my_type\"> <type name=\"string\">"
"<pattern value=\"[A-Za-z]*\">"
" <description><text>pattern description</text></description>"
" <error-app-tag value=\"pattern err-apt-tag\"/>"
" <error-message><value>pattern error message</value></error-message>"
"</pattern></type></typedef>"
"<leaf name=\"port\"><type name=\"my_type\"/></leaf>");
UTEST_ADD_MODULE(schema, LYS_IN_YIN, NULL, &mod);
assert_non_null(mod);
lysc_leaf = (void *) mod->compiled->data;
CHECK_LYSC_NODE_LEAF(lysc_leaf, NULL, 0, 0x5, 1, "port", 0, 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSC_TYPE_STR((struct lysc_type_str *)lysc_leaf->type, 0, 0, 1);
pattern = ((struct lysc_type_str *)lysc_leaf->type)->patterns[0];
CHECK_LYSC_PATTERN(pattern, "pattern description", "pattern err-apt-tag",
"pattern error message", "[A-Za-z]*", 0, 0, NULL);
lysp_leaf = (void *) mod->parsed->data;
CHECK_LYSP_NODE_LEAF(lysp_leaf, NULL, 0, 0x0, 0, "port", 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSP_TYPE(&(lysp_leaf->type), 0, 0, 0, 0, 0, 0x0, 0, 0, "my_type", 0, 0, 1, 0, 0, 0);
/* heredity new pattern */
schema = MODULE_CREATE_YIN("T2", "<typedef name=\"my_type\"> <type name=\"string\">"
"<pattern value=\"[A-Za-z]*\">"
" <description><text>pattern description</text></description>"
" <error-app-tag value=\"pattern err-apt-tag\"/>"
" <error-message><value>pattern error message</value></error-message>"
"</pattern></type></typedef>"
"<leaf name=\"port\"> <type name=\"my_type\"><pattern value=\"[A-Z]*\"/>"
"</type></leaf>");
UTEST_ADD_MODULE(schema, LYS_IN_YIN, NULL, &mod);
assert_non_null(mod);
lysc_leaf = (void *) mod->compiled->data;
CHECK_LYSC_NODE_LEAF(lysc_leaf, NULL, 0, 0x5, 1, "port", 0, 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSC_TYPE_STR((struct lysc_type_str *)lysc_leaf->type, 0, 0, 2);
pattern = ((struct lysc_type_str *)lysc_leaf->type)->patterns[0];
CHECK_LYSC_PATTERN(pattern, "pattern description", "pattern err-apt-tag",
"pattern error message", "[A-Za-z]*", 0, 0, NULL);
pattern = ((struct lysc_type_str *)lysc_leaf->type)->patterns[1];
CHECK_LYSC_PATTERN(pattern, NULL, NULL, NULL, "[A-Z]*", 0, 0, NULL);
lysp_leaf = (void *) mod->parsed->data;
CHECK_LYSP_NODE_LEAF(lysp_leaf, NULL, 0, 0x0, 0, "port", 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSP_TYPE(&(lysp_leaf->type), 0, 0, 0, 0, 0, 0x40, 0, 0, "my_type", 0, 1, 1, 0, 0, 0);
CHECK_LYSP_RESTR(&(lysp_leaf->type.patterns[0]), "\x6" "[A-Z]*", NULL, NULL, NULL, 0, NULL);
/* heredity new pattern */
schema = MODULE_CREATE_YIN("T3", "<typedef name=\"my_type\"> <type name=\"string\">"
"<pattern value=\"[A-Za-z]*\">"
" <description> <text>pattern 0 description</text></description>"
" <error-app-tag value=\"pattern 0 err-apt-tag\"/>"
" <error-message> <value>pattern 0 error message</value></error-message>"
"</pattern></type></typedef>"
"<leaf name=\"port\"> <type name=\"my_type\">"
"<pattern value=\"[A-Z]*\">"
" <description><text>pattern 1 description</text></description>"
" <error-app-tag value=\"pattern 1 err-apt-tag\"/>"
" <error-message><value>pattern 1 error message</value></error-message>"
"</pattern></type></leaf>");
UTEST_ADD_MODULE(schema, LYS_IN_YIN, NULL, &mod);
assert_non_null(mod);
lysc_leaf = (void *) mod->compiled->data;
CHECK_LYSC_NODE_LEAF(lysc_leaf, NULL, 0, 0x5, 1, "port", 0, 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSC_TYPE_STR((struct lysc_type_str *)lysc_leaf->type, 0, 0, 2);
pattern = ((struct lysc_type_str *)lysc_leaf->type)->patterns[0];
CHECK_LYSC_PATTERN(pattern, "pattern 0 description", "pattern 0 err-apt-tag",
"pattern 0 error message", "[A-Za-z]*", 0, 0, NULL);
pattern = ((struct lysc_type_str *)lysc_leaf->type)->patterns[1];
CHECK_LYSC_PATTERN(pattern, "pattern 1 description", "pattern 1 err-apt-tag",
"pattern 1 error message", "[A-Z]*", 0, 0, NULL);
lysp_leaf = (void *) mod->parsed->data;
CHECK_LYSP_NODE_LEAF(lysp_leaf, NULL, 0, 0x0, 0, "port", 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSP_TYPE(&(lysp_leaf->type), 0, 0, 0, 0, 0, 0x40, 0, 0, "my_type", 0, 1, 1, 0, 0, 0);
CHECK_LYSP_RESTR(&(lysp_leaf->type.patterns[0]), "\x6" "[A-Z]*", "pattern 1 description",
"pattern 1 err-apt-tag", "pattern 1 error message", 0, NULL);
}
static void
test_schema_print(void **state)
{
const char *schema_yang, *schema_yin;
char *printed;
struct lys_module *mod;
/* test print yang to yin */
schema_yang = MODULE_CREATE_YANG("PRINT0", "leaf port {type string {"
"pattern \"[A-Z]*\"{"
"description \"desc < \";"
"error-app-tag \"err-apt-tag <\";"
"error-message \"error message <\";}}}");
schema_yin = MODULE_CREATE_YIN("PRINT0",
" <leaf name=\"port\">\n"
" <type name=\"string\">\n"
" <pattern value=\"[A-Z]*\">\n"
" <error-message>\n"
" <value>error message &lt;</value>\n"
" </error-message>\n"
" <error-app-tag value=\"err-apt-tag &lt;\"/>\n"
" <description>\n"
" <text>desc &lt; </text>\n"
" </description>\n"
" </pattern>\n"
" </type>\n"
" </leaf>\n");
UTEST_ADD_MODULE(schema_yang, LYS_IN_YANG, NULL, &mod);
assert_non_null(mod);
assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YIN, 0));
assert_string_equal(printed, schema_yin);
free(printed);
/* test print yin to yang */
schema_yang = MODULE_CREATE_YANG("PRINT1",
"\n"
" leaf port {\n"
" type string {\n"
" pattern \"[A-Z]*\" {\n"
" error-message\n"
" \"error message <\";\n"
" error-app-tag \"err-apt-tag <\";\n"
" description\n"
" \"desc < \";\n"
" }\n"
" }\n"
" }\n");
schema_yin = MODULE_CREATE_YIN("PRINT1",
" <leaf name=\"port\">\n"
" <type name=\"string\">\n"
" <pattern value=\"[A-Z]*\">\n"
" <error-message>\n"
" <value>error message &lt;</value>\n"
" </error-message>\n"
" <error-app-tag value=\"err-apt-tag &lt;\"/>\n"
" <description>\n"
" <text>desc &lt; </text>\n"
" </description>\n"
" </pattern>\n"
" </type>\n"
" </leaf>\n");
UTEST_ADD_MODULE(schema_yin, LYS_IN_YIN, NULL, &mod);
assert_non_null(mod);
assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG, 0));
assert_string_equal(printed, schema_yang);
free(printed);
}
static void
test_data_xml(void **state)
{
const char *schema;
/* xml test */
schema = MODULE_CREATE_YANG("TPATTERN_0", "typedef my_type {type string {"
"pattern \"[A-Za-z]*\"{"
" description \"pattern 0 description\";"
" error-app-tag \"pattern 0 err-apt-tag\";"
" error-message \"pattern 0 error message\";}}}"
"leaf port {type my_type{pattern \"[A-Z]*\"{"
" description \"pattern 1 description\";"
" error-app-tag \"pattern 1 err-apt-tag\";"
" error-message \"pattern 1 error message\";"
"}}}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
/* test success */
TEST_SUCCESS_XML("TPATTERN_0", "AHOJ", STRING, "AHOJ");
/* test print error */
TEST_ERROR_XML("TPATTERN_0", "T128");
CHECK_LOG_CTX("pattern 0 error message", "/TPATTERN_0:port", 1);
TEST_ERROR_XML("TPATTERN_0", "ahoj");
CHECK_LOG_CTX("pattern 1 error message", "/TPATTERN_0:port", 1);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_schema_yang),
UTEST(test_schema_yin),
UTEST(test_schema_print),
UTEST(test_data_xml),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

View file

@ -0,0 +1,424 @@
/**
* @file test_range.c
* @author Radek Iša <isa@cesnet.cz>
* @brief test for int8 values
*
* Copyright (c) 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 UTEST HEADER */
#define _UTEST_MAIN_
#include "../utests.h"
/* GLOBAL INCLUDE HEADERS */
#include <ctype.h>
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
#include "path.h"
#define MODULE_CREATE_YIN(MOD_NAME, NODES) \
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" \
"<module name=\"" MOD_NAME "\"\n" \
" xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"\n" \
" xmlns:pref=\"urn:tests:" MOD_NAME "\">\n" \
" <yang-version value=\"1.1\"/>\n" \
" <namespace uri=\"urn:tests:" MOD_NAME "\"/>\n" \
" <prefix value=\"pref\"/>\n" \
NODES \
"</module>\n"
#define MODULE_CREATE_YANG(MOD_NAME, NODES) \
"module " MOD_NAME " {\n" \
" yang-version 1.1;\n" \
" namespace \"urn:tests:" MOD_NAME "\";\n" \
" prefix pref;\n" \
NODES \
"}\n"
#define TEST_SUCCESS_XML(MOD_NAME, DATA, TYPE, ...) \
{ \
struct lyd_node *tree; \
const char *data = "<port xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</port>"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree); \
CHECK_LYSC_NODE(tree->schema, NULL, 0, 0x5, 1, "port", 0, LYS_LEAF, 0, 0, 0, 0); \
CHECK_LYD_NODE_TERM((struct lyd_node_term *)tree, 0, 0, 0, 0, 1, TYPE, __VA_ARGS__); \
lyd_free_all(tree); \
}
#define TEST_SUCCESS_JSON(MOD_NAME, DATA, TYPE, ...) \
{ \
struct lyd_node *tree; \
const char *data = "{\"" MOD_NAME ":port\":" DATA "}"; \
CHECK_PARSE_LYD_PARAM(data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree); \
CHECK_LYSC_NODE(tree->schema, NULL, 0, 0x5, 1, "port", 0, LYS_LEAF, 0, 0, 0, 0); \
CHECK_LYD_NODE_TERM((struct lyd_node_term *)tree, 0, 0, 0, 0, 1, TYPE, __VA_ARGS__); \
lyd_free_all(tree); \
}
#define TEST_ERROR_XML(MOD_NAME, DATA) \
{\
struct lyd_node *tree; \
const char *data = "<port xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</port>"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); \
assert_null(tree); \
}
#define TEST_ERROR_JSON(MOD_NAME, DATA) \
{ \
struct lyd_node *tree; \
const char *data = "{\"" MOD_NAME ":port\":" DATA "}"; \
CHECK_PARSE_LYD_PARAM(data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); \
assert_null(tree); \
}
static void
test_schema_yang(void **state)
{
const char *schema;
struct lys_module *mod;
struct lysc_node_leaf *lysc_leaf;
struct lysp_node_leaf *lysp_leaf;
struct lysc_range *range;
schema = MODULE_CREATE_YANG("T0", "leaf port {type int8 {"
"range \"0 .. 50 | 127\"{"
"description \"description test\";"
"error-app-tag \"err-apt-tag\";"
"error-message \"error message\";}}}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
assert_non_null(mod);
lysc_leaf = (void *)mod->compiled->data;
CHECK_LYSC_NODE_LEAF(lysc_leaf, NULL, 0, 0x5, 1, "port", 0, 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSC_TYPE_NUM((struct lysc_type_num *)lysc_leaf->type, LY_TYPE_INT8, 0, 1);
range = ((struct lysc_type_num *)lysc_leaf->type)->range;
CHECK_LYSC_RANGE(range, "description test", "err-apt-tag", "error message", 0, 2, NULL);
lysp_leaf = (void *)mod->parsed->data;
CHECK_LYSP_NODE_LEAF(lysp_leaf, NULL, 0, 0x0, 0, "port", 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSP_TYPE(&(lysp_leaf->type), 0, 0, 0, 0, 0, 0x80, 0, 0, "int8", 0, 0, 1, 1, 0, 0);
CHECK_LYSP_RESTR(lysp_leaf->type.range, "0 .. 50 | 127", "description test", "err-apt-tag", "error message", 0, NULL);
/* heredity */
schema = MODULE_CREATE_YANG("T1", "typedef my_type {type uint16 {"
"range \"0 .. 100\"{"
"description \"percentage\";"
"error-app-tag \"err-apt-tag\";"
"error-message \"error message\";}}}"
"leaf port {type my_type;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
assert_non_null(mod);
lysc_leaf = (void *)mod->compiled->data;
CHECK_LYSC_NODE_LEAF(lysc_leaf, NULL, 0, 0x5, 1, "port", 0, 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSC_TYPE_NUM((struct lysc_type_num *)lysc_leaf->type, LY_TYPE_UINT16, 0, 1);
range = ((struct lysc_type_num *)lysc_leaf->type)->range;
CHECK_LYSC_RANGE(range, "percentage", "err-apt-tag", "error message", 0, 1, NULL);
lysp_leaf = (void *)mod->parsed->data;
CHECK_LYSP_NODE_LEAF(lysp_leaf, NULL, 0, 0x0, 0, "port", 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSP_TYPE(&(lysp_leaf->type), 0, 0, 0, 0, 0, 0x0, 0, 0, "my_type", 0, 0, 1, 0, 0, 0);
/* heredity new range */
schema = MODULE_CREATE_YANG("T2", "typedef my_type {type uint16 {"
"range \"0 .. 100\"{"
"description \"percentage\";"
"error-app-tag \"err-apt-tag\";"
"error-message \"error message\";}}}"
"leaf port {type my_type{range \"0 .. 20\";}}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
assert_non_null(mod);
lysc_leaf = (void *)mod->compiled->data;
CHECK_LYSC_NODE_LEAF(lysc_leaf, NULL, 0, 0x5, 1, "port", 0, 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSC_TYPE_NUM((struct lysc_type_num *)lysc_leaf->type, LY_TYPE_UINT16, 0, 1);
range = ((struct lysc_type_num *)lysc_leaf->type)->range;
CHECK_LYSC_RANGE(range, NULL, NULL, NULL, 0, 1, NULL);
lysp_leaf = (void *)mod->parsed->data;
CHECK_LYSP_NODE_LEAF(lysp_leaf, NULL, 0, 0x0, 0, "port", 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSP_TYPE(&(lysp_leaf->type), 0, 0, 0, 0, 0, 0x80, 0, 0, "my_type", 0, 0, 1, 1, 0, 0);
/* change */
schema = MODULE_CREATE_YANG("T3", "typedef my_type {type uint16 {"
"range \"0 .. 100\"{"
"description \"percentage\";"
"error-app-tag \"err-apt-tag\";"
"error-message \"error message\";}}}"
"leaf port {type my_type{"
" range \"0 .. 50\"{"
" description \"description 0-50\";"
" error-app-tag \"err-apt-tag 0-50\";"
" error-message \"error message 0-50\";}}"
"}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
assert_non_null(mod);
lysc_leaf = (void *)mod->compiled->data;
CHECK_LYSC_NODE_LEAF(lysc_leaf, NULL, 0, 0x5, 1, "port", 0, 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSC_TYPE_NUM((struct lysc_type_num *)lysc_leaf->type, LY_TYPE_UINT16, 0, 1);
range = ((struct lysc_type_num *)lysc_leaf->type)->range;
CHECK_LYSC_RANGE(range, "description 0-50", "err-apt-tag 0-50", "error message 0-50", 0, 1, NULL);
lysp_leaf = (void *)mod->parsed->data;
CHECK_LYSP_NODE_LEAF(lysp_leaf, NULL, 0, 0x0, 0, "port", 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSP_TYPE(&(lysp_leaf->type), 0, 0, 0, 0, 0, 0x80, 0, 0, "my_type", 0, 0, 1, 1, 0, 0);
CHECK_LYSP_RESTR(lysp_leaf->type.range, "0 .. 50", "description 0-50", "err-apt-tag 0-50", "error message 0-50", 0, NULL);
}
static void
test_schema_yin(void **state)
{
const char *schema;
struct lys_module *mod;
struct lysc_node_leaf *lysc_leaf;
struct lysp_node_leaf *lysp_leaf;
struct lysc_range *range;
schema = MODULE_CREATE_YIN("T0", "<leaf name=\"port\">"
"<type name=\"int64\">"
"<range value = \"0 .. 50 | 256\">"
" <description>"
" <text>desc</text>\n"
" </description>\n"
"<error-app-tag value=\"text &lt; tag\"/>"
" <error-message>"
" <value>yin error message &lt;</value>\n"
" </error-message>\n"
"</range>"
"</type>"
"</leaf>");
UTEST_ADD_MODULE(schema, LYS_IN_YIN, NULL, &mod);
assert_non_null(mod);
lysc_leaf = (void *)mod->compiled->data;
CHECK_LYSC_NODE_LEAF(lysc_leaf, NULL, 0, 0x5, 1, "port", 0, 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSC_TYPE_NUM((struct lysc_type_num *)lysc_leaf->type, LY_TYPE_INT64, 0, 1);
range = ((struct lysc_type_num *)lysc_leaf->type)->range;
CHECK_LYSC_RANGE(range, "desc", "text < tag", "yin error message <", 0, 2, NULL);
lysp_leaf = (void *)mod->parsed->data;
CHECK_LYSP_NODE_LEAF(lysp_leaf, NULL, 0, 0x0, 0, "port", 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSP_TYPE(&(lysp_leaf->type), 0, 0, 0, 0, 0, 0x80, 0, 0, "int64", 0, 0, 1, 1, 0, 0);
CHECK_LYSP_RESTR(lysp_leaf->type.range, "0 .. 50 | 256", "desc", "text < tag", "yin error message <", 0, NULL);
/* heredity */
schema = MODULE_CREATE_YIN("T1", "<typedef name=\"my_type\">"
"<type name=\"int16\">"
"<range value = \"0 .. 50\">"
" <description>"
" <text>percentage</text>\n"
" </description>\n"
"<error-app-tag value=\"text &lt; tag\"/>"
" <error-message>"
" <value>yin error message &lt;</value>\n"
" </error-message>\n"
"</range>"
"</type>"
"</typedef>"
"<leaf name=\"port\"> <type name=\"my_type\"/> </leaf>");
UTEST_ADD_MODULE(schema, LYS_IN_YIN, NULL, &mod);
assert_non_null(mod);
lysc_leaf = (void *)mod->compiled->data;
CHECK_LYSC_NODE_LEAF(lysc_leaf, NULL, 0, 0x5, 1, "port", 0, 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSC_TYPE_NUM((struct lysc_type_num *)lysc_leaf->type, LY_TYPE_INT16, 0, 1);
range = ((struct lysc_type_num *)lysc_leaf->type)->range;
CHECK_LYSC_RANGE(range, "percentage", "text < tag", "yin error message <", 0, 1, NULL);
lysp_leaf = (void *)mod->parsed->data;
CHECK_LYSP_NODE_LEAF(lysp_leaf, NULL, 0, 0x0, 0, "port", 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSP_TYPE(&(lysp_leaf->type), 0, 0, 0, 0, 0, 0x0, 0, 0, "my_type", 0, 0, 1, 0, 0, 0);
/* heredity new range */
schema = MODULE_CREATE_YIN("T2", "<typedef name=\"my_type\">"
"<type name=\"int32\">"
"<range value = \"0 .. 100\">"
" <description>"
" <text>percentage</text>\n"
" </description>\n"
" <error-app-tag value=\"text &lt; tag\"/>"
" <error-message>"
" <value>yin error message &lt;</value>\n"
" </error-message>\n"
" </range>"
" </type>"
"</typedef>"
"<leaf name=\"port\"> <type name=\"my_type\">"
" <range value = \"0 .. 50\"/>"
"</type></leaf>");
UTEST_ADD_MODULE(schema, LYS_IN_YIN, NULL, &mod);
assert_non_null(mod);
lysc_leaf = (void *)mod->compiled->data;
CHECK_LYSC_NODE_LEAF(lysc_leaf, NULL, 0, 0x5, 1, "port", 0, 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSC_TYPE_NUM((struct lysc_type_num *)lysc_leaf->type, LY_TYPE_INT32, 0, 1);
range = ((struct lysc_type_num *)lysc_leaf->type)->range;
CHECK_LYSC_RANGE(range, NULL, NULL, NULL, 0, 1, NULL);
lysp_leaf = (void *)mod->parsed->data;
CHECK_LYSP_NODE_LEAF(lysp_leaf, NULL, 0, 0x0, 0, "port", 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSP_TYPE(&(lysp_leaf->type), 0, 0, 0, 0, 0, 0x80, 0, 0, "my_type", 0, 0, 1, 1, 0, 0);
/* change */
schema = MODULE_CREATE_YIN("T3", "<typedef name=\"my_type\">"
"<type name=\"int32\">"
"<range value = \"0 .. 100\">"
" <description>"
" <text>percentage</text>\n"
" </description>\n"
" <error-app-tag value=\"text &lt; tag\"/>"
" <error-message>"
" <value>yin error message &lt;</value>\n"
" </error-message>\n"
" </range>"
" </type>"
"</typedef>"
"<leaf name=\"port\"> <type name=\"my_type\">"
" <range value = \"0 .. 50\">"
" <description>"
" <text>percentage 0-50</text>\n"
" </description>\n"
" <error-app-tag value=\"text tag 0-50\"/>"
" <error-message>"
" <value>yin error message 0-50</value>\n"
" </error-message>\n"
" </range>"
"</type></leaf>");
UTEST_ADD_MODULE(schema, LYS_IN_YIN, NULL, &mod);
assert_non_null(mod);
lysc_leaf = (void *)mod->compiled->data;
CHECK_LYSC_NODE_LEAF(lysc_leaf, NULL, 0, 0x5, 1, "port", 0, 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSC_TYPE_NUM((struct lysc_type_num *)lysc_leaf->type, LY_TYPE_INT32, 0, 1);
range = ((struct lysc_type_num *)lysc_leaf->type)->range;
CHECK_LYSC_RANGE(range, "percentage 0-50", "text tag 0-50", "yin error message 0-50", 0, 1, NULL);
lysp_leaf = (void *)mod->parsed->data;
CHECK_LYSP_NODE_LEAF(lysp_leaf, NULL, 0, 0x0, 0, "port", 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSP_TYPE(&(lysp_leaf->type), 0, 0, 0, 0, 0, 0x80, 0, 0, "my_type", 0, 0, 1, 1, 0, 0);
CHECK_LYSP_RESTR(lysp_leaf->type.range, "0 .. 50", "percentage 0-50", "text tag 0-50", "yin error message 0-50", 0, NULL);
}
static void
test_schema_print(void **state)
{
const char *schema_yang, *schema_yin;
char *printed;
struct lys_module *mod;
/* test print yang to yin */
schema_yang = MODULE_CREATE_YANG("PRINT0", "leaf port {type int32 {"
"range \"0 .. 50\"{"
"description \"desc < \";"
"error-app-tag \"err-apt-tag <\";"
"error-message \"error message <\";}}}");
schema_yin = MODULE_CREATE_YIN("PRINT0",
" <leaf name=\"port\">\n"
" <type name=\"int32\">\n"
" <range value=\"0 .. 50\">\n"
" <error-message>\n"
" <value>error message &lt;</value>\n"
" </error-message>\n"
" <error-app-tag value=\"err-apt-tag &lt;\"/>\n"
" <description>\n"
" <text>desc &lt; </text>\n"
" </description>\n"
" </range>\n"
" </type>\n"
" </leaf>\n");
UTEST_ADD_MODULE(schema_yang, LYS_IN_YANG, NULL, &mod);
assert_non_null(mod);
assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YIN, 0));
assert_string_equal(printed, schema_yin);
free(printed);
/* test print yin to yang */
schema_yang = MODULE_CREATE_YANG("PRINT1",
"\n"
" leaf port {\n"
" type int32 {\n"
" range \"0 .. 50\" {\n"
" error-message\n"
" \"error message <\";\n"
" error-app-tag \"err-apt-tag <\";\n"
" description\n"
" \"desc < \";\n"
" }\n"
" }\n"
" }\n");
schema_yin = MODULE_CREATE_YIN("PRINT1",
" <leaf name=\"port\">\n"
" <type name=\"int32\">\n"
" <range value=\"0 .. 50\">\n"
" <error-message>\n"
" <value>error message &lt;</value>\n"
" </error-message>\n"
" <error-app-tag value=\"err-apt-tag &lt;\"/>\n"
" <description>\n"
" <text>desc &lt; </text>\n"
" </description>\n"
" </range>\n"
" </type>\n"
" </leaf>\n");
UTEST_ADD_MODULE(schema_yin, LYS_IN_YIN, NULL, &mod);
assert_non_null(mod);
assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG, 0));
assert_string_equal(printed, schema_yang);
free(printed);
}
static void
test_data_xml(void **state)
{
const char *schema;
/* xml test */
schema = MODULE_CREATE_YANG("TRANGE_0", "leaf port {type int8 {"
"range \"0 .. 50 | 126\"{"
"description \"description test\";"
"error-app-tag \"err-apt-tag\";"
"error-message \"error message\";}}}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
/* test success */
TEST_SUCCESS_XML("TRANGE_0", "126", INT8, "126", 126);
/* test print error */
TEST_ERROR_XML("TRANGE_0", "-1");
CHECK_LOG_CTX("error message", "/TRANGE_0:port", 1);
TEST_ERROR_XML("TRANGE_0", "51");
CHECK_LOG_CTX("error message", "/TRANGE_0:port", 1);
TEST_ERROR_XML("TRANGE_0", "127");
CHECK_LOG_CTX("error message", "/TRANGE_0:port", 1);
/* xml test */
schema = MODULE_CREATE_YANG("TRANGE_1", "leaf port {type uint8 {"
"range \"30 .. 50 | 126\"{"
"description \"description test\";"
"error-app-tag \"err-apt-tag\";"
"error-message \"error message\";}}}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
/* test success */
TEST_SUCCESS_XML("TRANGE_1", "126", UINT8, "126", 126);
/* test print error */
TEST_ERROR_XML("TRANGE_1", "0");
CHECK_LOG_CTX("error message", "/TRANGE_1:port", 1);
TEST_ERROR_XML("TRANGE_1", "51");
CHECK_LOG_CTX("error message", "/TRANGE_1:port", 1);
TEST_ERROR_XML("TRANGE_1", "127");
CHECK_LOG_CTX("error message", "/TRANGE_1:port", 1);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_schema_yang),
UTEST(test_schema_yin),
UTEST(test_schema_print),
UTEST(test_data_xml),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

359
tests/utests/types/binary.c Normal file
View file

@ -0,0 +1,359 @@
/**
* @file binary.c
* @author Michal Vaško <mvasko@cesnet.cz>
* @brief test for built-in binary type
*
* Copyright (c) 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 UTEST HEADER */
#define _UTEST_MAIN_
#include "../utests.h"
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
#define MODULE_CREATE_YANG(MOD_NAME, NODES) \
"module " MOD_NAME " {\n" \
" yang-version 1.1;\n" \
" namespace \"urn:tests:" MOD_NAME "\";\n" \
" prefix pref;\n" \
NODES \
"}\n"
#define TEST_SUCCESS_LYB(MOD_NAME, NODE_NAME, DATA) \
{ \
struct lyd_node *tree_1; \
struct lyd_node *tree_2; \
char *xml_out, *data; \
data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, LY_SUCCESS, tree_1); \
assert_int_equal(lyd_print_mem(&xml_out, tree_1, LYD_LYB, LYD_PRINT_WITHSIBLINGS), 0); \
assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, xml_out, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
assert_non_null(tree_2); \
CHECK_LYD(tree_1, tree_2); \
free(xml_out); \
lyd_free_all(tree_1); \
lyd_free_all(tree_2); \
}
static void
test_plugin_store(void **state)
{
const char *val, *dec_val;
unsigned char bin_val[2];
struct ly_err_item *err = NULL;
struct lys_module *mod;
struct lyd_value value = {0};
struct lyplg_type *type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_BINARY]);
struct lysc_type *lysc_type, *lysc_type2;
LY_ERR ly_ret;
const char *schema;
/* create schema. Prepare common used variables */
schema = MODULE_CREATE_YANG("a", "leaf l {type binary;} leaf k {type binary {length 4..8;}}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
lysc_type = ((struct lysc_node_leaf *)mod->compiled->data)->type;
lysc_type2 = ((struct lysc_node_leaf *)mod->compiled->data->next)->type;
/* check proper type */
assert_string_equal("libyang 2 - binary, version 1", type->id);
/* check store XML double pad */
val = "YWhveQ==";
dec_val = "ahoy";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, val, strlen(val),
0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &value, NULL, &err));
CHECK_LYD_VALUE(value, BINARY, val, dec_val, strlen(dec_val));
assert_ptr_equal(value.realtype, lysc_type);
type->free(UTEST_LYCTX, &value);
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, dec_val, strlen(dec_val),
0, LY_VALUE_LYB, NULL, 0, NULL, &value, NULL, &err));
CHECK_LYD_VALUE(value, BINARY, val, dec_val, strlen(dec_val));
assert_ptr_equal(value.realtype, lysc_type);
type->free(UTEST_LYCTX, &value);
/* single pad */
val = "YWhveWo=";
dec_val = "ahoyj";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, val, strlen(val),
0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &value, NULL, &err));
CHECK_LYD_VALUE(value, BINARY, val, dec_val, strlen(dec_val));
assert_ptr_equal(value.realtype, lysc_type);
type->free(UTEST_LYCTX, &value);
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, dec_val, strlen(dec_val),
0, LY_VALUE_LYB, NULL, 0, NULL, &value, NULL, &err));
CHECK_LYD_VALUE(value, BINARY, val, dec_val, strlen(dec_val));
assert_ptr_equal(value.realtype, lysc_type);
type->free(UTEST_LYCTX, &value);
/* no pad */
val = "YWhveWoy";
dec_val = "ahoyj2";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, val, strlen(val),
0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &value, NULL, &err));
CHECK_LYD_VALUE(value, BINARY, val, dec_val, strlen(dec_val));
assert_ptr_equal(value.realtype, lysc_type);
type->free(UTEST_LYCTX, &value);
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, dec_val, strlen(dec_val),
0, LY_VALUE_LYB, NULL, 0, NULL, &value, NULL, &err));
CHECK_LYD_VALUE(value, BINARY, val, dec_val, strlen(dec_val));
assert_ptr_equal(value.realtype, lysc_type);
type->free(UTEST_LYCTX, &value);
/* binary data */
val = "q80=";
bin_val[0] = 0xab;
bin_val[1] = 0xcd;
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, val, strlen(val),
0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &value, NULL, &err));
CHECK_LYD_VALUE(value, BINARY, val, bin_val, 2);
assert_ptr_equal(value.realtype, lysc_type);
type->free(UTEST_LYCTX, &value);
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, bin_val, 2,
0, LY_VALUE_LYB, NULL, 0, NULL, &value, NULL, &err));
CHECK_LYD_VALUE(value, BINARY, val, bin_val, 2);
assert_ptr_equal(value.realtype, lysc_type);
type->free(UTEST_LYCTX, &value);
/* newlines after every 64 chars */
val = "MIIEAzCCAuugAwIBAgIURc4sipHvJSlNrQIhRhZilBvV4RowDQYJKoZIhvcNAQEL\n"
"BQAwgZAxCzAJBgNVBAYTAkNaMRYwFAYDVQQIDA1Tb3V0aCBNb3JhdmlhMQ0wCwYD\n"
"VQQHDARCcm5vMRgwFgYDVQQKDA9DRVNORVQgei5zLnAuby4xDDAKBgNVBAsMA1RN\n"
"QzETMBEGA1UEAwwKZXhhbXBsZSBDQTEdMBsGCSqGSIb3DQEJARYOY2FAZXhhbXBs\n"
"ZS5vcmcwHhcNMjEwOTAzMTAyMTAxWhcNMzEwOTAxMTAyMTAxWjCBkDELMAkGA1UE\n"
"BhMCQ1oxFjAUBgNVBAgMDVNvdXRoIE1vcmF2aWExDTALBgNVBAcMBEJybm8xGDAW\n"
"BgNVBAoMD0NFU05FVCB6LnMucC5vLjEMMAoGA1UECwwDVE1DMRMwEQYDVQQDDApl\n"
"eGFtcGxlIENBMR0wGwYJKoZIhvcNAQkBFg5jYUBleGFtcGxlLm9yZzCCASIwDQYJ\n"
"KoZIhvcNAQEBBQADggEPADCCAQoCggEBAN4Ld3JDDocyy9KXNJhEUPeZpQW3UdUN\n"
"Xloeh5n/bxasgThkBuQ7oF/nKyVUe517U1CJA993ZIc0jhIWThAnqXkz70DX5EZ7\n"
"ancPd01MidA6T8k1RYYJWr+vyIRYYBYzK7LSnU6wMWqPTgzZB+KMWwb065ooLEB5\n"
"XwqAeTIMPLRqM1Galewl4ZSuRJnrXxRjfF3AWNyC9dZw6wIg8cppvoLdBGQiFJQf\n"
"9SgiVy+HyedAytFEixqKAAIgQUJwhCgbEd6jGFbeaL8HT4MFp1VmaaUBQMkZj/Gn\n"
"KBwCk5BEMu76EN1pzHc4Dd6DabQNGCnsqOPe31yhQGmNFy9R6zNnWZMCAwEAAaNT\n"
"MFEwHQYDVR0OBBYEFM7w/pO8vk5oowvWPoCKo0RW/JcnMB8GA1UdIwQYMBaAFM7w\n"
"/pO8vk5oowvWPoCKo0RW/JcnMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL\n"
"BQADggEBAG/xfYuRKnCyiwYC/K7kAjHmCNnLCr1mx8P1ECsSJPme3OThDTNeGf8i\n"
"N2952tGmMFDa+DaAwPc6Gt3cWTb/NYMTLWlt2yj5rJAcLXxIU0SMafBf+F7E/R8A\n"
"b/HDDjs0pQaJ0EJhQJVkMdfj3Wq9l0dJT5iEBUrUQflDufiMdEJEIGKZh86MgzEL\n"
"bcn1QX8dlLc91M2OifWStqLzXPicG+jjuoPUceC0flMQDb2qx03sxvJKfYfS5ArA\n"
"CqvdWyXLoP7DI9THJrMI/vBHJKpl4Wtmsh2OLn9VHauFMzPSGke5GwjXCpbXGepj\n"
"9qWN8Gd/FWgSDH2OBvZ6aHdB1pPjN9k=";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, val, strlen(val),
0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &value, NULL, &err));
assert_ptr_equal(value.realtype, lysc_type);
type->free(UTEST_LYCTX, &value);
/* empty value */
val = "";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, val, strlen(val),
0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &value, NULL, &err));
CHECK_LYD_VALUE(value, BINARY, "", "", 0);
assert_ptr_equal(value.realtype, lysc_type);
type->free(UTEST_LYCTX, &value);
/* short value */
val = "YQ==";
dec_val = "a";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, val, strlen(val),
0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &value, NULL, &err));
CHECK_LYD_VALUE(value, BINARY, val, dec_val, strlen(dec_val));
assert_ptr_equal(value.realtype, lysc_type);
type->free(UTEST_LYCTX, &value);
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, dec_val, strlen(dec_val),
0, LY_VALUE_LYB, NULL, 0, NULL, &value, NULL, &err));
CHECK_LYD_VALUE(value, BINARY, val, dec_val, strlen(dec_val));
assert_ptr_equal(value.realtype, lysc_type);
type->free(UTEST_LYCTX, &value);
/* length check */
val = "Zm91cg==";
dec_val = "four";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type2, val, strlen(val),
0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &value, NULL, &err));
CHECK_LYD_VALUE(value, BINARY, val, dec_val, strlen(dec_val));
assert_ptr_equal(value.realtype, lysc_type2);
type->free(UTEST_LYCTX, &value);
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type2, dec_val, strlen(dec_val),
0, LY_VALUE_LYB, NULL, 0, NULL, &value, NULL, &err));
CHECK_LYD_VALUE(value, BINARY, val, dec_val, strlen(dec_val));
assert_ptr_equal(value.realtype, lysc_type2);
type->free(UTEST_LYCTX, &value);
val = "ZWlnaHQwMTI=";
dec_val = "eight012";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type2, val, strlen(val),
0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &value, NULL, &err));
CHECK_LYD_VALUE(value, BINARY, val, dec_val, strlen(dec_val));
assert_ptr_equal(value.realtype, lysc_type2);
type->free(UTEST_LYCTX, &value);
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type2, dec_val, strlen(dec_val),
0, LY_VALUE_LYB, NULL, 0, NULL, &value, NULL, &err));
CHECK_LYD_VALUE(value, BINARY, val, dec_val, strlen(dec_val));
assert_ptr_equal(value.realtype, lysc_type2);
type->free(UTEST_LYCTX, &value);
/*
* ERROR TESTS
*/
val = "q80.";
err = NULL;
ly_ret = type->store(UTEST_LYCTX, lysc_type, val, strlen(val),
0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &value, NULL, &err);
assert_int_equal(LY_EVALID, ly_ret);
assert_string_equal(err->msg, "Invalid Base64 character '.'.");
ly_err_free(err);
val = "q80";
err = NULL;
ly_ret = type->store(UTEST_LYCTX, lysc_type, val, strlen(val),
0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &value, NULL, &err);
assert_int_equal(LY_EVALID, ly_ret);
assert_string_equal(err->msg, "Base64 encoded value length must be divisible by 4.");
ly_err_free(err);
val = "MTIz";
err = NULL;
ly_ret = type->store(UTEST_LYCTX, lysc_type2, val, strlen(val),
0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &value, NULL, &err);
assert_int_equal(LY_EVALID, ly_ret);
assert_string_equal(err->msg, "Unsatisfied length - string \"MTIz\" length is not allowed.");
ly_err_free(err);
/* LYPLG_TYPE_STORE_ONLY test */
val = "MTIz";
err = NULL;
ly_ret = type->store(UTEST_LYCTX, lysc_type2, val, strlen(val),
LYPLG_TYPE_STORE_ONLY, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &value, NULL, &err);
assert_int_equal(LY_SUCCESS, ly_ret);
type->free(UTEST_LYCTX, &value);
ly_err_free(err);
}
static void
test_plugin_print(void **state)
{
const char *schema, *val;
struct lyd_value value = {0};
struct lys_module *mod;
struct lysc_type *lysc_type;
struct lyplg_type *type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_BINARY]);
struct ly_err_item *err = NULL;
/* create schema. Prepare common used variables */
schema = MODULE_CREATE_YANG("a", "leaf l {type binary;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
lysc_type = ((struct lysc_node_leaf *)mod->compiled->data)->type;
/* Testing empty value. */
val = "";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, val, strlen(val),
0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &value, NULL, &err));
assert_string_equal("", value.realtype->plugin->print(UTEST_LYCTX, &(value), LY_VALUE_CANON, NULL, NULL, NULL));
type->free(UTEST_LYCTX, &value);
}
static void
test_plugin_duplicate(void **state)
{
const char *schema, *val;
struct lyd_value value = {0}, dup;
struct lys_module *mod;
struct lysc_type *lysc_type;
struct lyplg_type *type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_BINARY]);
struct ly_err_item *err = NULL;
/* create schema. Prepare common used variables */
schema = MODULE_CREATE_YANG("a", "leaf l {type binary;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
lysc_type = ((struct lysc_node_leaf *)mod->compiled->data)->type;
/* Testing empty value. */
val = "";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, val, strlen(val),
0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &value, NULL, &err));
assert_int_equal(LY_SUCCESS, type->duplicate(UTEST_LYCTX, &value, &dup));
CHECK_LYD_VALUE(dup, BINARY, "", "", 0);
type->free(UTEST_LYCTX, &value);
type->free(UTEST_LYCTX, &dup);
}
static void
test_plugin_sort(void **state)
{
const char *v1, *v2;
const char *schema;
struct lys_module *mod;
struct lyd_value val1 = {0}, val2 = {0};
struct lyplg_type *type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_BINARY]);
struct lysc_type *lysc_type;
struct ly_err_item *err = NULL;
/* create schema. Prepare common used variables */
schema = MODULE_CREATE_YANG("a", "leaf-list ll {type binary;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
lysc_type = ((struct lysc_node_leaflist *)mod->compiled->data)->type;
/* v1 < v2, v2 > v1, v1 == v1 */
v1 = "YWhveQ=="; /* ahoy */
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
v2 = "YWhveg=="; /* ahoz */
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
assert_true(0 > type->sort(UTEST_LYCTX, &val1, &val2));
assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val1));
assert_true(0 < type->sort(UTEST_LYCTX, &val2, &val1));
type->free(UTEST_LYCTX, &val1);
type->free(UTEST_LYCTX, &val2);
/* v2 is shorter */
v1 = "YWhveQ=="; /* ahoj */
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
v2 = "YWhv"; /* aho */
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
assert_true(0 < type->sort(UTEST_LYCTX, &val1, &val2));
assert_true(0 > type->sort(UTEST_LYCTX, &val2, &val1));
type->free(UTEST_LYCTX, &val1);
type->free(UTEST_LYCTX, &val2);
}
static void
test_data_lyb(void **state)
{
const char *schema;
schema = MODULE_CREATE_YANG("lyb", "leaf port {type binary;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
TEST_SUCCESS_LYB("lyb", "port", "");
TEST_SUCCESS_LYB("lyb", "port", "YWhveQ==");
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_plugin_store),
UTEST(test_plugin_print),
UTEST(test_plugin_duplicate),
UTEST(test_plugin_sort),
UTEST(test_data_lyb),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

1121
tests/utests/types/bits.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,109 @@
/**
* @file boolean.c
* @author Adam Piecek <piecek@cesnet.cz>
* @brief test for built-in enumeration type
*
* Copyright (c) 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 UTEST HEADER */
#define _UTEST_MAIN_
#include "../utests.h"
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
#define MODULE_CREATE_YANG(MOD_NAME, NODES) \
"module " MOD_NAME " {\n" \
" yang-version 1.1;\n" \
" namespace \"urn:tests:" MOD_NAME "\";\n" \
" prefix pref;\n" \
NODES \
"}\n"
#define TEST_SUCCESS_XML(MOD_NAME, NODE_NAME, DATA, TYPE, ...) \
{ \
struct lyd_node *tree; \
const char *data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree); \
CHECK_LYD_NODE_TERM((struct lyd_node_term *)tree, 0, 0, 0, 0, 1, TYPE, __VA_ARGS__); \
lyd_free_all(tree); \
}
#define TEST_ERROR_XML(MOD_NAME, NODE_NAME, DATA) \
{\
struct lyd_node *tree; \
const char *data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); \
assert_null(tree); \
}
#define TEST_SUCCESS_LYB(MOD_NAME, NODE_NAME, DATA) \
{ \
struct lyd_node *tree_1; \
struct lyd_node *tree_2; \
char *xml_out, *data; \
data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, LY_SUCCESS, tree_1); \
assert_int_equal(lyd_print_mem(&xml_out, tree_1, LYD_LYB, LYD_PRINT_WITHSIBLINGS), 0); \
assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, xml_out, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
assert_non_null(tree_2); \
CHECK_LYD(tree_1, tree_2); \
free(xml_out); \
lyd_free_all(tree_1); \
lyd_free_all(tree_2); \
}
static void
test_data_xml(void **state)
{
const char *schema;
/* xml test */
schema = MODULE_CREATE_YANG("defs", "typedef tboolean {type boolean;}"
"leaf l1 {type boolean;}"
"leaf l2 {type tboolean;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
TEST_SUCCESS_XML("defs", "l1", "true", BOOL, "true", 1);
TEST_SUCCESS_XML("defs", "l1", "false", BOOL, "false", 0);
TEST_SUCCESS_XML("defs", "l2", "false", BOOL, "false", 0);
/* invalid value */
TEST_ERROR_XML("defs", "l1", "unsure");
CHECK_LOG_CTX("Invalid boolean value \"unsure\".", "/defs:l1", 1);
TEST_ERROR_XML("defs", "l1", " true");
CHECK_LOG_CTX("Invalid boolean value \" true\".", "/defs:l1", 1);
}
static void
test_plugin_lyb(void **state)
{
const char *schema;
schema = MODULE_CREATE_YANG("lyb",
"leaf bool {type boolean;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
TEST_SUCCESS_LYB("lyb", "bool", "true");
TEST_SUCCESS_LYB("lyb", "bool", "false");
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_data_xml),
UTEST(test_plugin_lyb),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

View file

@ -0,0 +1,130 @@
/**
* @file decimal64.c
* @author Adam Piecek <piecek@cesnet.cz>
* @brief test for built-in enumeration type
*
* Copyright (c) 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 UTEST HEADER */
#define _UTEST_MAIN_
#include "../utests.h"
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
#define MODULE_CREATE_YANG(MOD_NAME, NODES) \
"module " MOD_NAME " {\n" \
" yang-version 1.1;\n" \
" namespace \"urn:tests:" MOD_NAME "\";\n" \
" prefix pref;\n" \
NODES \
"}\n"
#define TEST_SUCCESS_XML(MOD_NAME, NODE_NAME, DATA, TYPE, ...) \
{ \
struct lyd_node *tree; \
const char *data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree); \
CHECK_LYD_NODE_TERM((struct lyd_node_term *)tree, 0, 0, 0, 0, 1, TYPE, __VA_ARGS__); \
lyd_free_all(tree); \
}
#define TEST_ERROR_XML(MOD_NAME, NODE_NAME, DATA) \
{\
struct lyd_node *tree; \
const char *data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); \
assert_null(tree); \
}
#define TEST_SUCCESS_LYB(MOD_NAME, NODE_NAME, DATA) \
{ \
struct lyd_node *tree_1; \
struct lyd_node *tree_2; \
char *xml_out, *data; \
data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, LY_SUCCESS, tree_1); \
assert_int_equal(lyd_print_mem(&xml_out, tree_1, LYD_LYB, LYD_PRINT_WITHSIBLINGS), 0); \
assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, xml_out, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
assert_non_null(tree_2); \
CHECK_LYD(tree_1, tree_2); \
free(xml_out); \
lyd_free_all(tree_1); \
lyd_free_all(tree_2); \
}
#define TEST_SUCCESS_PARSE_STORE_ONLY_XML(MOD_NAME, NODE_NAME, DATA) \
{\
struct lyd_node *tree; \
const char *data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_STORE_ONLY, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree); \
lyd_free_all(tree); \
}
static void
test_data_xml(void **state)
{
const char *schema;
/* xml test */
schema = MODULE_CREATE_YANG("defs", "leaf l1 {type decimal64 {fraction-digits 1; range 1.5..10;}}"
"leaf l2 {type decimal64 {fraction-digits 18;}}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
TEST_SUCCESS_XML("defs", "l1", "\n +8 \t\n ", DEC64, "8.0", 80);
TEST_SUCCESS_XML("defs", "l1", "8.00", DEC64, "8.0", 80);
TEST_SUCCESS_XML("defs", "l2", "-9.223372036854775808", DEC64, "-9.223372036854775808",
INT64_C(-9223372036854775807) - INT64_C(1));
TEST_SUCCESS_XML("defs", "l2", "9.223372036854775807", DEC64, "9.223372036854775807", INT64_C(9223372036854775807));
TEST_ERROR_XML("defs", "l1", "\n 15 \t\n ");
CHECK_LOG_CTX("Unsatisfied range - value \"15.0\" is out of the allowed range.", "/defs:l1", 3);
TEST_ERROR_XML("defs", "l1", "\n 0 \t\n ");
CHECK_LOG_CTX("Unsatisfied range - value \"0.0\" is out of the allowed range.", "/defs:l1", 3);
TEST_ERROR_XML("defs", "l1", "xxx");
CHECK_LOG_CTX("Invalid 1. character of decimal64 value \"xxx\".", "/defs:l1", 1);
TEST_ERROR_XML("defs", "l1", "");
CHECK_LOG_CTX("Invalid empty decimal64 value.", "/defs:l1", 1);
TEST_ERROR_XML("defs", "l1", "8.5 xxx");
CHECK_LOG_CTX("Invalid 6. character of decimal64 value \"8.5 xxx\".", "/defs:l1", 1);
TEST_ERROR_XML("defs", "l1", "8.55 xxx");
CHECK_LOG_CTX("Value \"8.55\" of decimal64 type exceeds defined number (1) of fraction digits.", "/defs:l1", 1);
/* LYPLG_TYPE_STORE_ONLY test */
TEST_SUCCESS_PARSE_STORE_ONLY_XML("defs", "l1", "\n 15 \t\n ");
}
static void
test_plugin_lyb(void **state)
{
const char *schema;
schema = MODULE_CREATE_YANG("lyb",
"leaf dec64 {type decimal64 {fraction-digits 1; range 1.5..10;}}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
TEST_SUCCESS_LYB("lyb", "dec64", "8.00");
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_data_xml),
UTEST(test_plugin_lyb),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

106
tests/utests/types/empty.c Normal file
View file

@ -0,0 +1,106 @@
/**
* @file empty.c
* @author Adam Piecek <piecek@cesnet.cz>
* @brief test for built-in enumeration type
*
* Copyright (c) 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 UTEST HEADER */
#define _UTEST_MAIN_
#include "../utests.h"
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
#define MODULE_CREATE_YANG(MOD_NAME, NODES) \
"module " MOD_NAME " {\n" \
" yang-version 1.1;\n" \
" namespace \"urn:tests:" MOD_NAME "\";\n" \
" prefix pref;\n" \
NODES \
"}\n"
#define TEST_SUCCESS_XML(MOD_NAME, NODE_NAME, DATA, TYPE, ...) \
{ \
struct lyd_node *tree; \
const char *data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree); \
CHECK_LYD_NODE_TERM((struct lyd_node_term *)tree, 0, 0, 0, 0, 1, TYPE, __VA_ARGS__); \
lyd_free_all(tree); \
}
#define TEST_ERROR_XML(MOD_NAME, NODE_NAME, DATA) \
{\
struct lyd_node *tree; \
const char *data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); \
assert_null(tree); \
}
#define TEST_SUCCESS_LYB(MOD_NAME, NODE_NAME, DATA) \
{ \
struct lyd_node *tree_1; \
struct lyd_node *tree_2; \
char *xml_out, *data; \
data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, LY_SUCCESS, tree_1); \
assert_int_equal(lyd_print_mem(&xml_out, tree_1, LYD_LYB, LYD_PRINT_WITHSIBLINGS), 0); \
assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, xml_out, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
assert_non_null(tree_2); \
CHECK_LYD(tree_1, tree_2); \
free(xml_out); \
lyd_free_all(tree_1); \
lyd_free_all(tree_2); \
}
static void
test_data_xml(void **state)
{
const char *schema;
/* xml test */
schema = MODULE_CREATE_YANG("defs", "typedef tempty {type empty;}"
"leaf l1 {type empty;}"
"leaf l2 {type tempty;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
TEST_SUCCESS_XML("defs", "l1", "", EMPTY, "");
TEST_SUCCESS_XML("defs", "l2", "", EMPTY, "");
/* invalid value */
TEST_ERROR_XML("defs", "l1", "x");
CHECK_LOG_CTX("Invalid empty value length 1.", "/defs:l1", 1);
TEST_ERROR_XML("defs", "l1", " ");
CHECK_LOG_CTX("Invalid empty value length 1.", "/defs:l1", 1);
}
static void
test_plugin_lyb(void **state)
{
const char *schema;
schema = MODULE_CREATE_YANG("lyb",
"leaf empty {type empty;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
TEST_SUCCESS_LYB("lyb", "empty", "");
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_data_xml),
UTEST(test_plugin_lyb),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

View file

@ -0,0 +1,140 @@
/**
* @file enumeration.c
* @author Adam Piecek <piecek@cesnet.cz>
* @brief test for built-in enumeration type
*
* Copyright (c) 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 UTEST HEADER */
#define _UTEST_MAIN_
#include "../utests.h"
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
#define MODULE_CREATE_YANG(MOD_NAME, NODES) \
"module " MOD_NAME " {\n" \
" yang-version 1.1;\n" \
" namespace \"urn:tests:" MOD_NAME "\";\n" \
" prefix pref;\n" \
NODES \
"}\n"
#define TEST_SUCCESS_XML(MOD_NAME, NODE_NAME, DATA, TYPE, ...) \
{ \
struct lyd_node *tree; \
const char *data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree); \
CHECK_LYD_NODE_TERM((struct lyd_node_term *)tree, 0, 0, 0, 0, 1, TYPE, __VA_ARGS__); \
lyd_free_all(tree); \
}
#define TEST_ERROR_XML(MOD_NAME, NODE_NAME, DATA) \
{\
struct lyd_node *tree; \
const char *data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); \
assert_null(tree); \
}
#define TEST_SUCCESS_LYB(MOD_NAME, NODE_NAME, DATA) \
{ \
struct lyd_node *tree_1; \
struct lyd_node *tree_2; \
char *xml_out, *data; \
data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, LY_SUCCESS, tree_1); \
assert_int_equal(lyd_print_mem(&xml_out, tree_1, LYD_LYB, LYD_PRINT_WITHSIBLINGS), 0); \
assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, xml_out, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
assert_non_null(tree_2); \
CHECK_LYD(tree_1, tree_2); \
free(xml_out); \
lyd_free_all(tree_1); \
lyd_free_all(tree_2); \
}
static void
test_data_xml(void **state)
{
const char *schema;
/* xml test */
schema = MODULE_CREATE_YANG("defs", "feature f; leaf l1 {type enumeration {enum white; enum yellow {if-feature f;}}}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
TEST_SUCCESS_XML("defs", "l1", "white", ENUM, "white", "white");
/* disabled feature */
TEST_ERROR_XML("defs", "l1", "yellow");
CHECK_LOG_CTX("Invalid enumeration value \"yellow\".", "/defs:l1", 1);
/* leading/trailing whitespaces */
TEST_ERROR_XML("defs", "l1", " white");
CHECK_LOG_CTX("Invalid enumeration value \" white\".", "/defs:l1", 1);
TEST_ERROR_XML("defs", "l1", "white\n");
CHECK_LOG_CTX("Invalid enumeration value \"white\n\".", "/defs:l1", 2);
/* invalid value */
TEST_ERROR_XML("defs", "l1", "black");
CHECK_LOG_CTX("Invalid enumeration value \"black\".", "/defs:l1", 1);
}
static void
test_plugin_sort(void **state)
{
const char *v1, *v2;
const char *schema;
struct lys_module *mod;
struct lyd_value val1 = {0}, val2 = {0};
struct lyplg_type *type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_ENUM]);
struct lysc_type *lysc_type;
struct ly_err_item *err = NULL;
schema = MODULE_CREATE_YANG("sort", "leaf l1 {type enumeration {enum white; enum yellow; enum black;}}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
lysc_type = ((struct lysc_node_leaf *)mod->compiled->data)->type;
v1 = "white";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
v2 = "black";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
assert_true(0 < type->sort(UTEST_LYCTX, &val1, &val2));
assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val1));
assert_true(0 > type->sort(UTEST_LYCTX, &val2, &val1));
type->free(UTEST_LYCTX, &val1);
type->free(UTEST_LYCTX, &val2);
}
static void
test_plugin_lyb(void **state)
{
const char *schema;
schema = MODULE_CREATE_YANG("lyb", "leaf l1 {type enumeration {enum white; enum yellow; enum black;}}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
TEST_SUCCESS_LYB("lyb", "l1", "white");
TEST_SUCCESS_LYB("lyb", "l1", "black");
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_data_xml),
UTEST(test_data_xml),
UTEST(test_plugin_sort),
UTEST(test_plugin_lyb),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

View file

@ -0,0 +1,134 @@
/**
* @file identityref.c
* @author Adam Piecek <piecek@cesnet.cz>
* @brief test for built-in enumeration type
*
* Copyright (c) 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 UTEST HEADER */
#define _UTEST_MAIN_
#include "../utests.h"
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
#define MODULE_CREATE_YANG(MOD_NAME, NODES) \
"module " MOD_NAME " {\n" \
" yang-version 1.1;\n" \
" namespace \"urn:tests:" MOD_NAME "\";\n" \
" prefix pref;\n" \
NODES \
"}\n"
#define TEST_ERROR_XML(MOD_NAME, NAMESPACES, NODE_NAME, DATA) \
{\
struct lyd_node *tree; \
const char *data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\" " NAMESPACES ">" DATA "</" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); \
assert_null(tree); \
}
#define TEST_SUCCESS_LYB(MOD_NAME, NODE_NAME, DATA) \
{ \
struct lyd_node *tree_1; \
struct lyd_node *tree_2; \
char *xml_out, *data; \
data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, LY_SUCCESS, tree_1); \
assert_int_equal(lyd_print_mem(&xml_out, tree_1, LYD_LYB, LYD_PRINT_WITHSIBLINGS), 0); \
assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, xml_out, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
assert_non_null(tree_2); \
CHECK_LYD(tree_1, tree_2); \
free(xml_out); \
lyd_free_all(tree_1); \
lyd_free_all(tree_2); \
}
static void
test_data_xml(void **state)
{
const char *schema, *schema2;
struct lyd_node *tree;
const char *data;
/* xml test */
schema = "module ident-base {"
" yang-version 1.1;"
" namespace \"urn:tests:ident-base\";"
" prefix ib;"
" identity ident-base;"
" identity ident-imp {base ident-base;}"
"}";
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
schema2 = "module defs {"
" yang-version 1.1;"
" namespace \"urn:tests:defs\";"
" prefix d;"
" import ident-base {prefix ib;}"
" identity ident1 {base ib:ident-base;}"
" leaf l1 {type identityref {base ib:ident-base;}}"
"}";
UTEST_ADD_MODULE(schema2, LYS_IN_YANG, NULL, NULL);
/* local ident, XML/JSON print */
data = "<l1 xmlns=\"urn:tests:defs\">ident1</l1>";
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
CHECK_LYD_NODE_TERM((struct lyd_node_term *)tree, 0, 0, 0, 0, 1, IDENT, "defs:ident1", "ident1");
CHECK_LYD_STRING_PARAM(tree, data, LYD_XML, LYD_PRINT_SHRINK);
CHECK_LYD_STRING_PARAM(tree, "{\"defs:l1\":\"ident1\"}", LYD_JSON, LYD_PRINT_SHRINK);
lyd_free_all(tree);
/* foreign ident, XML/JSON print */
data = "<l1 xmlns=\"urn:tests:defs\" xmlns:ib=\"urn:tests:ident-base\">ib:ident-imp</l1>";
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
CHECK_LYD_NODE_TERM((struct lyd_node_term *)tree, 0, 0, 0, 0, 1, IDENT, "ident-base:ident-imp", "ident-imp");
CHECK_LYD_STRING_PARAM(tree, data, LYD_XML, LYD_PRINT_SHRINK);
CHECK_LYD_STRING_PARAM(tree, "{\"defs:l1\":\"ident-base:ident-imp\"}", LYD_JSON, LYD_PRINT_SHRINK);
lyd_free_all(tree);
/* invalid value */
TEST_ERROR_XML("defs", "", "l1", "fast-ethernet");
CHECK_LOG_CTX("Invalid identityref \"fast-ethernet\" value - identity not found in module \"defs\".", "/defs:l1", 1);
TEST_ERROR_XML("defs", "xmlns:x=\"urn:tests:defs\"", "l1", "x:slow-ethernet");
CHECK_LOG_CTX("Invalid identityref \"x:slow-ethernet\" value - identity not found in module \"defs\".", "/defs:l1", 1);
TEST_ERROR_XML("defs", "xmlns:x=\"urn:tests:ident-base\"", "l1", "x:ident-base");
CHECK_LOG_CTX("Invalid identityref \"x:ident-base\" value - identity not derived from the base \"ident-base:ident-base\".",
"/defs:l1", 1);
TEST_ERROR_XML("defs", "xmlns:x=\"urn:tests:unknown\"", "l1", "x:ident-base");
CHECK_LOG_CTX("Invalid identityref \"x:ident-base\" value - unable to map prefix to YANG schema.", "/defs:l1", 1);
}
static void
test_plugin_lyb(void **state)
{
const char *schema;
schema = MODULE_CREATE_YANG("lyb",
"identity idbase;"
"identity ident {base idbase;}"
"leaf lf {type identityref {base idbase;}}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
TEST_SUCCESS_LYB("lyb", "lf", "ident");
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_data_xml),
UTEST(test_plugin_lyb),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

View file

@ -0,0 +1,337 @@
/**
* @file inet_types.c
* @author Michal Vaško <mvasko@cesnet.cz>
* @brief test for ietf-inet-types values
*
* Copyright (c) 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 UTEST HEADER */
#define _UTEST_MAIN_
#include "../utests.h"
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
#define MODULE_CREATE_YIN(MOD_NAME, NODES) \
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" \
"<module name=\"" MOD_NAME "\"\n" \
" xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"\n" \
" xmlns:pref=\"urn:tests:" MOD_NAME "\">\n" \
" <yang-version value=\"1.1\"/>\n" \
" <namespace uri=\"urn:tests:" MOD_NAME "\"/>\n" \
" <prefix value=\"pref\"/>\n" \
NODES \
"</module>\n"
#define MODULE_CREATE_YANG(MOD_NAME, NODES) \
"module " MOD_NAME " {\n" \
" yang-version 1.1;\n" \
" namespace \"urn:tests:" MOD_NAME "\";\n" \
" prefix pref;\n" \
" import ietf-inet-types {\n" \
" prefix inet;\n" \
" }\n" \
NODES \
"}\n"
#define TEST_SUCCESS_XML(MOD_NAME, NODE_NAME, DATA, TYPE, ...) \
{ \
struct lyd_node *tree; \
const char *data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree); \
CHECK_LYD_NODE_TERM((struct lyd_node_term *)tree, 0, 0, 0, 0, 1, TYPE, __VA_ARGS__); \
lyd_free_all(tree); \
}
#define TEST_ERROR_XML(MOD_NAME, NODE_NAME, DATA) \
{ \
struct lyd_node *tree; \
const char *data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); \
assert_null(tree); \
}
#define TEST_SUCCESS_PARSE_STORE_ONLY_XML(MOD_NAME, NODE_NAME, DATA, TYPE, ...) \
{ \
struct lyd_node *tree; \
const char *data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STORE_ONLY, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree); \
CHECK_LYD_NODE_TERM((struct lyd_node_term *)tree, 4, 0, 0, 0, 1, TYPE, __VA_ARGS__); \
lyd_free_all(tree); \
}
#define TEST_ERROR_PARSE_STORE_ONLY_XML(MOD_NAME, NODE_NAME, DATA) \
{ \
struct lyd_node *tree; \
const char *data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STORE_ONLY, LYD_VALIDATE_PRESENT, LY_EVALID, tree); \
assert_null(tree); \
}
#define TEST_SUCCESS_LYB(MOD_NAME, NODE_NAME, DATA) \
{ \
struct lyd_node *tree_1; \
struct lyd_node *tree_2; \
char *xml_out, *data; \
data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, LY_SUCCESS, tree_1); \
assert_int_equal(lyd_print_mem(&xml_out, tree_1, LYD_LYB, LYD_PRINT_WITHSIBLINGS), 0); \
assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, xml_out, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
assert_non_null(tree_2); \
CHECK_LYD(tree_1, tree_2); \
free(xml_out); \
lyd_free_all(tree_1); \
lyd_free_all(tree_2); \
}
static void
test_data_xml(void **state)
{
const char *schema;
/* xml test */
schema = MODULE_CREATE_YANG("a",
"leaf l {type inet:ip-address;}"
"leaf l2 {type inet:ipv6-address;}"
"leaf l3 {type inet:ip-address-no-zone;}"
"leaf l4 {type inet:ipv6-address-no-zone;}"
"leaf l5 {type inet:ip-prefix;}"
"leaf l6 {type inet:ipv4-prefix;}"
"leaf l7 {type inet:ipv6-prefix;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
/* ip-address */
TEST_SUCCESS_XML("a", "l", "192.168.0.1", UNION, "192.168.0.1", STRING, "192.168.0.1");
TEST_SUCCESS_XML("a", "l", "192.168.0.1%12", UNION, "192.168.0.1%12", STRING, "192.168.0.1%12");
TEST_SUCCESS_XML("a", "l", "2008:15:0:0:0:0:feAC:1", UNION, "2008:15::feac:1", STRING, "2008:15::feac:1");
/* ipv6-address */
TEST_SUCCESS_XML("a", "l2", "FAAC:21:011:Da85::87:daaF%1", STRING, "faac:21:11:da85::87:daaf%1");
/* ip-address-no-zone */
TEST_SUCCESS_XML("a", "l3", "127.0.0.1", UNION, "127.0.0.1", STRING, "127.0.0.1");
TEST_SUCCESS_XML("a", "l3", "0:00:000:0000:000:00:0:1", UNION, "::1", STRING, "::1");
/* ipv6-address-no-zone */
TEST_SUCCESS_XML("a", "l4", "A:B:c:D:e:f:1:0", STRING, "a:b:c:d:e:f:1:0");
/* ip-prefix */
TEST_SUCCESS_XML("a", "l5", "158.1.58.4/1", UNION, "128.0.0.0/1", STRING, "128.0.0.0/1");
TEST_SUCCESS_XML("a", "l5", "158.1.58.4/24", UNION, "158.1.58.0/24", STRING, "158.1.58.0/24");
TEST_SUCCESS_XML("a", "l5", "2000:A:B:C:D:E:f:a/16", UNION, "2000::/16", STRING, "2000::/16");
/* ipv4-prefix */
TEST_SUCCESS_XML("a", "l6", "0.1.58.4/32", STRING, "0.1.58.4/32");
TEST_SUCCESS_XML("a", "l6", "12.1.58.4/8", STRING, "12.0.0.0/8");
/* ipv6-prefix */
TEST_SUCCESS_XML("a", "l7", "::C:D:E:f:a/112", STRING, "::c:d:e:f:0/112");
TEST_SUCCESS_XML("a", "l7", "::C:D:E:f:a/110", STRING, "::c:d:e:c:0/110");
TEST_SUCCESS_XML("a", "l7", "::C:D:E:f:a/96", STRING, "::c:d:e:0:0/96");
TEST_SUCCESS_XML("a", "l7", "::C:D:E:f:a/55", STRING, "::/55");
}
static void
test_data_basic_plugins_only_xml(void **state)
{
const char *schema;
schema = MODULE_CREATE_YANG("a", "leaf l {type inet:ipv4-address;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
/* Stored via ipv4-address plugin */
TEST_SUCCESS_XML("a", "l", "192.168.0.1", STRING, "192.168.0.1");
TEST_ERROR_XML("a", "l", "192.168.0.333");
TEST_ERROR_PARSE_STORE_ONLY_XML("a", "l", "192.168.0.333");
/* Recreate context to get rid of all plugins */
ly_ctx_destroy(UTEST_LYCTX);
assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, LY_CTX_BUILTIN_PLUGINS_ONLY, &UTEST_LYCTX));
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
/* Stored via string plugin */
TEST_SUCCESS_XML("a", "l", "192.168.0.1", STRING, "192.168.0.1");
TEST_ERROR_XML("a", "l", "192.168.0.333");
CHECK_LOG_CTX("Unsatisfied pattern - \"192.168.0.333\" does not conform to \""
"(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9]"
"[0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(%[\\p{N}\\p{L}]+)?\".", "/a:l", 1);
TEST_SUCCESS_PARSE_STORE_ONLY_XML("a", "l", "192.168.0.333", STRING, "192.168.0.333");
}
static void
test_data_lyb(void **state)
{
const char *schema;
schema = MODULE_CREATE_YANG("lyb",
"leaf l {type inet:ip-address;}"
"leaf l2 {type inet:ipv6-address;}"
"leaf l3 {type inet:ip-address-no-zone;}"
"leaf l4 {type inet:ipv6-address-no-zone;}"
"leaf l5 {type inet:ip-prefix;}"
"leaf l6 {type inet:ipv4-prefix;}"
"leaf l7 {type inet:ipv6-prefix;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
TEST_SUCCESS_LYB("lyb", "l", "192.168.0.1");
TEST_SUCCESS_LYB("lyb", "l2", "FAAC:21:011:Da85::87:daaF%1");
TEST_SUCCESS_LYB("lyb", "l3", "127.0.0.1");
TEST_SUCCESS_LYB("lyb", "l4", "A:B:c:D:e:f:1:0");
TEST_SUCCESS_LYB("lyb", "l5", "158.1.58.4/1");
TEST_SUCCESS_LYB("lyb", "l6", "12.1.58.4/8");
TEST_SUCCESS_LYB("lyb", "l7", "::C:D:E:f:a/112");
}
static void
test_plugin_sort(void **state)
{
const char *v1, *v2;
const char *schema;
struct lys_module *mod;
struct lyd_value val1 = {0}, val2 = {0};
struct lyplg_type *type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_UNION]);
struct lysc_type *lysc_type;
struct ly_err_item *err = NULL;
schema = MODULE_CREATE_YANG("a",
"leaf l {type inet:ip-address;}"
"leaf l2 {type inet:ipv6-address;}"
"leaf l3 {type inet:ip-address-no-zone;}"
"leaf l4 {type inet:ipv6-address-no-zone;}"
"leaf l5 {type inet:ipv4-prefix;}"
"leaf l6 {type inet:ipv6-prefix;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
/* ipv4-address */
lysc_type = ((struct lysc_node_leaf *)mod->compiled->data)->type;
v1 = "192.168.0.1";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
v2 = "192.168.0.2";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
assert_true(0 > type->sort(UTEST_LYCTX, &val1, &val2));
assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val1));
assert_true(0 < type->sort(UTEST_LYCTX, &val2, &val1));
type->free(UTEST_LYCTX, &val1);
type->free(UTEST_LYCTX, &val2);
v1 = "192.168.0.1%1A";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
v2 = "192.168.0.1";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
assert_true(0 < type->sort(UTEST_LYCTX, &val1, &val2));
assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val1));
assert_true(0 > type->sort(UTEST_LYCTX, &val2, &val1));
type->free(UTEST_LYCTX, &val1);
type->free(UTEST_LYCTX, &val2);
/* ipv6-address */
lysc_type = ((struct lysc_node_leaflist *)mod->compiled->data->next)->type;
type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_STRING]);
v1 = "2008:15:0:0:0:0:feAC:1";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
v2 = "2008:15::feac:2";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
assert_true(0 > type->sort(UTEST_LYCTX, &val1, &val2));
assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val1));
assert_true(0 < type->sort(UTEST_LYCTX, &val2, &val1));
type->free(UTEST_LYCTX, &val1);
type->free(UTEST_LYCTX, &val2);
v1 = "FAAC:21:011:Da85::87:daaF%1";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
v2 = "FAAC:21:011:Da85::87:daaF%14";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
assert_true(0 > type->sort(UTEST_LYCTX, &val1, &val2));
assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val1));
assert_true(0 < type->sort(UTEST_LYCTX, &val2, &val1));
type->free(UTEST_LYCTX, &val1);
type->free(UTEST_LYCTX, &val2);
/* ipv4-address-no-zone */
lysc_type = ((struct lysc_node_leaflist *)mod->compiled->data->next->next)->type;
type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_UNION]);
v1 = "127.0.0.1";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
v2 = "127.0.1.1";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
assert_true(0 > type->sort(UTEST_LYCTX, &val1, &val2));
assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val1));
assert_true(0 < type->sort(UTEST_LYCTX, &val2, &val1));
type->free(UTEST_LYCTX, &val1);
type->free(UTEST_LYCTX, &val2);
/* ipv6-address-no-zone */
lysc_type = ((struct lysc_node_leaflist *)mod->compiled->data->next->next->next)->type;
type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_STRING]);
v1 = "A:B:c:D:e:f:1:1";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
v2 = "A:B:c:D:e:f:1:0";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
assert_true(0 < type->sort(UTEST_LYCTX, &val1, &val2));
assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val1));
assert_true(0 > type->sort(UTEST_LYCTX, &val2, &val1));
type->free(UTEST_LYCTX, &val1);
type->free(UTEST_LYCTX, &val2);
/* ipv4-prefix */
lysc_type = ((struct lysc_node_leaflist *)mod->compiled->data->next->next->next->next)->type;
v1 = "0.1.58.4/32";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
v2 = "0.1.58.4/16";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
assert_true(0 < type->sort(UTEST_LYCTX, &val1, &val2));
assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val1));
assert_true(0 > type->sort(UTEST_LYCTX, &val2, &val1));
type->free(UTEST_LYCTX, &val1);
type->free(UTEST_LYCTX, &val2);
/* ipv6-prefix */
lysc_type = ((struct lysc_node_leaflist *)mod->compiled->data->next->next->next->next->next)->type;
v1 = "::C:D:E:f:a/96";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
v2 = "::C:D:E:f:a/112";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
assert_true(0 < type->sort(UTEST_LYCTX, &val1, &val2));
assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val1));
assert_true(0 > type->sort(UTEST_LYCTX, &val2, &val1));
type->free(UTEST_LYCTX, &val1);
type->free(UTEST_LYCTX, &val2);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_data_xml),
UTEST(test_data_lyb),
UTEST(test_plugin_sort),
UTEST(test_data_basic_plugins_only_xml),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

View file

@ -0,0 +1,292 @@
/**
* @file instanceid.c
* @author Adam Piecek <piecek@cesnet.cz>
* @brief test for built-in enumeration type
*
* Copyright (c) 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 UTEST HEADER */
#define _UTEST_MAIN_
#include "../utests.h"
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
#include "path.h"
#define MODULE_CREATE_YANG(MOD_NAME, NODES) \
"module " MOD_NAME " {\n" \
" yang-version 1.1;\n" \
" namespace \"urn:tests:" MOD_NAME "\";\n" \
" prefix pref;\n" \
NODES \
"}\n"
#define TEST_SUCCESS_XML2(XML1, MOD_NAME, NAMESPACES, NODE_NAME, DATA, TYPE, ...) \
{ \
struct lyd_node *tree; \
const char *data = XML1 "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\" " NAMESPACES ">" DATA "</" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree); \
CHECK_LYD_NODE_TERM((struct lyd_node_term *)tree, 0, 0, 1, 0, 1, TYPE, __VA_ARGS__); \
lyd_free_all(tree); \
}
#define TEST_ERROR_XML2(XML1, MOD_NAME, NAMESPACES, NODE_NAME, DATA, RET) \
{\
struct lyd_node *tree; \
const char *data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\" " NAMESPACES ">" DATA "</" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, RET, tree); \
assert_null(tree); \
}
#define LYB_CHECK_START \
struct lyd_node *tree_1; \
struct lyd_node *tree_2; \
char *xml_out, *data;
#define LYB_CHECK_END \
{ \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, LY_SUCCESS, tree_1); \
assert_int_equal(lyd_print_mem(&xml_out, tree_1, LYD_LYB, LYD_PRINT_WITHSIBLINGS), 0); \
assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, xml_out, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
assert_non_null(tree_2); \
CHECK_LYD(tree_1, tree_2); \
free(xml_out); \
lyd_free_all(tree_1); \
lyd_free_all(tree_2); \
}
#define TEST_SUCCESS_LYB(MOD_NAME, NODE_NAME1, DATA1, NODE_NAME2, DATA2) \
LYB_CHECK_START \
data = "<" NODE_NAME1 " xmlns=\"urn:tests:" MOD_NAME "\">" DATA1 "</" NODE_NAME1 ">" \
"<xdf:" NODE_NAME2 " xmlns:xdf=\"urn:tests:" MOD_NAME "\">/xdf:" DATA2 "</xdf:" NODE_NAME2 ">"; \
LYB_CHECK_END \
#define TEST_SUCCESS_LYB2(MOD_NAME, NODE_NAME, DATA) \
{ \
LYB_CHECK_START \
data = "<" NODE_NAME " xmlns:aa=\"urn:tests:lyb2\" xmlns=\"urn:tests:" MOD_NAME "\">/aa:" DATA "</" NODE_NAME ">"; \
LYB_CHECK_END \
}
static void
test_data_xml(void **state)
{
const char *schema, *schema2;
const enum ly_path_pred_type val1[] = {0, 0};
const enum ly_path_pred_type val2[] = {LY_PATH_PREDTYPE_LIST, 0};
const enum ly_path_pred_type val3[] = {LY_PATH_PREDTYPE_LEAFLIST};
const enum ly_path_pred_type val4[] = {LY_PATH_PREDTYPE_LIST, 0};
const enum ly_path_pred_type val5[] = {LY_PATH_PREDTYPE_LIST, 0};
const enum ly_path_pred_type val6[] = {LY_PATH_PREDTYPE_LIST, 0};
/* xml test */
schema = MODULE_CREATE_YANG("mod", "container cont {leaf l2 {type empty;}}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
schema2 = MODULE_CREATE_YANG("defs", "identity ident; identity ident-der1 {base ident;} identity ident-der2 {base ident;}"
"leaf l1 {type instance-identifier {require-instance true;}}"
"leaf l2 {type instance-identifier {require-instance false;}}"
"container cont {leaf l {type empty;}}"
"list list {key \"id\"; leaf id {type string;} leaf value {type string;}}"
"leaf-list llist {type uint32;}"
"list list-inst {key \"id\"; leaf id {type instance-identifier;} leaf value {type string;}}"
"list list-ident {key \"id\"; leaf id {type identityref {base ident;}} leaf value {type string;}}"
"list list2 {key \"id id2\"; leaf id {type string;} leaf id2 {type string;}}"
"list list-keyless {config false; leaf value {type string;}}");
UTEST_ADD_MODULE(schema2, LYS_IN_YANG, NULL, NULL);
TEST_SUCCESS_XML2("<cont xmlns=\"urn:tests:defs\"><l/></cont>", "defs", "xmlns:xdf=\"urn:tests:defs\"", "l1",
"/xdf:cont/xdf:l", INST, "/defs:cont/l", val1);
TEST_SUCCESS_XML2("<list xmlns=\"urn:tests:defs\"><id>a</id></list><list xmlns=\"urn:tests:defs\"><id>b</id></list>",
"defs", "xmlns:xdf=\"urn:tests:defs\"", "xdf:l1", "/xdf:list[xdf:id='b']/xdf:id", INST,
"/defs:list[id='b']/id", val2);
TEST_SUCCESS_XML2("<llist xmlns=\"urn:tests:defs\">1</llist><llist xmlns=\"urn:tests:defs\">2</llist>",
"defs", "xmlns:xdf=\"urn:tests:defs\"", "xdf:l1", "/xdf:llist[.='1']", INST, "/defs:llist[.='1']", val3);
TEST_SUCCESS_XML2("<list-inst xmlns=\"urn:tests:defs\"><id xmlns:b=\"urn:tests:defs\">/b:llist[.='1']</id>"
"<value>x</value></list-inst>"
"<list-inst xmlns=\"urn:tests:defs\"><id xmlns:b=\"urn:tests:defs\">/b:llist[.='2']</id>"
"<value>y</value></list-inst>"
"<llist xmlns=\"urn:tests:defs\">1</llist><llist xmlns=\"urn:tests:defs\">2</llist>",
"defs", "xmlns:a=\"urn:tests:defs\"", "a:l1", "/a:list-inst[a:id=\"/a:llist[.='1']\"]/a:value",
INST, "/defs:list-inst[id=\"/defs:llist[.='1']\"]/value", val4);
TEST_SUCCESS_XML2("<list-ident xmlns=\"urn:tests:defs\"><id xmlns:b=\"urn:tests:defs\">b:ident-der1</id>"
"<value>x</value></list-ident>"
"<list-ident xmlns=\"urn:tests:defs\"><id xmlns:b=\"urn:tests:defs\">b:ident-der2</id>"
"<value>y</value></list-ident>",
"defs", "xmlns:a=\"urn:tests:defs\"", "a:l1", "/a:list-ident[a:id='a:ident-der1']/a:value",
INST, "/defs:list-ident[id='defs:ident-der1']/value", val5);
TEST_SUCCESS_XML2("<list2 xmlns=\"urn:tests:defs\"><id>defs:xxx</id><id2>x</id2></list2>"
"<list2 xmlns=\"urn:tests:defs\"><id>a:xxx</id><id2>y</id2></list2>",
"defs", "xmlns:a=\"urn:tests:defs\"", "a:l1", "/a:list2[a:id='a:xxx'][a:id2='y']/a:id2",
INST, "/defs:list2[id='a:xxx'][id2='y']/id2", val6);
/* syntax/semantic errors */
TEST_ERROR_XML2("<list xmlns=\"urn:tests:defs\"><id>a</id></list>"
"<list xmlns=\"urn:tests:defs\"><id>b</id><value>x</value></list>",
"defs", "xmlns:xdf=\"urn:tests:defs\"", "xdf:l1", "/xdf:list[2]/xdf:value", LY_EVALID);
CHECK_LOG_CTX("Invalid instance-identifier \"/xdf:list[2]/xdf:value\" value - semantic error: "
"Positional predicate defined for configuration list \"list\" in path.", "/defs:l1", 1);
TEST_ERROR_XML2("",
"defs", "xmlns:xdf=\"urn:tests:defs\"", "xdf:l1", "/t:cont/t:1l", LY_EVALID);
CHECK_LOG_CTX("Invalid instance-identifier \"/t:cont/t:1l\" value - syntax error: Invalid character 't'[9] of expression '/t:cont/t:1l'.",
"/defs:l1", 1);
TEST_ERROR_XML2("",
"defs", "xmlns:xdf=\"urn:tests:defs\"", "xdf:l1", "/t:cont:t:1l", LY_EVALID);
CHECK_LOG_CTX("Invalid instance-identifier \"/t:cont:t:1l\" value - syntax error: Invalid character ':'[8] of expression '/t:cont:t:1l'.",
"/defs:l1", 1);
TEST_ERROR_XML2("",
"defs", "xmlns:xdf=\"urn:tests:defs\"", "xdf:l1", "/xdf:cont/xdf:invalid/xdf:path", LY_EVALID);
CHECK_LOG_CTX("Invalid instance-identifier \"/xdf:cont/xdf:invalid/xdf:path\" value - semantic error: Not found node \"invalid\" in path.",
"/defs:l1", 1);
/* non-existing instances, instance-identifier is here in JSON format because it is already in internal
* representation without canonical prefixes */
TEST_ERROR_XML2("<cont xmlns=\"urn:tests:mod\"/>",
"defs", "xmlns:m=\"urn:tests:mod\"", "l1", "/m:cont/m:l2", LY_ENOTFOUND);
CHECK_LOG_CTX_APPTAG("Invalid instance-identifier \"/mod:cont/l2\" value - required instance not found.",
"/defs:l1", 0, "instance-required");
TEST_ERROR_XML2("<llist xmlns=\"urn:tests:defs\">1</llist>",
"defs", "xmlns:a=\"urn:tests:defs\"", "l1", "/a:llist[.='2']", LY_ENOTFOUND);
CHECK_LOG_CTX_APPTAG("Invalid instance-identifier \"/defs:llist[.='2']\" value - required instance not found.",
"/defs:l1", 0, "instance-required");
TEST_ERROR_XML2("<list2 xmlns=\"urn:tests:defs\"><id>a</id><id2>a</id2></list2>"
"<list2 xmlns=\"urn:tests:defs\"><id>c</id><id2>b</id2></list2>"
"<llist xmlns=\"urn:tests:defs\">a</llist>"
"<llist xmlns=\"urn:tests:defs\">b</llist>",
"defs", "xmlns:a=\"urn:tests:defs\"", "l1", "/a:list2[a:id='a'][a:id2='a']/a:id", LY_ENOTFOUND);
CHECK_LOG_CTX_APPTAG("Invalid instance-identifier \"/defs:list2[id='a'][id2='a']/id\" value - required instance not found.",
"/defs:l1", 0, "instance-required");
TEST_ERROR_XML2("<list2 xmlns=\"urn:tests:defs\"><id>a</id><id2>a</id2></list2>"
"<list2 xmlns=\"urn:tests:defs\"><id>c</id><id2>b</id2></list2>"
"<llist xmlns=\"urn:tests:defs\">1</llist>"
"<llist xmlns=\"urn:tests:defs\">2</llist>",
"defs", "xmlns:a=\"urn:tests:defs\"", "l1", "/a:llist[.='3']", LY_ENOTFOUND);
CHECK_LOG_CTX_APPTAG("Invalid instance-identifier \"/defs:llist[.='3']\" value - required instance not found.",
"/defs:l1", 0, "instance-required");
TEST_ERROR_XML2("",
"defs", "xmlns:a=\"urn:tests:defs\"", "l1", "/a:list-keyless[3]", LY_ENOTFOUND);
CHECK_LOG_CTX_APPTAG("Invalid instance-identifier \"/defs:list-keyless[3]\" value - required instance not found.",
"/defs:l1", 0, "instance-required");
/* more errors */
TEST_ERROR_XML2("<llist xmlns=\"urn:tests:defs\">x</llist>",
"defs", "xmlns:t=\"urn:tests:defs\"", "t:l1", "/t:llist[1", LY_EVALID);
CHECK_LOG_CTX("Invalid instance-identifier \"/t:llist[1\" value - syntax error: Unexpected XPath expression end.",
"/defs:l1", 1);
TEST_ERROR_XML2("<cont xmlns=\"urn:tests:mod\"/>",
"defs", "xmlns:m=\"urn:tests:mod\"", "l1", "/m:cont[1]", LY_EVALID);
CHECK_LOG_CTX("Invalid instance-identifier \"/m:cont[1]\" value - semantic error: Positional predicate defined for container \"cont\" in path.",
"/defs:l1", 1);
TEST_ERROR_XML2("<cont xmlns=\"urn:tests:mod\"/>",
"defs", "xmlns:m=\"urn:tests:mod\"", "l1", "[1]", LY_EVALID);
CHECK_LOG_CTX("Invalid instance-identifier \"[1]\" value - syntax error: Unexpected XPath token \"[\" (\"[1]\"), expected \"Operator(Path)\".",
"/defs:l1", 1);
TEST_ERROR_XML2("<cont xmlns=\"urn:tests:mod\"><l2/></cont>",
"defs", "xmlns:m=\"urn:tests:mod\"", "l1", "/m:cont/m:l2[l2='1']", LY_EVALID);
CHECK_LOG_CTX("Invalid instance-identifier \"/m:cont/m:l2[l2='1']\" value - syntax error: Prefix missing for \"l2\" in path.",
"/defs:l1", 1);
TEST_ERROR_XML2("<cont xmlns=\"urn:tests:mod\"><l2/></cont>",
"defs", "xmlns:m=\"urn:tests:mod\"", "l1", "/m:cont/m:l2[m:l2='1']", LY_EVALID);
CHECK_LOG_CTX("Invalid instance-identifier \"/m:cont/m:l2[m:l2='1']\" value - semantic error: List predicate defined for leaf \"l2\" in path.",
"/defs:l1", 1);
TEST_ERROR_XML2("<llist xmlns=\"urn:tests:defs\">1</llist><llist xmlns=\"urn:tests:defs\">2</llist>",
"defs", "xmlns:t=\"urn:tests:defs\"", "t:l1", "/t:llist[4]", LY_EVALID);
CHECK_LOG_CTX("Invalid instance-identifier \"/t:llist[4]\" value - semantic error: Positional predicate defined for configuration leaf-list \"llist\" in path.",
"/defs:l1", 1);
TEST_ERROR_XML2("",
"defs", "xmlns:xdf=\"urn:tests:defs\"", "xdf:l2", "/t:llist[6]", LY_EVALID);
CHECK_LOG_CTX("Invalid instance-identifier \"/t:llist[6]\" value - semantic error: No module connected with the prefix \"t\" found (prefix format XML prefixes).",
"/defs:l2", 1);
TEST_ERROR_XML2("<list xmlns=\"urn:tests:defs\"><id>1</id><value>x</value></list>",
"defs", "xmlns:xdf=\"urn:tests:defs\"", "xdf:l2", "/xdf:list[xdf:value='x']", LY_EVALID);
CHECK_LOG_CTX("Invalid instance-identifier \"/xdf:list[xdf:value='x']\" value - semantic error: Key expected instead of leaf \"value\" in path.",
"/defs:l2", 1);
TEST_ERROR_XML2("",
"defs", "xmlns:xdf=\"urn:tests:defs\"", "xdf:l2", "/xdf:list[.='x']", LY_EVALID);
CHECK_LOG_CTX("Invalid instance-identifier \"/xdf:list[.='x']\" value - semantic error: Leaf-list predicate defined for list \"list\" in path.",
"/defs:l2", 1);
TEST_ERROR_XML2("<llist xmlns=\"urn:tests:defs\">1</llist>",
"defs", "xmlns:t=\"urn:tests:defs\"", "t:l1", "/t:llist[.='x']", LY_EVALID);
CHECK_LOG_CTX("Invalid instance-identifier \"/t:llist[.='x']\" value - semantic error: Invalid type uint32 value \"x\".",
"/defs:l1", 1);
TEST_ERROR_XML2("",
"defs", "xmlns:xdf=\"urn:tests:defs\"", "xdf:l2", "/t:llist[1][2]", LY_EVALID);
CHECK_LOG_CTX("Invalid instance-identifier \"/t:llist[1][2]\" value - syntax error: Unparsed characters \"[2]\" left at the end of path.",
"/defs:l2", 1);
TEST_ERROR_XML2("",
"defs", "xmlns:xdf=\"urn:tests:defs\"", "xdf:l2", "/t:llist[.='a'][.='b']", LY_EVALID);
CHECK_LOG_CTX("Invalid instance-identifier \"/t:llist[.='a'][.='b']\" value - syntax error: Unparsed characters \"[.='b']\" left at the end of path.",
"/defs:l2", 1);
TEST_ERROR_XML2("<list xmlns=\"urn:tests:defs\"><id>1</id><value>x</value></list>",
"defs", "xmlns:xdf=\"urn:tests:defs\"", "xdf:l2", "/xdf:list[xdf:id='1'][xdf:id='2']/xdf:value", LY_EVALID);
CHECK_LOG_CTX("Invalid instance-identifier \"/xdf:list[xdf:id='1'][xdf:id='2']/xdf:value\" value - syntax error: Duplicate predicate key \"id\" in path.",
"/defs:l2", 1);
TEST_ERROR_XML2("",
"defs", "xmlns:xdf=\"urn:tests:defs\"", "xdf:l2", "/xdf:list2[xdf:id='1']/xdf:value", LY_EVALID);
CHECK_LOG_CTX("Invalid instance-identifier \"/xdf:list2[xdf:id='1']/xdf:value\" value - semantic error: Predicate missing for a key of list \"list2\" in path.",
"/defs:l2", 1);
}
static void
test_plugin_lyb(void **state)
{
const char *schema;
schema = MODULE_CREATE_YANG("lyb",
"leaf-list leaflisttarget {type string;}"
"leaf inst {type instance-identifier {require-instance true;}}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
TEST_SUCCESS_LYB("lyb", "leaflisttarget", "1", "inst", "leaflisttarget[.='1']");
/* ietf-netconf-acm node-instance-identifier type */
assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_DIR_MODULES_YANG));
schema = MODULE_CREATE_YANG("lyb2",
"import ietf-netconf-acm {prefix acm;}"
"leaf-list ll {type string;}"
"leaf nii {type acm:node-instance-identifier;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
TEST_SUCCESS_LYB2("lyb2", "nii", "ll[. = 'some_string']");
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_data_xml),
UTEST(test_plugin_lyb),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

View file

@ -0,0 +1,76 @@
/**
* @file instanceid_keys.c
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief test for yang instance-identifier-keys type
*
* Copyright (c) 2022 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 UTEST HEADER */
#define _UTEST_MAIN_
#include "../utests.h"
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
#define MODULE_CREATE_YANG(MOD_NAME, NODES) \
"module " MOD_NAME " {\n" \
" yang-version 1.1;\n" \
" namespace \"urn:tests:" MOD_NAME "\";\n" \
" prefix pref;\n" \
NODES \
"}\n"
#define TEST_SUCCESS_XML_NS1(MOD_NAME, NODE_NAME, PREFIX, NS, DATA, TYPE, ...) \
{ \
struct lyd_node *tree; \
const char *data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\" xmlns:" PREFIX "=\"" NS "\">" DATA "</" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree); \
CHECK_LYD_NODE_TERM((struct lyd_node_term *)tree, 0, 0, 0, 0, 1, TYPE, __VA_ARGS__); \
lyd_free_all(tree); \
}
#define TEST_ERROR_XML(MOD_NAME, NODE_NAME, DATA) \
{\
struct lyd_node *tree; \
const char *data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); \
assert_null(tree); \
}
static void
test_data_xml(void **state)
{
const char *schema;
/* xml test */
schema = MODULE_CREATE_YANG("defs", "import yang {prefix y;} leaf l1 {type y:instance-identifier-keys;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
TEST_SUCCESS_XML_NS1("defs", "l1", "px", "urn:tests:defs", "[px:key='val']", STRING, "[defs:key='val']");
TEST_ERROR_XML("defs", "l1", "black");
CHECK_LOG_CTX("Invalid first character 'b', list key predicates expected.", "/defs:l1", 1);
TEST_ERROR_XML("defs", "l1", "[this is not a valid xpath]");
CHECK_LOG_CTX("Invalid character 0x69 ('i'), perhaps \"this\" is supposed to be a function call.", "/defs:l1", 1);
TEST_ERROR_XML("defs", "l1", "[px:key='val']");
CHECK_LOG_CTX("Failed to resolve prefix \"px\".", "/defs:l1", 1);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_data_xml),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

View file

@ -0,0 +1,74 @@
/**
* @file int16.c
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief test for int16 values
*
* Copyright (c) 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 UTEST HEADER */
#define _UTEST_MAIN_
#include "../utests.h"
/* GLOBAL INCLUDE HEADERS */
#include <ctype.h>
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
#include "path.h"
#include "plugins_internal.h"
#define MODULE_CREATE_YANG(MOD_NAME, NODES) \
"module " MOD_NAME " {\n" \
" yang-version 1.1;\n" \
" namespace \"urn:tests:" MOD_NAME "\";\n" \
" prefix pref;\n" \
NODES \
"}\n"
#define TEST_SUCCESS_XML(MOD_NAME, DATA, TYPE, ...) \
{ \
struct lyd_node *tree; \
const char *data = "<port xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</port>"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree); \
CHECK_LYSC_NODE(tree->schema, NULL, 0, 0x5, 1, "port", 0, LYS_LEAF, 0, 0, 0, 0); \
CHECK_LYD_NODE_TERM((struct lyd_node_term *)tree, 0, 0, 0, 0, 1, TYPE, ## __VA_ARGS__); \
lyd_free_all(tree); \
}
#define TEST_ERROR_XML(MOD_NAME, DATA) \
{\
struct lyd_node *tree; \
const char *data = "<port xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</port>"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); \
assert_null(tree); \
}
static void
test_data_xml(void **state)
{
const char *schema;
/* xml test */
schema = MODULE_CREATE_YANG("defs", "leaf port {type int16 {range -20..-10;}}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
TEST_ERROR_XML("defs", "100");
CHECK_LOG_CTX("Unsatisfied range - value \"100\" is out of the allowed range.", "/defs:port", 1);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_data_xml),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

View file

@ -0,0 +1,74 @@
/**
* @file int32.c
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief test for int32 values
*
* Copyright (c) 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 UTEST HEADER */
#define _UTEST_MAIN_
#include "../utests.h"
/* GLOBAL INCLUDE HEADERS */
#include <ctype.h>
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
#include "path.h"
#include "plugins_internal.h"
#define MODULE_CREATE_YANG(MOD_NAME, NODES) \
"module " MOD_NAME " {\n" \
" yang-version 1.1;\n" \
" namespace \"urn:tests:" MOD_NAME "\";\n" \
" prefix pref;\n" \
NODES \
"}\n"
#define TEST_SUCCESS_XML(MOD_NAME, DATA, TYPE, ...) \
{ \
struct lyd_node *tree; \
const char *data = "<port xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</port>"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree); \
CHECK_LYSC_NODE(tree->schema, NULL, 0, 0x5, 1, "port", 0, LYS_LEAF, 0, 0, 0, 0); \
CHECK_LYD_NODE_TERM((struct lyd_node_term *)tree, 0, 0, 0, 0, 1, TYPE, ## __VA_ARGS__); \
lyd_free_all(tree); \
}
#define TEST_ERROR_XML(MOD_NAME, DATA) \
{\
struct lyd_node *tree; \
const char *data = "<port xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</port>"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); \
assert_null(tree); \
}
static void
test_data_xml(void **state)
{
const char *schema;
/* xml test */
schema = MODULE_CREATE_YANG("defs", "leaf port {type int32;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
TEST_ERROR_XML("defs", "0x01");
CHECK_LOG_CTX("Invalid type int32 value \"0x01\".", "/defs:port", 1);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_data_xml),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

View file

@ -0,0 +1,80 @@
/**
* @file int64.c
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief test for int32 values
*
* Copyright (c) 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 UTEST HEADER */
#define _UTEST_MAIN_
#include "../utests.h"
/* GLOBAL INCLUDE HEADERS */
#include <ctype.h>
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
#include "path.h"
#include "plugins_internal.h"
#define MODULE_CREATE_YANG(MOD_NAME, NODES) \
"module " MOD_NAME " {\n" \
" yang-version 1.1;\n" \
" namespace \"urn:tests:" MOD_NAME "\";\n" \
" prefix pref;\n" \
NODES \
"}\n"
#define TEST_SUCCESS_XML(MOD_NAME, DATA, TYPE, ...) \
{ \
struct lyd_node *tree; \
const char *data = "<port xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</port>"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree); \
CHECK_LYSC_NODE(tree->schema, NULL, 0, 0x5, 1, "port", 0, LYS_LEAF, 0, 0, 0, 0); \
CHECK_LYD_NODE_TERM((struct lyd_node_term *)tree, 0, 0, 0, 0, 1, TYPE, ## __VA_ARGS__); \
lyd_free_all(tree); \
}
#define TEST_ERROR_XML(MOD_NAME, DATA) \
{\
struct lyd_node *tree; \
const char *data = "<port xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</port>"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); \
assert_null(tree); \
}
static void
test_data_xml(void **state)
{
const char *schema;
/* xml test */
schema = MODULE_CREATE_YANG("defs", "leaf port {type int64;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
TEST_ERROR_XML("defs", "");
CHECK_LOG_CTX("Invalid type int64 empty value.", "/defs:port", 1);
TEST_ERROR_XML("defs", " ");
CHECK_LOG_CTX("Invalid type int64 empty value.", "/defs:port", 1);
TEST_ERROR_XML("defs", "-10 xxx");
CHECK_LOG_CTX("Invalid type int64 value \"-10 xxx\".", "/defs:port", 1);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_data_xml),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

1762
tests/utests/types/int8.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,326 @@
/**
* @file leafref.c
* @author Adam Piecek <piecek@cesnet.cz>
* @brief test for built-in enumeration type
*
* Copyright (c) 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 UTEST HEADER */
#define _UTEST_MAIN_
#include "../utests.h"
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
#define MODULE_CREATE_YANG(MOD_NAME, NODES) \
"module " MOD_NAME " {\n" \
" yang-version 1.1;\n" \
" namespace \"urn:tests:" MOD_NAME "\";\n" \
" prefix pref;\n" \
NODES \
"}\n"
#define TEST_SUCCESS_XML2(XML1, MOD_NAME, NAMESPACES, NODE_NAME, DATA, TYPE, ...) \
{ \
struct lyd_node *tree; \
const char *data = XML1 "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\" " NAMESPACES ">" DATA "</" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree); \
CHECK_LYD_NODE_TERM((struct lyd_node_term *)tree, 0, 0, 1, 0, 1, TYPE, __VA_ARGS__); \
lyd_free_all(tree); \
}
#define TEST_ERROR_XML2(XML1, MOD_NAME, NAMESPACES, NODE_NAME, DATA, RET) \
{\
struct lyd_node *tree; \
const char *data = XML1 "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\" " NAMESPACES ">" DATA "</" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, RET, tree); \
assert_null(tree); \
}
#define TEST_SUCCESS_LYB(MOD_NAME, NODE_NAME1, DATA1, NODE_NAME2, DATA2) \
{ \
struct lyd_node *tree_1; \
struct lyd_node *tree_2; \
char *xml_out, *data; \
data = "<" NODE_NAME1 " xmlns=\"urn:tests:" MOD_NAME "\"><name>" DATA1 "</name></" NODE_NAME1 ">" \
"<" NODE_NAME2 " xmlns=\"urn:tests:" MOD_NAME "\">" DATA2 "</" NODE_NAME2 ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, LY_SUCCESS, tree_1); \
assert_int_equal(lyd_print_mem(&xml_out, tree_1, LYD_LYB, LYD_PRINT_WITHSIBLINGS), 0); \
assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, xml_out, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
assert_non_null(tree_2); \
CHECK_LYD(tree_1, tree_2); \
free(xml_out); \
lyd_free_all(tree_1); \
lyd_free_all(tree_2); \
}
static void
test_data_xml(void **state)
{
const char *schema, *schema2, *schema3, *data;
struct lyd_node *tree;
/* xml test */
schema = MODULE_CREATE_YANG("defs", "leaf lref {type leafref {path /leaflisttarget; require-instance true;}}"
"leaf lref2 {type leafref {path \"../list[id = current()/../str-norestr]/targets\"; require-instance true;}}"
"leaf str-norestr {type string;}"
"list list {key id; leaf id {type string;} leaf value {type string;} leaf-list targets {type string;}}"
"container cont {leaf leaftarget {type empty;}"
" list listtarget {key id; max-elements 5;leaf id {type uint8;} leaf value {type string;}}"
" leaf-list leaflisttarget {type uint8; max-elements 5;}}"
"leaf-list leaflisttarget {type string;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
schema2 = MODULE_CREATE_YANG("leafrefs", "import defs {prefix t;}"
"container c { container x {leaf x {type string;}} list l {"
" key \"id value\"; leaf id {type string;} leaf value {type string;}"
" leaf lr1 {type leafref {path \"../../../t:str-norestr\"; require-instance true;}}"
" leaf lr2 {type leafref {path \"../../l[id=current()/../../../t:str-norestr]\" +"
" \"[value=current()/../../../t:str-norestr]/value\"; require-instance true;}}"
" leaf lr3 {type leafref {path \"/t:list[t:id=current ( )/../../x/x]/t:targets\";}}"
"}}");
UTEST_ADD_MODULE(schema2, LYS_IN_YANG, NULL, NULL);
TEST_SUCCESS_XML2("<leaflisttarget xmlns=\"urn:tests:defs\">x</leaflisttarget>"
"<leaflisttarget xmlns=\"urn:tests:defs\">y</leaflisttarget>",
"defs", "xmlns:a=\"urn:tests:defs\"", "a:lref", "y", STRING, "y");
TEST_SUCCESS_XML2("<list xmlns=\"urn:tests:defs\"><id>x</id><targets>a</targets><targets>b</targets></list>"
"<list xmlns=\"urn:tests:defs\"><id>y</id><targets>x</targets><targets>y</targets></list>"
"<str-norestr xmlns=\"urn:tests:defs\">y</str-norestr>",
"defs", "xmlns:a=\"urn:tests:defs\"", "a:lref2", "y", STRING, "y");
data = "<str-norestr xmlns=\"urn:tests:defs\">y</str-norestr>"
"<c xmlns=\"urn:tests:leafrefs\"><l><id>x</id><value>x</value><lr1>y</lr1></l></c>";
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
CHECK_LYD_NODE_TERM((struct lyd_node_term *)lyd_child(lyd_child(tree->next->next)->next)->next->next,
0, 0, 0, 1, 1, STRING, "y");
lyd_free_all(tree);
data = "<list xmlns=\"urn:tests:defs\"><id>x</id><targets>a</targets><targets>b</targets></list>"
"<list xmlns=\"urn:tests:defs\"><id>y</id><targets>c</targets><targets>d</targets></list>"
"<c xmlns=\"urn:tests:leafrefs\"><x><x>y</x></x>"
"<l><id>x</id><value>x</value><lr3>c</lr3></l></c>";
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
CHECK_LYD_NODE_TERM((struct lyd_node_term *)lyd_child(lyd_child(tree->next->next->next)->next)->next->next,
0, 0, 0, 1, 1, STRING, "c");
lyd_free_all(tree);
schema3 = MODULE_CREATE_YANG("simple", "leaf l1 {type leafref {path \"../target\";}}"
"leaf target {type string;}");
UTEST_ADD_MODULE(schema3, LYS_IN_YANG, NULL, NULL);
data = "<l1 xmlns=\"urn:tests:simple\">&quot;*&quot;&#39;</l1>"
"<target xmlns=\"urn:tests:simple\">&quot;*&quot;&#39;</target>";
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
lyd_free_all(tree);
data = "<l1 xmlns=\"urn:tests:simple\">&quot;*&#39;&quot;</l1>"
"<target xmlns=\"urn:tests:simple\">&quot;*&#39;&quot;</target>";
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
lyd_free_all(tree);
/* invalid value */
TEST_ERROR_XML2("<leaflisttarget xmlns=\"urn:tests:defs\">x</leaflisttarget>",
"defs", "", "lref", "y", LY_EVALID);
CHECK_LOG_CTX_APPTAG("Invalid leafref value \"y\" - no target instance \"/leaflisttarget\" with the same value.",
"/defs:lref", 0, "instance-required");
TEST_ERROR_XML2("<list xmlns=\"urn:tests:defs\"><id>x</id><targets>a</targets><targets>b</targets></list>"
"<list xmlns=\"urn:tests:defs\"><id>y</id><targets>x</targets><targets>y</targets></list>"
"<str-norestr xmlns=\"urn:tests:defs\">y</str-norestr>",
"defs", "", "lref2", "b", LY_EVALID);
CHECK_LOG_CTX_APPTAG("Invalid leafref value \"b\" - "
"no target instance \"../list[id = current()/../str-norestr]/targets\" with the same value.",
"/defs:lref2", 0, "instance-required");
TEST_ERROR_XML2("<list xmlns=\"urn:tests:defs\"><id>x</id><targets>a</targets><targets>b</targets></list>"
"<list xmlns=\"urn:tests:defs\"><id>y</id><targets>x</targets><targets>y</targets></list>",
"defs", "", "lref2", "b", LY_EVALID);
CHECK_LOG_CTX_APPTAG("Invalid leafref value \"b\" - "
"no target instance \"../list[id = current()/../str-norestr]/targets\" with the same value.",
"/defs:lref2", 0, "instance-required");
TEST_ERROR_XML2("<str-norestr xmlns=\"urn:tests:defs\">y</str-norestr>",
"defs", "", "lref2", "b", LY_EVALID);
CHECK_LOG_CTX_APPTAG("Invalid leafref value \"b\" - "
"no target instance \"../list[id = current()/../str-norestr]/targets\" with the same value.",
"/defs:lref2", 0, "instance-required");
TEST_ERROR_XML2("<str-norestr xmlns=\"urn:tests:defs\">y</str-norestr>",
"leafrefs", "", "c", "<l><id>x</id><value>x</value><lr1>a</lr1></l>", LY_EVALID);
CHECK_LOG_CTX_APPTAG("Invalid leafref value \"a\" - no target instance \"../../../t:str-norestr\" with the same value.",
"/leafrefs:c/l[id='x'][value='x']/lr1", 0, "instance-required");
TEST_ERROR_XML2("<str-norestr xmlns=\"urn:tests:defs\">z</str-norestr>",
"leafrefs", "", "c", "<l><id>y</id><value>y</value></l><l><id>x</id><value>x</value><lr2>z</lr2></l>", LY_EVALID);
CHECK_LOG_CTX_APPTAG("Invalid leafref value \"z\" - no target instance \"../../l[id=current()/../../../t:str-norestr]"
"[value=current()/../../../t:str-norestr]/value\" with the same value.",
"/leafrefs:c/l[id='x'][value='x']/lr2", 0, "instance-required");
TEST_ERROR_XML2("",
"defs", "", "lref", "%n", LY_EVALID);
CHECK_LOG_CTX_APPTAG("Invalid leafref value \"%n\" - no target instance \"/leaflisttarget\" with the same value.",
"/defs:lref", 0, "instance-required");
}
static void
test_data_json(void **state)
{
const char *schema, *data;
struct lyd_node *tree;
/* json test */
schema = MODULE_CREATE_YANG("simple", "leaf l1 {type leafref {path \"../target\";}}"
"leaf target {type string;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
data = "{"
" \"simple:l1\":\"\\\"*\\\"'\","
" \"simple:target\":\"\\\"*\\\"'\""
"}";
CHECK_PARSE_LYD_PARAM(data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
lyd_free_all(tree);
data = "{"
" \"simple:l1\":\"\\\"*'\\\"\","
" \"simple:target\":\"\\\"*'\\\"\""
"}";
CHECK_PARSE_LYD_PARAM(data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
lyd_free_all(tree);
}
static void
test_plugin_lyb(void **state)
{
const char *schema;
schema = MODULE_CREATE_YANG("lyb",
"list lst {key \"name\"; leaf name {type string;}}"
"leaf lref {type leafref {path \"../lst/name\";}}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
TEST_SUCCESS_LYB("lyb", "lst", "key_str", "lref", "key_str");
}
static void
test_plugin_sort(void **state)
{
const char *v1, *v2;
const char *schema;
struct lys_module *mod;
struct lyd_value val1 = {0}, val2 = {0};
struct lyplg_type *type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_LEAFREF]);
struct lysc_type *lysc_type;
struct ly_err_item *err = NULL;
schema = MODULE_CREATE_YANG("simple",
"leaf l1 {"
" type leafref {"
" require-instance false;"
" path \"../target\";"
" }"
"}"
"leaf target {"
" type string;"
"}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
lysc_type = ((struct lysc_node_leaf *)mod->compiled->data)->type;
v1 = "str1";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
v2 = "str2";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
assert_true(0 > type->sort(UTEST_LYCTX, &val1, &val2));
assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val1));
assert_true(0 < type->sort(UTEST_LYCTX, &val2, &val1));
type->free(UTEST_LYCTX, &val1);
type->free(UTEST_LYCTX, &val2);
}
static void
test_data_xpath_json(void **state)
{
const char *schema, *data;
struct lyd_node *tree;
ly_ctx_set_options(UTEST_LYCTX, LY_CTX_LEAFREF_EXTENDED);
/* json xpath test */
schema = MODULE_CREATE_YANG("xp_test",
"list l1 {key t1;"
"leaf t1 {type uint8;}"
"list l2 {key t2;"
"leaf t2 {type uint8;}"
"leaf-list l3 {type uint8;}"
"}}"
"leaf r1 {type leafref {path \"../l1/t1\";}}"
"leaf r2 {type leafref {path \"deref(../r1)/../l2/t2\";}}"
"leaf r3 {type leafref {path \"deref(../r2)/../l3\";}}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
data = "{"
" \"xp_test:l1\":[{\"t1\": 1,\"l2\":[{\"t2\": 2,\"l3\":[3]}]}],"
" \"xp_test:r1\": 1,"
" \"xp_test:r2\": 2,"
" \"xp_test:r3\": 3"
"}";
CHECK_PARSE_LYD_PARAM(data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
lyd_free_all(tree);
}
static void
test_xpath_invalid_schema(void **state)
{
const char *schema1, *schema2;
ly_ctx_set_options(UTEST_LYCTX, LY_CTX_LEAFREF_EXTENDED);
schema1 = MODULE_CREATE_YANG("xp_test",
"list l1 {key t1;"
"leaf t1 {type uint8;}"
"list l2 {key t2;"
"leaf t2 {type uint8;}"
"leaf-list l3 {type uint8;}"
"}}"
"leaf r1 {type leafref {path \"deref(../l1)/../l2/t2\";}}");
UTEST_INVALID_MODULE(schema1, LYS_IN_YANG, NULL, LY_EVALID)
CHECK_LOG_CTX("The deref function target node \"l1\" is not leaf nor leaflist", "/xp_test:r1", 0);
schema2 = MODULE_CREATE_YANG("xp_test",
"list l1 {key t1;"
"leaf t1 {type uint8;}"
"list l2 {key t2;"
"leaf t2 {type uint8;}"
"leaf-list l3 {type uint8;}"
"}}"
"leaf r1 {type uint8;}"
"leaf r2 {type leafref {path \"deref(../r1)/../l2/t2\";}}");
UTEST_INVALID_MODULE(schema2, LYS_IN_YANG, NULL, LY_EVALID)
CHECK_LOG_CTX("The deref function target node \"r1\" is not leafref", "/xp_test:r2", 0);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_data_xml),
UTEST(test_data_json),
UTEST(test_plugin_lyb),
UTEST(test_plugin_sort),
UTEST(test_data_xpath_json),
UTEST(test_xpath_invalid_schema)
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

1379
tests/utests/types/string.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,74 @@
/**
* @file uint16.c
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief test for uint16 values
*
* Copyright (c) 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 UTEST HEADER */
#define _UTEST_MAIN_
#include "../utests.h"
/* GLOBAL INCLUDE HEADERS */
#include <ctype.h>
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
#include "path.h"
#include "plugins_internal.h"
#define MODULE_CREATE_YANG(MOD_NAME, NODES) \
"module " MOD_NAME " {\n" \
" yang-version 1.1;\n" \
" namespace \"urn:tests:" MOD_NAME "\";\n" \
" prefix pref;\n" \
NODES \
"}\n"
#define TEST_SUCCESS_XML(MOD_NAME, DATA, TYPE, ...) \
{ \
struct lyd_node *tree; \
const char *data = "<port xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</port>"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree); \
CHECK_LYSC_NODE(tree->schema, NULL, 0, 0x5, 1, "port", 0, LYS_LEAF, 0, 0, 0, 0); \
CHECK_LYD_NODE_TERM((struct lyd_node_term *)tree, 0, 0, 0, 0, 1, TYPE, ## __VA_ARGS__); \
lyd_free_all(tree); \
}
#define TEST_ERROR_XML(MOD_NAME, DATA) \
{\
struct lyd_node *tree; \
const char *data = "<port xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</port>"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); \
assert_null(tree); \
}
static void
test_data_xml(void **state)
{
const char *schema;
/* xml test */
schema = MODULE_CREATE_YANG("defs", "leaf port {type uint16 {range 150..200;}}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
TEST_ERROR_XML("defs", "\n 1500 \t\n ");
CHECK_LOG_CTX("Unsatisfied range - value \"1500\" is out of the allowed range.", "/defs:port", 3);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_data_xml),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

View file

@ -0,0 +1,74 @@
/**
* @file uint32.c
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief test for uint32 values
*
* Copyright (c) 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 UTEST HEADER */
#define _UTEST_MAIN_
#include "../utests.h"
/* GLOBAL INCLUDE HEADERS */
#include <ctype.h>
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
#include "path.h"
#include "plugins_internal.h"
#define MODULE_CREATE_YANG(MOD_NAME, NODES) \
"module " MOD_NAME " {\n" \
" yang-version 1.1;\n" \
" namespace \"urn:tests:" MOD_NAME "\";\n" \
" prefix pref;\n" \
NODES \
"}\n"
#define TEST_SUCCESS_XML(MOD_NAME, DATA, TYPE, ...) \
{ \
struct lyd_node *tree; \
const char *data = "<port xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</port>"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree); \
CHECK_LYSC_NODE(tree->schema, NULL, 0, 0x5, 1, "port", 0, LYS_LEAF, 0, 0, 0, 0); \
CHECK_LYD_NODE_TERM((struct lyd_node_term *)tree, 0, 0, 0, 0, 1, TYPE, ## __VA_ARGS__); \
lyd_free_all(tree); \
}
#define TEST_ERROR_XML(MOD_NAME, DATA) \
{\
struct lyd_node *tree; \
const char *data = "<port xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</port>"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); \
assert_null(tree); \
}
static void
test_data_xml(void **state)
{
const char *schema;
/* xml test */
schema = MODULE_CREATE_YANG("defs", "leaf port {type uint32;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
TEST_ERROR_XML("defs", "-10");
CHECK_LOG_CTX("Value \"-10\" is out of type uint32 min/max bounds.", "/defs:port", 1);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_data_xml),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

View file

@ -0,0 +1,80 @@
/**
* @file uint64.c
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief test for uint64 values
*
* Copyright (c) 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 UTEST HEADER */
#define _UTEST_MAIN_
#include "../utests.h"
/* GLOBAL INCLUDE HEADERS */
#include <ctype.h>
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
#include "path.h"
#include "plugins_internal.h"
#define MODULE_CREATE_YANG(MOD_NAME, NODES) \
"module " MOD_NAME " {\n" \
" yang-version 1.1;\n" \
" namespace \"urn:tests:" MOD_NAME "\";\n" \
" prefix pref;\n" \
NODES \
"}\n"
#define TEST_SUCCESS_XML(MOD_NAME, DATA, TYPE, ...) \
{ \
struct lyd_node *tree; \
const char *data = "<port xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</port>"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree); \
CHECK_LYSC_NODE(tree->schema, NULL, 0, 0x5, 1, "port", 0, LYS_LEAF, 0, 0, 0, 0); \
CHECK_LYD_NODE_TERM((struct lyd_node_term *)tree, 0, 0, 0, 0, 1, TYPE, ## __VA_ARGS__); \
lyd_free_all(tree); \
}
#define TEST_ERROR_XML(MOD_NAME, DATA) \
{\
struct lyd_node *tree; \
const char *data = "<port xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</port>"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); \
assert_null(tree); \
}
static void
test_data_xml(void **state)
{
const char *schema;
/* xml test */
schema = MODULE_CREATE_YANG("defs", "leaf port {type uint64;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
TEST_ERROR_XML("defs", "");
CHECK_LOG_CTX("Invalid type uint64 empty value.", "/defs:port", 1);
TEST_ERROR_XML("defs", " ");
CHECK_LOG_CTX("Invalid type uint64 empty value.", "/defs:port", 1);
TEST_ERROR_XML("defs", "10 xxx");
CHECK_LOG_CTX("Invalid type uint64 value \"10 xxx\".", "/defs:port", 1);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_data_xml),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

View file

@ -0,0 +1,87 @@
/**
* @file uint8.c
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief test for uint8 values
*
* Copyright (c) 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 UTEST HEADER */
#define _UTEST_MAIN_
#include "../utests.h"
/* GLOBAL INCLUDE HEADERS */
#include <ctype.h>
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
#include "path.h"
#include "plugins_internal.h"
#define MODULE_CREATE_YANG(MOD_NAME, NODES) \
"module " MOD_NAME " {\n" \
" yang-version 1.1;\n" \
" namespace \"urn:tests:" MOD_NAME "\";\n" \
" prefix pref;\n" \
NODES \
"}\n"
#define TEST_SUCCESS_XML(MOD_NAME, DATA, TYPE, ...) \
{ \
struct lyd_node *tree; \
const char *data = "<port xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</port>"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree); \
CHECK_LYSC_NODE(tree->schema, NULL, 0, 0x5, 1, "port", 0, LYS_LEAF, 0, 0, 0, 0); \
CHECK_LYD_NODE_TERM((struct lyd_node_term *)tree, 0, 0, 0, 0, 1, TYPE, __VA_ARGS__); \
lyd_free_all(tree); \
}
#define TEST_ERROR_XML(MOD_NAME, DATA) \
{\
struct lyd_node *tree; \
const char *data = "<port xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</port>"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); \
assert_null(tree); \
}
#define TEST_SUCCESS_PARSE_STORE_ONLY_XML(MOD_NAME, DATA) \
{\
struct lyd_node *tree; \
const char *data = "<port xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</port>"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_STORE_ONLY, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree); \
lyd_free_all(tree); \
}
static void
test_data_xml(void **state)
{
const char *schema;
/* xml test */
schema = MODULE_CREATE_YANG("defs", "leaf port {type uint8 {range 150..200;}}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
TEST_SUCCESS_XML("defs", "\n 150 \t\n ", UINT8, "150", 150);
TEST_ERROR_XML("defs", "\n 15 \t\n ");
CHECK_LOG_CTX("Unsatisfied range - value \"15\" is out of the allowed range.", "/defs:port", 3);
/* LYPLG_TYPE_STORE_ONLY test */
TEST_SUCCESS_PARSE_STORE_ONLY_XML("defs", "\n 15 \t\n ");
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_data_xml),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

315
tests/utests/types/union.c Normal file
View file

@ -0,0 +1,315 @@
/**
* @file union.c
* @author Adam Piecek <piecek@cesnet.cz>
* @brief test for built-in enumeration type
*
* Copyright (c) 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 UTEST HEADER */
#define _UTEST_MAIN_
#include "../utests.h"
/* LOCAL INCLUDE HEADERS */
#include "libyang.h"
#include "path.h"
#define MODULE_CREATE_YANG(MOD_NAME, NODES) \
"module " MOD_NAME " {\n" \
" yang-version 1.1;\n" \
" namespace \"urn:tests:" MOD_NAME "\";\n" \
" prefix pref;\n" \
NODES \
"}\n"
#define TEST_SUCCESS_XML2(XML1, MOD_NAME, NAMESPACES, NODE_NAME, DATA, TYPE, ...) \
{ \
struct lyd_node *tree; \
const char *data = XML1 "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\" " NAMESPACES ">" DATA "</" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree); \
CHECK_LYD_NODE_TERM((struct lyd_node_term *)tree, 0, 0, 1, 0, 1, TYPE, __VA_ARGS__); \
lyd_free_all(tree); \
}
#define TEST_ERROR_XML2(XML1, MOD_NAME, NAMESPACES, NODE_NAME, DATA, RET) \
{\
struct lyd_node *tree; \
const char *data = XML1 "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\" " NAMESPACES ">" DATA "</" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, RET, tree); \
assert_null(tree); \
}
#define TEST_SUCCESS_LYB(MOD_NAME, NODE_NAME, DATA) \
{ \
struct lyd_node *tree_1; \
struct lyd_node *tree_2; \
char *xml_out, *data; \
data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, LY_SUCCESS, tree_1); \
assert_int_equal(lyd_print_mem(&xml_out, tree_1, LYD_LYB, LYD_PRINT_WITHSIBLINGS), 0); \
assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, xml_out, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
assert_non_null(tree_2); \
CHECK_LYD(tree_1, tree_2); \
free(xml_out); \
lyd_free_all(tree_1); \
lyd_free_all(tree_2); \
}
static void
test_data_xml(void **state)
{
const char *schema;
const enum ly_path_pred_type val1[] = {LY_PATH_PREDTYPE_LEAFLIST};
/* xml test */
schema = MODULE_CREATE_YANG("defs", "identity ident1; identity ident2 {base ident1;}"
"leaf un1 {type union {"
" type leafref {path /int8; require-instance true;}"
" type leafref {path /int64; require-instance true;}"
" type union { type identityref {base ident1;} type instance-identifier {require-instance true;} }"
" type string {length 1..20;}}}"
"leaf int8 {type int8 {range 10..20;}}"
"leaf int64 {type int64;}"
"leaf-list llist {type string;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
TEST_SUCCESS_XML2("<int8 xmlns=\"urn:tests:defs\">12</int8>",
"defs", "", "un1", "12", UNION, "12", INT8, "12", 12);
TEST_SUCCESS_XML2("<int8 xmlns=\"urn:tests:defs\">12</int8>",
"defs", "", "un1", "2", UNION, "2", STRING, "2");
TEST_SUCCESS_XML2("<int8 xmlns=\"urn:tests:defs\">10</int8>",
"defs", "xmlns:x=\"urn:tests:defs\"", "un1", "x:ident2", UNION, "defs:ident2", IDENT, "defs:ident2", "ident2");
TEST_SUCCESS_XML2("<int8 xmlns=\"urn:tests:defs\">10</int8>",
"defs", "xmlns:x=\"urn:tests:defs\"", "un1", "x:ident55", UNION, "x:ident55", STRING, "x:ident55");
TEST_SUCCESS_XML2("<llist xmlns=\"urn:tests:defs\">x</llist>"
"<llist xmlns=\"urn:tests:defs\">y</llist>",
"defs", "xmlns:x=\"urn:tests:defs\"", "un1", "/x:llist[.='y']", UNION, "/defs:llist[.='y']",
INST, "/defs:llist[.='y']", val1);
TEST_SUCCESS_XML2("<llist xmlns=\"urn:tests:defs\">x</llist>"
"<llist xmlns=\"urn:tests:defs\">y</llist>",
"defs", "xmlns:x=\"urn:tests:defs\"", "un1", "/x:llist[3]", UNION, "/x:llist[3]",
STRING, "/x:llist[3]");
/* invalid value */
TEST_ERROR_XML2("",
"defs", "", "un1", "123456789012345678901", LY_EVALID);
CHECK_LOG_CTX("Invalid union value \"123456789012345678901\" - no matching subtype found:\n"
" libyang 2 - leafref, version 1: Invalid type int8 value \"123456789012345678901\".\n"
" libyang 2 - leafref, version 1: Invalid type int64 value \"123456789012345678901\".\n"
" libyang 2 - identityref, version 1: Invalid identityref \"123456789012345678901\" value - identity not found in module \"defs\".\n"
" libyang 2 - instance-identifier, version 1: Invalid instance-identifier \"123456789012345678901\" value - syntax error.\n"
" libyang 2 - string, version 1: Unsatisfied length - string \"123456789012345678901\" length is not allowed.\n",
"/defs:un1", 1);
}
static void
test_data_json(void **state)
{
const char *schema, *data;
struct lyd_node *tree;
/* xml test */
schema = MODULE_CREATE_YANG("defs", "leaf un21 {type union {type uint8; type string;}}"
"leaf un22 {type union {type uint16; type string;}}"
"leaf un2 {type union {type leafref {path /un21; require-instance false;} type leafref {path /un22; require-instance false;}}}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
data = "{\"defs:un2\":\"str\"}";
CHECK_PARSE_LYD_PARAM(data, LYD_JSON, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
CHECK_LYD_STRING_PARAM(tree, data, LYD_JSON, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS);
lyd_free_all(tree);
}
static void
test_plugin_lyb(void **state)
{
const char *schema;
schema = MODULE_CREATE_YANG("lyb",
"leaf int8 {type int8 {range 10..20;}}"
"leaf un1 {type union {"
" type leafref {path /int8; require-instance true;}"
" type string;}}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
TEST_SUCCESS_LYB("lyb", "un1", "12");
TEST_SUCCESS_LYB("lyb", "un1", "some_string");
TEST_SUCCESS_LYB("lyb", "un1", "");
}
static void
test_plugin_sort(void **state)
{
const char *v1, *v2;
const char *schema;
struct lys_module *mod;
struct lyd_value val1 = {0}, val2 = {0};
struct lyplg_type *type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_UNION]);
struct lysc_type *lysc_type;
struct ly_err_item *err = NULL;
schema = MODULE_CREATE_YANG("sort", "leaf-list ll {type union {type uint16; type int16;}}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
lysc_type = ((struct lysc_node_leaflist *)mod->compiled->data)->type;
v1 = "1";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
0, LY_VALUE_JSON, NULL, LYD_VALHINT_DECNUM, NULL, &val1, NULL, &err));
v2 = "-1";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
0, LY_VALUE_JSON, NULL, LYD_VALHINT_DECNUM, NULL, &val2, NULL, &err));
assert_true(0 < type->sort(UTEST_LYCTX, &val1, &val2));
assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val1));
assert_true(0 > type->sort(UTEST_LYCTX, &val2, &val1));
type->free(UTEST_LYCTX, &val1);
type->free(UTEST_LYCTX, &val2);
v1 = "-1";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
0, LY_VALUE_JSON, NULL, LYD_VALHINT_DECNUM, NULL, &val1, NULL, &err));
v2 = "-2";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
0, LY_VALUE_JSON, NULL, LYD_VALHINT_DECNUM, NULL, &val2, NULL, &err));
assert_true(0 < type->sort(UTEST_LYCTX, &val1, &val2));
assert_true(0 > type->sort(UTEST_LYCTX, &val2, &val1));
type->free(UTEST_LYCTX, &val1);
type->free(UTEST_LYCTX, &val2);
}
static void
test_validation(void **state)
{
const char *schema, *data;
struct lyd_node *tree;
char *out;
uint32_t uint_val;
schema = MODULE_CREATE_YANG("val",
"leaf l1 {\n"
" type union {\n"
" type uint32 {\n"
" range \"0..1048575\";\n"
" }\n"
" type enumeration {\n"
" enum auto;\n"
" }\n"
" }\n"
"}\n"
"leaf int8 {type int8 {range 10..20;}}\n"
"leaf l2 {\n"
" type union {\n"
" type leafref {path /int8; require-instance true;}\n"
" type string;\n"
" }\n"
"}\n");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
/* parse from LYB */
data = "<l1 xmlns=\"urn:tests:val\">auto</l1><int8 xmlns=\"urn:tests:val\">15</int8><l2 xmlns=\"urn:tests:val\">15</l2>";
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
assert_int_equal(LY_SUCCESS, lyd_print_mem(&out, tree, LYD_LYB, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS));
lyd_free_all(tree);
CHECK_PARSE_LYD_PARAM(out, LYD_LYB, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
free(out);
/* validate */
assert_int_equal(LY_SUCCESS, lyd_validate_all(&tree, NULL, LYD_VALIDATE_PRESENT, NULL));
/* print and compare */
assert_int_equal(LY_SUCCESS, lyd_print_mem(&out, tree, LYD_XML, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS));
assert_string_equal(out, data);
free(out);
lyd_free_all(tree);
schema = MODULE_CREATE_YANG("lref",
"container test {\n"
" list a {\n"
" key \"name\";\n"
" leaf name {\n"
" type enumeration {\n"
" enum zero;\n"
" enum one;\n"
" enum two;\n"
" }\n"
" }\n"
" }\n"
"\n"
" list b {\n"
" key \"name\";\n"
" leaf name {\n"
" type uint32;\n"
" }\n"
" }\n"
"\n"
" list community {\n"
" key \"name\";\n"
" leaf name {\n"
" type string;\n"
" }\n"
" leaf view {\n"
" type union {\n"
" type leafref {\n"
" path \"../../a/name\";\n"
" }\n"
" type leafref {\n"
" path \"../../b/name\";\n"
" }\n"
" }\n"
" }\n"
" }\n"
"}\n");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
/* parse from LYB #1 */
data = "<test xmlns=\"urn:tests:lref\"><b><name>2</name></b><community><name>test</name><view>2</view></community></test>";
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
assert_int_equal(LY_SUCCESS, lyd_print_mem(&out, tree, LYD_LYB, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS));
lyd_free_all(tree);
CHECK_PARSE_LYD_PARAM(out, LYD_LYB, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
free(out);
lyd_free_all(tree);
/* parse from LYB #2 */
data = "<test xmlns=\"urn:tests:lref\"><a><name>one</name></a><community><name>test</name><view>one</view></community></test>";
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
assert_int_equal(LY_SUCCESS, lyd_print_mem(&out, tree, LYD_LYB, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS));
lyd_free_all(tree);
CHECK_PARSE_LYD_PARAM(out, LYD_LYB, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
free(out);
/* remove the target and create another, which is represented the same way in LYB */
lyd_free_tree(lyd_child(tree));
uint_val = 1;
assert_int_equal(LY_SUCCESS, lyd_new_list(tree, NULL, "b", LYD_NEW_VAL_BIN, NULL, &uint_val, sizeof uint_val));
assert_int_equal(LY_EVALID, lyd_validate_all(&tree, NULL, LYD_VALIDATE_PRESENT, NULL));
CHECK_LOG_CTX("Invalid LYB union value - no matching subtype found:\n"
" libyang 2 - leafref, version 1: Invalid leafref value \"one\" - no target instance \"../../a/name\" with the same value.\n"
" libyang 2 - leafref, version 1: Invalid type uint32 value \"one\".\n", "/lref:test/community[name='test']/view", 0);
lyd_free_all(tree);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_data_xml),
UTEST(test_data_json),
UTEST(test_plugin_lyb),
UTEST(test_plugin_sort),
UTEST(test_validation),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

View file

@ -0,0 +1,323 @@
/**
* @file yang_types.c
* @author Michal Vaško <mvasko@cesnet.cz>
* @brief test for ietf-yang-types values
*
* Copyright (c) 2021 - 2023 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 UTEST HEADER */
#define _UTEST_MAIN_
#include "../utests.h"
#include <stdlib.h>
#include "compat.h"
#include "libyang.h"
#define MODULE_CREATE_YIN(MOD_NAME, NODES) \
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" \
"<module name=\"" MOD_NAME "\"\n" \
" xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"\n" \
" xmlns:pref=\"urn:tests:" MOD_NAME "\">\n" \
" <yang-version value=\"1.1\"/>\n" \
" <namespace uri=\"urn:tests:" MOD_NAME "\"/>\n" \
" <prefix value=\"pref\"/>\n" \
NODES \
"</module>\n"
#define MODULE_CREATE_YANG(MOD_NAME, NODES) \
"module " MOD_NAME " {\n" \
" yang-version 1.1;\n" \
" namespace \"urn:tests:" MOD_NAME "\";\n" \
" prefix pref;\n" \
" import ietf-yang-types {\n" \
" prefix yang;\n" \
" }\n" \
NODES \
"}\n"
#define TEST_SUCCESS_XML(MOD_NAME, NODE_NAME, DATA, TYPE, ...) \
{ \
struct lyd_node *tree; \
const char *data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree); \
CHECK_LYD_NODE_TERM((struct lyd_node_term *)tree, 0, 0, 0, 0, 1, TYPE, __VA_ARGS__); \
lyd_free_all(tree); \
}
#define TEST_ERROR_XML(MOD_NAME, NODE_NAME, DATA, RET) \
{\
struct lyd_node *tree; \
const char *data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, RET, tree); \
assert_null(tree); \
}
#define TEST_SUCCESS_LYB(MOD_NAME, NODE_NAME, DATA) \
{ \
struct lyd_node *tree_1; \
struct lyd_node *tree_2; \
char *xml_out, *data; \
data = "<" NODE_NAME " xmlns=\"urn:tests:" MOD_NAME "\">" DATA "</" NODE_NAME ">"; \
CHECK_PARSE_LYD_PARAM(data, LYD_XML, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, LY_SUCCESS, tree_1); \
assert_int_equal(lyd_print_mem(&xml_out, tree_1, LYD_LYB, LYD_PRINT_WITHSIBLINGS), 0); \
assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, xml_out, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree_2)); \
assert_non_null(tree_2); \
CHECK_LYD(tree_1, tree_2); \
free(xml_out); \
lyd_free_all(tree_1); \
lyd_free_all(tree_2); \
}
static void
test_data_xml(void **state)
{
const char *schema;
/* xml test */
schema = MODULE_CREATE_YANG("a",
"leaf l {type yang:date-and-time;}"
"leaf l21 {type yang:hex-string;}"
"leaf l22 {type yang:uuid;}"
"leaf l3 {type yang:xpath1.0;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
schema = MODULE_CREATE_YANG("b",
"");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
/* date-and-time */
TEST_SUCCESS_XML("a", "l", "2005-05-25T23:15:15.88888Z", STRING, "2005-05-25T21:15:15.88888-02:00");
TEST_SUCCESS_XML("a", "l", "2005-05-31T23:15:15-08:59", STRING, "2005-06-01T06:14:15-02:00");
TEST_SUCCESS_XML("a", "l", "2005-05-31T23:15:15-23:00", STRING, "2005-06-01T20:15:15-02:00");
/* test 1 second before epoch (mktime returns -1, but it is a correct value), with and without DST */
TEST_SUCCESS_XML("a", "l", "1970-01-01T00:59:59-02:00", STRING, "1970-01-01T00:59:59-02:00");
TEST_SUCCESS_XML("a", "l", "1969-12-31T23:59:59-02:00", STRING, "1969-12-31T23:59:59-02:00");
/* canonize */
TEST_SUCCESS_XML("a", "l", "2005-02-29T23:15:15-02:00", STRING, "2005-03-01T23:15:15-02:00");
/* fractional hours */
TEST_SUCCESS_XML("a", "l", "2005-05-25T23:15:15.88888+04:30", STRING, "2005-05-25T16:45:15.88888-02:00");
/* unknown timezone -- timezone conversion MUST NOT happen */
TEST_SUCCESS_XML("a", "l", "2017-02-01T00:00:00-00:00", STRING, "2017-02-01T00:00:00-00:00");
TEST_SUCCESS_XML("a", "l", "2021-02-29T00:00:00-00:00", STRING, "2021-03-01T00:00:00-00:00");
TEST_ERROR_XML("a", "l", "2005-05-31T23:15:15.-08:00", LY_EVALID);
CHECK_LOG_CTX("Unsatisfied pattern - \"2005-05-31T23:15:15.-08:00\" does not conform to "
"\"\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[\\+\\-]\\d{2}:\\d{2})\".",
"/a:l", 1);
TEST_ERROR_XML("a", "l", "2023-16-15T20:13:01+01:00", LY_EINVAL);
CHECK_LOG_CTX("Invalid date-and-time month \"15\".", "/a:l", 1);
TEST_ERROR_XML("a", "l", "2023-10-15T20:13:01+95:00", LY_EINVAL);
CHECK_LOG_CTX("Invalid date-and-time timezone hour \"95\".", "/a:l", 1);
/* hex-string */
TEST_SUCCESS_XML("a", "l21", "DB:BA:12:54:fa", STRING, "db:ba:12:54:fa");
TEST_SUCCESS_XML("a", "l22", "f81D4fAE-7dec-11d0-A765-00a0c91E6BF6", STRING, "f81d4fae-7dec-11d0-a765-00a0c91e6bf6");
/* xpath1.0 */
TEST_SUCCESS_XML("a\" xmlns:aa=\"urn:tests:a", "l3", "/aa:l3[. = '4']", STRING, "/a:l3[.='4']");
TEST_SUCCESS_XML("a\" xmlns:yl=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\" "
"xmlns:ds=\"urn:ietf:params:xml:ns:yang:ietf-datastores", "l3",
"/yl:yang-library/yl:datastore/yl:name = 'ds:running'", STRING,
"/ietf-yang-library:yang-library/datastore/name='ietf-datastores:running'");
TEST_SUCCESS_XML("a\" xmlns:a1=\"urn:tests:a\" xmlns:a2=\"urn:tests:a\" xmlns:bb=\"urn:tests:b", "l3",
"/a1:node1/a2:node2[a1:node3/bb:node4]/bb:node5 | bb:node6 and (bb:node7)", STRING,
"/a:node1/node2[node3/b:node4]/b:node5 | b:node6 and (b:node7)");
TEST_SUCCESS_XML("a", "l3", "/l3[. = '4']", STRING, "/l3[.='4']");
TEST_ERROR_XML("a", "l3", "/a:l3[. = '4']", LY_EVALID);
CHECK_LOG_CTX("Failed to resolve prefix \"a\".", "/a:l3", 1);
TEST_ERROR_XML("a\" xmlns:yl=\"urn:ietf:params:xml:ns:yang:ietf-yang-library", "l3",
"/yl:yang-library/yl:datastore/yl::name", LY_EVALID);
CHECK_LOG_CTX("Storing value failed.", "/a:l3", 1);
CHECK_LOG_CTX("Invalid character 'y'[31] of expression '/yl:yang-library/yl:datastore/yl::name'.", "/a:l3", 1);
}
static void
test_print(void **state)
{
const char *schema = MODULE_CREATE_YANG("a", "leaf l {type yang:xpath1.0;}");
const char *data, *expected;
struct lyd_node *tree;
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
/* XML data */
data = "<l xmlns=\"urn:tests:a\" xmlns:aa=\"urn:tests:a\">/aa:l[. = '/aa:l']</l>";
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
/* XML print */
expected = "<l xmlns=\"urn:tests:a\" xmlns:pref=\"urn:tests:a\">/pref:l[.='/pref:l']</l>";
CHECK_LYD_STRING_PARAM(tree, expected, LYD_XML, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS);
/* JSON print */
expected = "{\"a:l\":\"/a:l[.='/a:l']\"}";
CHECK_LYD_STRING_PARAM(tree, expected, LYD_JSON, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS);
lyd_free_tree(tree);
/* JSON data */
data = "{\"a:l\":\"/a:l/k/m[. = '/a:l']\"}";
CHECK_PARSE_LYD_PARAM(data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
/* XML print */
expected = "<l xmlns=\"urn:tests:a\" xmlns:pref=\"urn:tests:a\">/pref:l/pref:k/pref:m[.='/pref:l']</l>";
CHECK_LYD_STRING_PARAM(tree, expected, LYD_XML, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS);
/* JSON print */
expected = "{\"a:l\":\"/a:l/k/m[. = '/a:l']\"}";
CHECK_LYD_STRING_PARAM(tree, expected, LYD_JSON, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS);
lyd_free_tree(tree);
}
static void
test_duplicate(void **state)
{
const char *schema = MODULE_CREATE_YANG("a", "leaf l1 {type yang:date-and-time;} leaf l2 {type yang:xpath1.0;}");
const char *data, *expected;
struct lyd_node *tree, *dup;
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
data = "<l1 xmlns=\"urn:tests:a\">2005-05-25T23:15:15.88888+04:30</l1>"
"<l2 xmlns=\"urn:tests:a\" xmlns:aa=\"urn:tests:a\">/aa:l2[. = '/aa:l2']</l2>";
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
/* duplicate */
assert_int_equal(LY_SUCCESS, lyd_dup_siblings(tree, NULL, 0, &dup));
/* print */
expected = "<l1 xmlns=\"urn:tests:a\">2005-05-25T16:45:15.88888-02:00</l1>"
"<l2 xmlns=\"urn:tests:a\" xmlns:pref=\"urn:tests:a\">/pref:l2[.='/pref:l2']</l2>";
CHECK_LYD_STRING_PARAM(dup, expected, LYD_XML, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS);
lyd_free_siblings(tree);
lyd_free_siblings(dup);
}
static void
test_lyb(void **state)
{
const char *schema;
/* xml test */
schema = MODULE_CREATE_YANG("a",
"leaf l {type yang:date-and-time;}"
"leaf l2 {type yang:xpath1.0;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
/* date-and-time */
TEST_SUCCESS_LYB("a", "l", "2005-05-25T23:15:15.88888Z");
TEST_SUCCESS_LYB("a", "l", "2005-05-31T23:15:15-08:59");
TEST_SUCCESS_LYB("a", "l", "2005-05-01T20:15:15-00:00");
/* xpath1.0 */
TEST_SUCCESS_LYB("a\" xmlns:aa=\"urn:tests:a", "l2", "/aa:l2[. = '4']");
}
static void
test_sort(void **state)
{
const char *v1, *v2;
const char *schema;
struct lys_module *mod;
struct lyd_value val1 = {0}, val2 = {0};
struct lyplg_type *type = lyplg_type_plugin_find(NULL, "ietf-yang-types", "2013-07-15", "date-and-time");
struct lysc_type *lysc_type;
struct ly_err_item *err = NULL;
/* create schema. Prepare common used variables */
schema = MODULE_CREATE_YANG("a",
"leaf-list ll {type yang:date-and-time;}");
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
lysc_type = ((struct lysc_node_leaflist *)mod->compiled->data)->type;
/* v1 > v2, v2 < v1, v1 == v1 */
v1 = "2005-05-25T23:15:15Z";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
v2 = "2005-05-25T23:15:14Z";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
assert_true(0 < type->sort(UTEST_LYCTX, &val1, &val2));
assert_true(0 > type->sort(UTEST_LYCTX, &val2, &val1));
assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val1));
type->free(UTEST_LYCTX, &val1);
type->free(UTEST_LYCTX, &val2);
/* unknown timezone */
v1 = "2005-05-25T23:15:15Z";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
v2 = "2005-05-25T23:15:15-00:00";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val2));
type->free(UTEST_LYCTX, &val1);
type->free(UTEST_LYCTX, &val2);
/* fractions of a second */
v1 = "2005-05-25T23:15:15.88888Z";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
v2 = "2005-05-25T23:15:15.88889Z";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
assert_true(0 > type->sort(UTEST_LYCTX, &val1, &val2));
assert_true(0 < type->sort(UTEST_LYCTX, &val2, &val1));
assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val1));
type->free(UTEST_LYCTX, &val1);
type->free(UTEST_LYCTX, &val2);
/* zero fractions of a second */
v1 = "2005-05-25T23:15:15.00Z";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
v2 = "2005-05-25T23:15:15Z";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val2));
assert_int_equal(0, type->sort(UTEST_LYCTX, &val2, &val1));
type->free(UTEST_LYCTX, &val1);
type->free(UTEST_LYCTX, &val2);
/* zero fractions of a second and non-zero */
v1 = "2005-05-25T23:15:15.00Z";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
v2 = "2005-05-25T23:15:15.0001Z";
assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
assert_true(0 > type->sort(UTEST_LYCTX, &val1, &val2));
assert_true(0 < type->sort(UTEST_LYCTX, &val2, &val1));
assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val1));
type->free(UTEST_LYCTX, &val1);
type->free(UTEST_LYCTX, &val2);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
UTEST(test_data_xml),
UTEST(test_print),
UTEST(test_duplicate),
UTEST(test_lyb),
UTEST(test_sort),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

1414
tests/utests/utests.h Normal file

File diff suppressed because it is too large Load diff