/* * @file test_printer_xml.c * @author: Radek Krejci * @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 #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 = ""; CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree); /* canonized */ data = ""; CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data); lyd_free_all(tree); data = ""; 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 = "\n" " \n" " \n" " \n" " \n" " \n" " \n" "\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 = "\n" " \n" " \n" " \n" " \n" " \n" "\n"; CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data); lyd_free_all(tree); data = "\n" " \n" " ahoj jak se vede < how are you" " \n" "\n"; CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree); CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data); lyd_free_all(tree); data = "\n" " ahoj \n" " nazdar \n" " Čau \n" "\n"; CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree); CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data); lyd_free_all(tree); data = "\n" " \n" "\n"; CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree); CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data); lyd_free_all(tree); data = "\n" " \n" " < how are you" " \n" "\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 = "aa"; 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 = "/d:baa"; CHECK_LYD_STRING(tree, LYD_PRINT_WD_ALL | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data); data = "/d:b" "aa"; CHECK_LYD_STRING(tree, LYD_PRINT_WD_ALL_TAG | LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data); data = "/d:b" "aa"; 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 = "/d:baa"; 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 = "/d:bvalaa"; data_trim = "valaa"; data_all = "/d:bvalaa"; data_all_tag = "/d:b" "val" "aa"; data_impl_tag = "/d:bvalaa"; 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 = "1020"; reply = "30"; result = "30"; 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 = ""; reply = ""; result = ""; 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 = "10test"; reply = "test-reply"; result = "10test-reply"; 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); }