diff options
Diffstat (limited to 'tests')
171 files changed, 8692 insertions, 1195 deletions
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6f36f31..259ef34 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -45,6 +45,8 @@ if(ENABLE_TESTS) add_subdirectory(style) add_subdirectory(fuzz) endif() + add_subdirectory(yanglint) + add_subdirectory(yangre) endif() if(ENABLE_PERF_TESTS) add_subdirectory(perf) diff --git a/tests/tool_i.tcl b/tests/tool_i.tcl new file mode 100644 index 0000000..d0f3d4b --- /dev/null +++ b/tests/tool_i.tcl @@ -0,0 +1,156 @@ +# @brief Common functions and variables for Tool Under Test (TUT). +# +# The script requires variables: +# TUT_PATH - Assumed absolute path to the directory in which the TUT is located. +# TUT_NAME - TUT name (without path). +# +# The script sets the variables: +# TUT - The path (including the name) of the executable TUT. +# error_prompt - Delimiter on error. +# error_head - Header on error. + +package require Expect + +# Complete the path for Tool Under Test (TUT). For example, on Windows, TUT can be located in the Debug or Release +# subdirectory. Note that Release build takes precedence over Debug. +set conftypes {{} Release Debug} +foreach i $conftypes { + if { [file executable "$TUT_PATH/$i/$TUT_NAME"] || [file executable "$TUT_PATH/$i/$TUT_NAME.exe"] } { + set TUT "$TUT_PATH/$i/$TUT_NAME" + break + } +} +if {![info exists TUT]} { + error "$TUT_NAME executable not found" +} + +# prompt of error message +set error_prompt ">>>" +# the beginning of error message +set error_head "$error_prompt Check-failed" + +# detection on eof and timeout will be on every expect command +expect_after { + eof { + global error_head + error "$error_head unexpected termination" + } timeout { + global error_head + error "$error_head timeout" + } +} + +# Run commands from command line +tcltest::loadTestedCommands + +# namespace of internal functions +namespace eval ly::private {} + +# Send command 'cmd' to the process, then check output string by 'pattern'. +# Parameter cmd is a string of arguments. +# Parameter pattern is a regex or an exact string to match. If is not specified, only prompt assumed afterwards. +# It must not contain a prompt. There can be an '$' character at the end of the pattern, in which case the regex +# matches the characters before the prompt. +# Parameter 'opt' can contain: +# -ex has a similar meaning to the expect command. The 'pattern' parameter is used as a simple string +# for exact matching of the output. So 'pattern' is not a regular expression but some characters +# must still be escaped, eg ][. +proc ly_cmd {cmd {pattern ""} {opt ""}} { + global prompt + + send -- "${cmd}\r" + expect -- "${cmd}\r\n" + + if { $pattern eq "" } { + # command without output + expect ^$prompt + return + } + + # definition of an expression that matches failure + set failure_pattern "\r\n${prompt}$" + + if { $opt eq "" && [string index $pattern end] eq "$"} { + # check output by regular expression + # It was explicitly specified how the expression should end. + set pattern [string replace $pattern end end] + expect { + -re "${pattern}\r\n${prompt}$" {} + -re $failure_pattern { + error "unexpected output:\n$expect_out(buffer)" + } + } + } elseif { $opt eq "" } { + # check output by regular expression + expect { + -re "${pattern}.*\r\n${prompt}$" {} + -re $failure_pattern { + error "unexpected output:\n$expect_out(buffer)" + } + } + } elseif { $opt eq "-ex" } { + # check output by exact matching + expect { + -ex "${pattern}\r\n${prompt}" {} + -re $failure_pattern { + error "unexpected output:\n$expect_out(buffer)" + } + } + } else { + global error_head + error "$error_head unrecognized value of parameter 'opt'" + } +} + +# Send command 'cmd' to the process, expect some header and then check output string by 'pattern'. +# This function is useful for checking an error that appears in the form of a header. +# Parameter header is the expected header on the output. +# Parameter cmd is a string of arguments. +# Parameter pattern is a regex. It must not contain a prompt. +proc ly_cmd_header {cmd header pattern} { + global prompt + + send -- "${cmd}\r" + expect -- "${cmd}\r\n" + + expect { + -re "$header .*${pattern}.*\r\n${prompt}$" {} + -re "\r\n${prompt}$" { + error "unexpected output:\n$expect_out(buffer)" + } + } +} + +# Whatever is written is sent, output is ignored and then another prompt is expected. +# Parameter cmd is optional and any output is ignored. +proc ly_ignore {{cmd ""}} { + global prompt + + send "${cmd}\r" + expect -re "$prompt$" +} + +# Send a completion request and check if the anchored regex output matches. +proc ly_completion {input output} { + global prompt + + send -- "${input}\t" + # expecting echoing input, output and 10 terminal control characters + expect -re "^${input}\r${prompt}${output}.*\r.*$" +} + +# Send a completion request and check if the anchored regex hint options match. +proc ly_hint {input prev_input hints} { + global prompt + + set output {} + foreach i $hints { + # each element might have some number of spaces and CRLF around it + append output "${i} *(?:\\r\\n)?" + } + + send -- "${input}\t" + # expecting the hints, previous input from which the hints were generated + # and some number of terminal control characters + expect -re "${output}\r${prompt}${prev_input}.*\r.*$" +} diff --git a/tests/tool_ni.tcl b/tests/tool_ni.tcl new file mode 100644 index 0000000..7282d35 --- /dev/null +++ b/tests/tool_ni.tcl @@ -0,0 +1,141 @@ +# @brief Common functions and variables for Tool Under Test (TUT). +# +# The script requires variables: +# TUT_PATH - Assumed absolute path to the directory in which the TUT is located. +# TUT_NAME - TUT name (without path). +# +# The script sets the variables: +# TUT - The path (including the name) of the executable TUT. +# error_prompt - Delimiter on error. +# error_head - Header on error. + +# Complete the path for Tool Under Test (TUT). For example, on Windows, TUT can be located in the Debug or Release +# subdirectory. Note that Release build takes precedence over Debug. +set conftypes {{} Release Debug} +foreach i $conftypes { + if { [file executable "$TUT_PATH/$i/$TUT_NAME"] || [file executable "$TUT_PATH/$i/$TUT_NAME.exe"] } { + set TUT "$TUT_PATH/$i/$TUT_NAME" + break + } +} +if {![info exists TUT]} { + error "$TUT_NAME executable not found" +} + +# prompt of error message +set error_prompt ">>>" +# the beginning of error message +set error_head "$error_prompt Check-failed" + +# Run commands from command line +tcltest::loadTestedCommands + +# namespace of internal functions +namespace eval ly::private { + namespace export * +} + +# Run the process with arguments. +# Parameter cmd is a string with arguments. +# Parameter wrn is a flag. Set to 1 if stderr should be ignored. +# Returns a pair where the first is the return code and the second is the output. +proc ly::private::ly_exec {cmd {wrn ""}} { + global TUT + try { + set results [exec -- $TUT {*}$cmd] + set status 0 + } trap CHILDSTATUS {results options} { + # return code is not 0 + set status [lindex [dict get $options -errorcode] 2] + } trap NONE results { + if { $wrn == 1 } { + set status 0 + } else { + error "return code is 0 but something was written to stderr:\n$results\n" + } + } trap CHILDKILLED {results options} { + set status [lindex [dict get $options -errorcode] 2] + error "process was killed: $status" + } + list $status $results +} + +# Internal function. +# Check the output with pattern. +# Parameter pattern is a regex or an exact string to match. +# Parameter msg is the output to check. +# Parameter 'opt' is optional. If contains '-ex', then the 'pattern' parameter is +# used as a simple string for exact matching of the output. +proc ly::private::output_check {pattern msg {opt ""}} { + if { $opt eq "" } { + expr {![regexp -- $pattern $msg]} + } elseif { $opt eq "-ex" } { + expr {![string equal "$pattern" $msg]} + } else { + global error_head + error "$error_head unrecognized value of parameter 'opt'" + } +} + +# Execute yanglint with arguments and expect success. +# Parameter cmd is a string of arguments. +# Parameter pattern is a regex or an exact string to match. +# Parameter 'opt' is optional. If contains '-ex', then the 'pattern' parameter is +# used as a simple string for exact matching of the output. +proc ly_cmd {cmd {pattern ""} {opt ""}} { + namespace import ly::private::* + lassign [ly_exec $cmd] rc msg + if { $rc != 0 } { + error "unexpected return code $rc:\n$msg\n" + } + if { $pattern ne "" && [output_check $pattern $msg $opt] } { + error "unexpected output:\n$msg\n" + } + return +} + +# Execute yanglint with arguments and expect error. +# Parameter cmd is a string of arguments. +# Parameter pattern is a regex. +proc ly_cmd_err {cmd pattern} { + namespace import ly::private::* + lassign [ly_exec $cmd] rc msg + if { $rc == 0 } { + error "unexpected return code $rc" + } + if { [output_check $pattern $msg] } { + error "unexpected output:\n$msg\n" + } + return +} + +# Execute yanglint with arguments, expect warning in stderr but success. +# Parameter cmd is a string of arguments. +# Parameter pattern is a regex. +proc ly_cmd_wrn {cmd pattern} { + namespace import ly::private::* + lassign [ly_exec $cmd 1] rc msg + if { $rc != 0 } { + error "unexpected return code $rc:\n$msg\n" + } + if { [output_check $pattern $msg] } { + error "unexpected output:\n$msg\n" + } + return +} + +# Check if yanglint supports the specified option. +# Parameter opt is a option to be found. +# Return true if option is found otherwise false. +proc ly_opt_exists {opt} { + namespace import ly::private::* + lassign [ly_exec "--help"] rc msg + if { $rc != 0 } { + error "unexpected return code $rc:\n$msg\n" + } + if { [output_check $opt $msg] } { + return false + } else { + return true + } +} diff --git a/tests/utests/basic/test_common.c b/tests/utests/basic/test_common.c index 75235a2..46b80ab 100644 --- a/tests/utests/basic/test_common.c +++ b/tests/utests/basic/test_common.c @@ -1,4 +1,4 @@ -/* +/** * @file test_common.c * @author: Radek Krejci <rkrejci@cesnet.cz> * @brief unit tests for functions from common.c diff --git a/tests/utests/basic/test_context.c b/tests/utests/basic/test_context.c index 4c4cc3f..cfba1d3 100644 --- a/tests/utests/basic/test_context.c +++ b/tests/utests/basic/test_context.c @@ -1,4 +1,4 @@ -/* +/** * @file test_context.c * @author: Radek Krejci <rkrejci@cesnet.cz> * @brief unit tests for functions from context.c @@ -298,8 +298,8 @@ test_models(void **state) assert_int_equal(LY_EVALID, lys_parse_in(UTEST_LYCTX, in, LYS_IN_YANG, NULL, NULL, &unres.creating, &mod1)); lys_unres_glob_erase(&unres); ly_in_free(in, 0); - CHECK_LOG_CTX("Parsing module \"y\" failed.", NULL, - "Name collision between module and submodule of name \"y\".", "Line number 1."); + CHECK_LOG_CTX("Parsing module \"y\" failed.", NULL); + CHECK_LOG_CTX("Name collision between module and submodule of name \"y\".", "Line number 1."); assert_int_equal(LY_SUCCESS, ly_in_new_memory("module a {namespace urn:a;prefix a;include y;revision 2018-10-30; }", &in)); assert_int_equal(LY_SUCCESS, lys_parse_in(UTEST_LYCTX, in, LYS_IN_YANG, NULL, NULL, &unres.creating, &mod1)); @@ -308,8 +308,8 @@ test_models(void **state) assert_int_equal(LY_EVALID, lys_parse_in(UTEST_LYCTX, in, LYS_IN_YANG, NULL, NULL, &unres.creating, &mod1)); lys_unres_glob_erase(&unres); ly_in_free(in, 0); - CHECK_LOG_CTX("Parsing module \"y\" failed.", NULL, - "Name collision between module and submodule of name \"y\".", "Line number 1."); + CHECK_LOG_CTX("Parsing module \"y\" failed.", NULL); + CHECK_LOG_CTX("Name collision between module and submodule of name \"y\".", "Line number 1."); ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, "submodule y {belongs-to b {prefix b;}}"); assert_int_equal(LY_SUCCESS, ly_in_new_memory("module b {namespace urn:b;prefix b;include y;}", &in)); @@ -317,10 +317,10 @@ test_models(void **state) lys_unres_glob_revert(UTEST_LYCTX, &unres); lys_unres_glob_erase(&unres); ly_in_free(in, 0); - CHECK_LOG_CTX("Parsing module \"b\" failed.", NULL, - "Including \"y\" submodule into \"b\" failed.", NULL, - "Parsing submodule failed.", NULL, - "Name collision between submodules of name \"y\".", "Line number 1."); + CHECK_LOG_CTX("Parsing module \"b\" failed.", NULL); + CHECK_LOG_CTX("Including \"y\" submodule into \"b\" failed.", NULL); + CHECK_LOG_CTX("Parsing submodule failed.", NULL); + CHECK_LOG_CTX("Name collision between submodules of name \"y\".", "Line number 1."); /* selecting correct revision of the submodules */ ly_ctx_reset_latests(UTEST_LYCTX); @@ -338,19 +338,6 @@ test_models(void **state) assert_non_null(mod1->compiled); assert_non_null(mod1->parsed); -#if 0 - /* TODO in case we are able to remove the parsed schema, here we will test how it will handle missing import parsed schema */ - - assert_int_equal(LY_SUCCESS, ly_in_new_memory("module z {namespace urn:z;prefix z;import w {prefix w;revision-date 2018-10-24;}}", &in)); - /* mod1->parsed is necessary to compile mod2 because of possible groupings, typedefs, ... */ - ly_ctx_set_module_imp_clb(UTEST_LYCTX, NULL, NULL); - assert_int_equal(LY_ENOTFOUND, lys_create_module(UTEST_LYCTX, in, LYS_IN_YANG, 1, NULL, NULL, &mod2)); - /*logbuf_assert("Unable to reload \"w\" module to import it into \"z\", source data not found.");*/ - CHECK_LOG_CTX("Recompilation of module \"w\" failed.", NULL); - assert_null(mod2); - ly_in_free(in, 0); -#endif - assert_int_equal(LY_SUCCESS, ly_in_new_memory("module z {namespace urn:z;prefix z;import w {prefix w;revision-date 2018-10-24;}}", &in)); ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, "module w {namespace urn:w;prefix w;revision 2018-10-24;}"); assert_int_equal(LY_SUCCESS, lys_parse(UTEST_LYCTX, in, LYS_IN_YANG, NULL, &mod2)); @@ -425,6 +412,7 @@ test_imports(void **state) "import a {prefix a;}" "}"; assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL)); + ly_err_clean(UTEST_LYCTX, NULL); } static void diff --git a/tests/utests/basic/test_hash_table.c b/tests/utests/basic/test_hash_table.c index 25b595a..78950cd 100644 --- a/tests/utests/basic/test_hash_table.c +++ b/tests/utests/basic/test_hash_table.c @@ -1,4 +1,4 @@ -/* +/** * @file test_hash_table.c * @author: Radek Krejci <rkrejci@cesnet.cz> * @brief unit tests for functions from hash_table.c @@ -19,8 +19,6 @@ #include "common.h" #include "hash_table.h" -struct ht_rec *lyht_get_rec(unsigned char *recs, uint16_t rec_size, uint32_t idx); - static void test_invalid_arguments(void **state) { @@ -83,7 +81,7 @@ static void test_ht_basic(void **state) { uint32_t i; - struct hash_table *ht; + struct ly_ht *ht; assert_non_null(ht = lyht_new(8, sizeof(int), ht_equal_clb, NULL, 0)); @@ -96,15 +94,14 @@ test_ht_basic(void **state) assert_int_equal(LY_ENOTFOUND, lyht_remove(ht, &i, i)); CHECK_LOG("Invalid argument hash (lyht_remove_with_resize_cb()).", NULL); - lyht_free(ht); + lyht_free(ht, NULL); } static void test_ht_resize(void **state) { uint32_t i; - struct ht_rec *rec; - struct hash_table *ht; + struct ly_ht *ht; assert_non_null(ht = lyht_new(8, sizeof(int), ht_equal_clb, NULL, 1)); assert_int_equal(8, ht->size); @@ -120,13 +117,12 @@ test_ht_resize(void **state) for (i = 0; i < 16; ++i) { if ((i >= 2) && (i < 8)) { /* inserted data on indexes 2-7 */ - rec = lyht_get_rec(ht->recs, ht->rec_size, i); - assert_int_equal(1, rec->hits); - assert_int_equal(i, rec->hash); + assert_int_not_equal(UINT32_MAX, ht->hlists[i].first); + assert_int_equal(LY_SUCCESS, lyht_find(ht, &i, i, NULL)); } else { /* nothing otherwise */ - rec = lyht_get_rec(ht->recs, ht->rec_size, i); - assert_int_equal(0, rec->hits); + assert_int_equal(UINT32_MAX, ht->hlists[i].first); + assert_int_equal(LY_ENOTFOUND, lyht_find(ht, &i, i, NULL)); } } @@ -153,7 +149,7 @@ test_ht_resize(void **state) } /* cleanup */ - lyht_free(ht); + lyht_free(ht, NULL); } static void @@ -162,8 +158,10 @@ test_ht_collisions(void **UNUSED(state)) #define GET_REC_INT(rec) (*((uint32_t *)&(rec)->val)) uint32_t i; - struct ht_rec *rec; - struct hash_table *ht; + 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)); @@ -172,66 +170,69 @@ test_ht_collisions(void **UNUSED(state)) } /* check all records */ - for (i = 0; i < 2; ++i) { - rec = lyht_get_rec(ht->recs, ht->rec_size, i); - assert_int_equal(rec->hits, 0); + 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); + } } - rec = lyht_get_rec(ht->recs, ht->rec_size, i); - assert_int_equal(rec->hits, 4); - assert_int_equal(GET_REC_INT(rec), i); - ++i; - for ( ; i < 6; ++i) { - rec = lyht_get_rec(ht->recs, ht->rec_size, i); - assert_int_equal(rec->hits, 1); - assert_int_equal(GET_REC_INT(rec), i); + 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)); + } } - for ( ; i < 8; ++i) { - rec = lyht_get_rec(ht->recs, ht->rec_size, i); - assert_int_equal(rec->hits, 0); + 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); - assert_int_equal(rec->hits, -1); i = 2; assert_int_equal(lyht_remove(ht, &i, 2), 0); /* check all records */ - for (i = 0; i < 2; ++i) { - rec = lyht_get_rec(ht->recs, ht->rec_size, i); - assert_int_equal(rec->hits, 0); + 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); + } } - rec = lyht_get_rec(ht->recs, ht->rec_size, i); - assert_int_equal(rec->hits, 2); - assert_int_equal(GET_REC_INT(rec), 5); - ++i; - rec = lyht_get_rec(ht->recs, ht->rec_size, i); - assert_int_equal(rec->hits, 1); - assert_int_equal(GET_REC_INT(rec), 3); - ++i; - for ( ; i < 6; ++i) { - rec = lyht_get_rec(ht->recs, ht->rec_size, i); - assert_int_equal(rec->hits, -1); + 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)); + } } - for ( ; i < 8; ++i) { - rec = lyht_get_rec(ht->recs, ht->rec_size, i); - assert_int_equal(rec->hits, 0); + 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 < 3; ++i) { - assert_int_equal(lyht_find(ht, &i, 2, NULL), LY_ENOTFOUND); - } - assert_int_equal(lyht_find(ht, &i, 2, NULL), LY_SUCCESS); - ++i; - assert_int_equal(lyht_find(ht, &i, 2, NULL), LY_ENOTFOUND); - ++i; - assert_int_equal(lyht_find(ht, &i, 2, NULL), LY_SUCCESS); - ++i; - for ( ; i < 8; ++i) { - assert_int_equal(lyht_find(ht, &i, 2, NULL), LY_ENOTFOUND); + 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; @@ -240,20 +241,11 @@ test_ht_collisions(void **UNUSED(state)) assert_int_equal(lyht_remove(ht, &i, 2), 0); /* check all records */ - for (i = 0; i < 2; ++i) { - rec = lyht_get_rec(ht->recs, ht->rec_size, i); - assert_int_equal(rec->hits, 0); - } - for ( ; i < 6; ++i) { - rec = lyht_get_rec(ht->recs, ht->rec_size, i); - assert_int_equal(rec->hits, -1); - } - for ( ; i < 8; ++i) { - rec = lyht_get_rec(ht->recs, ht->rec_size, i); - assert_int_equal(rec->hits, 0); + for (i = 0; i < 8; ++i) { + assert_int_equal(UINT32_MAX, ht->hlists[i].first); } - lyht_free(ht); + lyht_free(ht, NULL); } int diff --git a/tests/utests/basic/test_inout.c b/tests/utests/basic/test_inout.c index be27510..3f83568 100644 --- a/tests/utests/basic/test_inout.c +++ b/tests/utests/basic/test_inout.c @@ -84,8 +84,11 @@ test_input_mem(void **UNUSED(state)) 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)); @@ -103,12 +106,15 @@ test_input_fd(void **UNUSED(state)) 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)); diff --git a/tests/utests/basic/test_json.c b/tests/utests/basic/test_json.c index 1896b8a..08b7719 100644 --- a/tests/utests/basic/test_json.c +++ b/tests/utests/basic/test_json.c @@ -1,4 +1,4 @@ -/* +/** * @file test_json.c * @author: Radek Krejci <rkrejci@cesnet.cz> * @brief unit tests for a generic JSON parser @@ -27,39 +27,40 @@ test_general(void **state) /* empty */ str = ""; assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx, 0)); - lyjson_ctx_free(jsonctx); + assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx)); + CHECK_LOG_CTX("Empty JSON file.", "Line number 1."); str = " \n\t \n"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx, 0)); - lyjson_ctx_free(jsonctx); + assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx)); + CHECK_LOG_CTX("Empty JSON file.", "Line number 3."); /* constant values */ str = "true"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_TRUE, lyjson_ctx_status(jsonctx, 0)); + 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, 0)); + 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, 0, &jsonctx)); - assert_int_equal(LYJSON_FALSE, lyjson_ctx_status(jsonctx, 0)); + 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, 0)); + 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, 0, &jsonctx)); - assert_int_equal(LYJSON_NULL, lyjson_ctx_status(jsonctx, 0)); + 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, 0)); + assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx)); lyjson_ctx_free(jsonctx); ly_in_free(in, 0); @@ -75,8 +76,8 @@ test_number(void **state) /* 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, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -85,8 +86,8 @@ test_number(void **state) /* fraction number */ str = "37.7668"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -95,8 +96,8 @@ test_number(void **state) /* negative number */ str = "-122.3959"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -105,8 +106,8 @@ test_number(void **state) /* integer, positive exponent */ str = "550E3"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -114,8 +115,8 @@ test_number(void **state) str = "-550E3"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -124,8 +125,8 @@ test_number(void **state) /* 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, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -133,8 +134,8 @@ test_number(void **state) str = "15E-1"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -142,8 +143,8 @@ test_number(void **state) str = "-15E-1"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -151,8 +152,8 @@ test_number(void **state) str = "16E-2"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -160,8 +161,8 @@ test_number(void **state) str = "-16E-2"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -169,8 +170,8 @@ test_number(void **state) str = "17E-3"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -178,8 +179,8 @@ test_number(void **state) str = "-17E-3"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -187,8 +188,8 @@ test_number(void **state) str = "21000E-2"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -196,8 +197,8 @@ test_number(void **state) str = "21000E-4"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -205,8 +206,8 @@ test_number(void **state) str = "21000E-7"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -215,8 +216,8 @@ test_number(void **state) /* 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, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -224,8 +225,8 @@ test_number(void **state) str = "-5.087E1"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -233,8 +234,8 @@ test_number(void **state) str = "5.087E5"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -242,8 +243,8 @@ test_number(void **state) str = "59.1e+1"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -251,8 +252,8 @@ test_number(void **state) str = "0.005087E1"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -260,8 +261,8 @@ test_number(void **state) str = "0.005087E2"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -269,8 +270,8 @@ test_number(void **state) str = "0.005087E6"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -278,8 +279,8 @@ test_number(void **state) str = "0.05087E6"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -287,8 +288,8 @@ test_number(void **state) str = "0.005087E8"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -297,8 +298,8 @@ test_number(void **state) /* 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, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -306,8 +307,8 @@ test_number(void **state) str = "-35.94e-1"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -315,8 +316,8 @@ test_number(void **state) str = "35.94e-2"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -324,8 +325,8 @@ test_number(void **state) str = "35.94e-3"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -333,8 +334,8 @@ test_number(void **state) str = "0.3594e-1"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -342,8 +343,8 @@ test_number(void **state) str = "0.03594e-1"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -351,8 +352,8 @@ test_number(void **state) str = "0.003594e-1"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -360,8 +361,8 @@ test_number(void **state) str = "0.3594e-2"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -369,8 +370,8 @@ test_number(void **state) str = "0.03594e-2"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -378,8 +379,8 @@ test_number(void **state) str = "0.003594e-2"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -388,8 +389,8 @@ test_number(void **state) /* zero */ str = "0"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -397,8 +398,8 @@ test_number(void **state) str = "-0"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -407,8 +408,8 @@ test_number(void **state) str = "94E0"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -417,8 +418,8 @@ test_number(void **state) str = "0E2"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -426,8 +427,8 @@ test_number(void **state) str = "-0E2"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -436,8 +437,8 @@ test_number(void **state) str = "5.320e+2"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -445,8 +446,8 @@ test_number(void **state) str = "5.320e-1"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_NUMBER, lyjson_ctx_status(jsonctx, 0)); + 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); @@ -455,69 +456,64 @@ test_number(void **state) /* various invalid inputs */ str = "-x"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); + assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx)); CHECK_LOG_CTX("Invalid character in JSON Number value (\"x\").", "Line number 1."); str = " -"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); + assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx)); CHECK_LOG_CTX("Unexpected end-of-input.", "Line number 1."); str = "--1"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); + assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx)); CHECK_LOG_CTX("Invalid character in JSON Number value (\"-\").", "Line number 1."); str = "+1"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); + assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx)); CHECK_LOG_CTX("Invalid character sequence \"+1\", expected a JSON value.", "Line number 1."); str = " 1.x "; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); + assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx)); CHECK_LOG_CTX("Invalid character in JSON Number value (\"x\").", "Line number 1."); str = "1."; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); + assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx)); CHECK_LOG_CTX("Unexpected end-of-input.", "Line number 1."); str = " 1eo "; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); + assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx)); CHECK_LOG_CTX("Invalid character in JSON Number value (\"o\").", "Line number 1."); str = "1e"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); + assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, &jsonctx)); CHECK_LOG_CTX("Unexpected end-of-input.", "Line number 1."); str = "1E1000"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); + 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.", "Line number 1."); str = "1e9999999999999999999"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); + 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).", "Line number 1."); str = "1.1e66000"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); + 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).", "Line number 1."); str = "1.1e-66000"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); + 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).", "Line number 1."); - str = "-2.1e0."; - assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - CHECK_LOG_CTX("Unexpected character \".\" after JSON number.", "Line number 1."); - ly_in_free(in, 0); } @@ -532,68 +528,12 @@ test_string(void **state) str = ""; assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in)); -#if 0 - /* simple string */ - str = "\"hello\""; - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_STRING, lyjson_ctx_status(jsonctx, 0)); - assert_ptr_equal(&str[1], jsonctx->value); - assert_int_equal(5, jsonctx->value_len); - assert_int_equal(0, jsonctx->dynamic); - lyjson_ctx_free(jsonctx); - - /* 4-byte utf8 character */ - str = "\"\\t𠜎\""; - assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_STRING, lyjson_ctx_status(jsonctx, 0)); - assert_string_equal("\t𠜎", jsonctx->value); - assert_int_equal(5, jsonctx->value_len); - assert_int_equal(1, jsonctx->dynamic); - lyjson_ctx_free(jsonctx); - - /* valid escape sequences - note that here it mixes valid JSON string characters (RFC 7159, sec. 7) and - * valid characters in YANG string type (RFC 7950, sec. 9.4). Since the latter is a subset of JSON string, - * the YANG string type's restrictions apply to the JSON escape sequences */ - str = "\"\\\" \\\\ \\r \\/ \\n \\t \\u20ac\""; - assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_STRING, lyjson_ctx_status(jsonctx, 0)); - assert_string_equal("\" \\ \r / \n \t €", jsonctx->value); - assert_int_equal(15, jsonctx->value_len); - assert_int_equal(1, jsonctx->dynamic); - lyjson_ctx_free(jsonctx); - - /* backspace and form feed are valid JSON escape sequences, but the control characters they represents are not allowed values for YANG string type */ - str = "\"\\b\""; - assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - CHECK_LOG_CTX("Invalid character reference \"\\b\" (0x00000008).", "Line number 1."); - - str = "\"\\f\""; - assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - CHECK_LOG_CTX("Invalid character reference \"\\f\" (0x0000000c).", "Line number 1."); -#endif - /* unterminated string */ str = "\"unterminated string"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); + 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.", "Line number 1."); -#if 0 - /* invalid escape sequence */ - str = "\"char \\x \""; - assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - CHECK_LOG_CTX("Invalid character escape sequence \\x.", "Line number 1."); - - /* new line is allowed only as escaped character in JSON */ - str = "\"\n\""; - assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - CHECK_LOG_CTX("Invalid character in JSON string \"\n\" (0x0000000a).", "Line number 1."); -#endif + CHECK_LOG_CTX("Unexpected end-of-input.", "Line number 1."); ly_in_free(in, 0); } @@ -608,95 +548,122 @@ test_object(void **state) /* empty */ str = " { } "; assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_OBJECT_EMPTY, lyjson_ctx_status(jsonctx, 0)); + 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, 0)); + 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, 0, &jsonctx)); - assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx, 0)); + + 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_string_equal("\"Radek\"}", jsonctx->in->current); + assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL)); - assert_int_equal(LYJSON_STRING, lyjson_ctx_status(jsonctx, 0)); + 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_string_equal("}", jsonctx->in->current); + assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL)); - assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx, 0)); + 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, 0)); + 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, 0, &jsonctx)); - assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx, 0)); + 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_string_equal("true,\"handsom\":false}", jsonctx->in->current); + + 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_TRUE, lyjson_ctx_status(jsonctx, 0)); - assert_string_equal(",\"handsom\":false}", jsonctx->in->current); + 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, lyjson_ctx_status(jsonctx, 0)); + 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_string_equal("false}", jsonctx->in->current); + assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL)); - assert_int_equal(LYJSON_FALSE, lyjson_ctx_status(jsonctx, 0)); - assert_string_equal("}", jsonctx->in->current); + 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, 0)); + 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, 0)); + 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, 0, &jsonctx)); - assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx, 0)); + 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_string_equal("{\"name\":\"Radek\"}}", jsonctx->in->current); + assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL)); - assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx, 0)); + 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_string_equal("\"Radek\"}}", jsonctx->in->current); + assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL)); - assert_int_equal(LYJSON_STRING, lyjson_ctx_status(jsonctx, 0)); + 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_string_equal("}}", jsonctx->in->current); + assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL)); - assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx, 0)); - assert_string_equal("}", jsonctx->in->current); + 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, 0)); + 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, 0)); + assert_int_equal(LYJSON_END, lyjson_ctx_status(jsonctx)); lyjson_ctx_free(jsonctx); - /* new line is allowed only as escaped character in JSON */ + /* unquoted string */ str = "{ unquoted : \"data\"}"; assert_non_null(ly_in_memory(in, str)); - assert_int_equal(LY_EVALID, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - CHECK_LOG_CTX("Invalid character sequence \"unquoted : \"data\"}\", expected a JSON object's member.", "Line number 1."); + 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.", "Line number 1."); + lyjson_ctx_free(jsonctx); ly_in_free(in, 0); } @@ -711,67 +678,79 @@ test_array(void **state) /* empty */ str = " [ ] "; assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in)); - assert_int_equal(LY_SUCCESS, lyjson_ctx_new(UTEST_LYCTX, in, 0, &jsonctx)); - assert_int_equal(LYJSON_ARRAY_EMPTY, lyjson_ctx_status(jsonctx, 0)); + 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, 0)); + 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, 0, &jsonctx)); - assert_int_equal(LYJSON_ARRAY, lyjson_ctx_status(jsonctx, 0)); + 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_string_equal("null]", jsonctx->in->current); + assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL)); - assert_int_equal(LYJSON_NULL, lyjson_ctx_status(jsonctx, 0)); - assert_string_equal("]", jsonctx->in->current); + 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, 0)); + 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, 0)); + 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, 0, &jsonctx)); - assert_int_equal(LYJSON_ARRAY, lyjson_ctx_status(jsonctx, 0)); + 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_string_equal("{\"a\":null},\"x\"]", jsonctx->in->current); + assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL)); - assert_int_equal(LYJSON_OBJECT, lyjson_ctx_status(jsonctx, 0)); + 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_string_equal("null},\"x\"]", jsonctx->in->current); + assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL)); - assert_int_equal(LYJSON_NULL, lyjson_ctx_status(jsonctx, 0)); - assert_string_equal("},\"x\"]", jsonctx->in->current); + 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, 0)); - assert_string_equal(",\"x\"]", jsonctx->in->current); + assert_int_equal(LYJSON_OBJECT_CLOSED, lyjson_ctx_status(jsonctx)); + assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL)); - assert_int_equal(LYJSON_STRING, lyjson_ctx_status(jsonctx, 0)); + 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_string_equal("]", jsonctx->in->current); + assert_int_equal(LY_SUCCESS, lyjson_ctx_next(jsonctx, NULL)); - assert_int_equal(LYJSON_ARRAY_CLOSED, lyjson_ctx_status(jsonctx, 0)); + 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, 0)); + 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, 0, &jsonctx)); + 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.", "Line number 1."); lyjson_ctx_free(jsonctx); diff --git a/tests/utests/basic/test_plugins.c b/tests/utests/basic/test_plugins.c index 7f3fe40..de13c0b 100644 --- a/tests/utests/basic/test_plugins.c +++ b/tests/utests/basic/test_plugins.c @@ -1,4 +1,4 @@ -/* +/** * @file test_plugins.c * @author: Radek Krejci <rkrejci@cesnet.cz> * @brief unit tests for functions from set.c diff --git a/tests/utests/basic/test_set.c b/tests/utests/basic/test_set.c index af39afa..9485927 100644 --- a/tests/utests/basic/test_set.c +++ b/tests/utests/basic/test_set.c @@ -1,4 +1,4 @@ -/* +/** * @file test_set.c * @author: Radek Krejci <rkrejci@cesnet.cz> * @brief unit tests for functions from set.c diff --git a/tests/utests/basic/test_xml.c b/tests/utests/basic/test_xml.c index 668de4b..071846a 100644 --- a/tests/utests/basic/test_xml.c +++ b/tests/utests/basic/test_xml.c @@ -1,4 +1,4 @@ -/* +/** * @file test_xml.c * @author: Radek Krejci <rkrejci@cesnet.cz> * @brief unit tests for functions from xml.c diff --git a/tests/utests/basic/test_xpath.c b/tests/utests/basic/test_xpath.c index b388dc3..754abf2 100644 --- a/tests/utests/basic/test_xpath.c +++ b/tests/utests/basic/test_xpath.c @@ -88,6 +88,19 @@ const char *schema_a = " type string;\n" " }\n" " }\n" + "\n" + " rpc r {\n" + " input {\n" + " leaf l {\n" + " type string;\n" + " }\n" + " }\n" + " output {\n" + " leaf l {\n" + " type string;\n" + " }\n" + " }\n" + " }\n" "}"; static int @@ -254,9 +267,11 @@ test_invalid(void **state) assert_int_equal(LY_EVALID, lyd_find_xpath(tree, "/a:foo2[.=]", &set)); assert_null(set); + CHECK_LOG_CTX("Unexpected XPath token \"]\" (\"]\").", NULL); assert_int_equal(LY_EVALID, lyd_find_xpath(tree, "/a:", &set)); assert_null(set); + CHECK_LOG_CTX("Invalid character 'a'[2] of expression '/a:'.", NULL); lyd_free_all(tree); } @@ -381,6 +396,31 @@ test_hash(void **state) } static void +test_rpc(void **state) +{ + const char *data = + "<r xmlns=\"urn:tests:a\">\n" + " <l>val</l>\n" + "</r>"; + struct ly_in *in; + struct lyd_node *tree; + struct ly_set *set; + + assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in)); + assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_XML, LYD_TYPE_REPLY_YANG, &tree, NULL)); + ly_in_free(in, 0); + assert_non_null(tree); + + /* name collision input/output, hashes are not used */ + assert_int_equal(LY_SUCCESS, lyd_find_xpath(tree, "/a:r/l", &set)); + assert_int_equal(1, set->count); + + ly_set_free(set, NULL); + + lyd_free_all(tree); +} + +static void test_toplevel(void **state) { const char *schema_b = @@ -479,7 +519,7 @@ test_atomize(void **state) /* some random paths just making sure the API function works */ assert_int_equal(LY_SUCCESS, lys_find_xpath_atoms(UTEST_LYCTX, NULL, "/a:*", 0, &set)); - assert_int_equal(6, set->count); + assert_int_equal(7, set->count); ly_set_free(set, NULL); /* all nodes from all modules (including internal, which can change easily, so check just the test modules) */ @@ -496,7 +536,7 @@ test_atomize(void **state) ly_set_free(set, NULL); assert_int_equal(LY_SUCCESS, lys_find_xpath_atoms(UTEST_LYCTX, NULL, "/*", 0, &set)); - assert_int_equal(13, set->count); + assert_int_equal(14, set->count); ly_set_free(set, NULL); /* @@ -530,7 +570,7 @@ test_atomize(void **state) /* descendant-or-self */ assert_int_equal(LY_SUCCESS, lys_find_xpath_atoms(UTEST_LYCTX, NULL, "/a:*/descendant-or-self::c", 0, &set)); - assert_int_equal(7, set->count); + assert_int_equal(8, set->count); ly_set_free(set, NULL); /* following */ @@ -545,11 +585,11 @@ test_atomize(void **state) /* parent */ assert_int_equal(LY_SUCCESS, lys_find_xpath_atoms(UTEST_LYCTX, NULL, "/child::a:*/c/parent::l1", 0, &set)); - assert_int_equal(7, set->count); + assert_int_equal(8, set->count); ly_set_free(set, NULL); assert_int_equal(LY_SUCCESS, lys_find_xpath_atoms(UTEST_LYCTX, NULL, "/child::a:c//..", 0, &set)); - assert_int_equal(8, set->count); + assert_int_equal(11, set->count); ly_set_free(set, NULL); /* preceding */ @@ -898,6 +938,7 @@ test_variables(void **state) LOCAL_SETUP(data, tree); assert_int_equal(LY_SUCCESS, lyxp_vars_set(&vars, "var1", "\"mstr\"")); assert_int_equal(LY_ENOTFOUND, lyd_find_xpath2(tree, "/foo[text() = $var55]", vars, &set)); + CHECK_LOG_CTX("Variable \"var55\" not defined.", NULL); LOCAL_TEARDOWN(set, tree, vars); /* Syntax error in value. */ @@ -906,6 +947,7 @@ test_variables(void **state) LOCAL_SETUP(data, tree); assert_int_equal(LY_SUCCESS, lyxp_vars_set(&vars, "var", "\"")); assert_int_equal(LY_EVALID, lyd_find_xpath2(tree, "/foo[$var]", vars, &set)); + CHECK_LOG_CTX("Unterminated string delimited with \" (\").", "Data location \"/a:foo\"."); LOCAL_TEARDOWN(set, tree, vars); /* Prefix is not supported. */ @@ -914,7 +956,7 @@ test_variables(void **state) LOCAL_SETUP(data, tree); assert_int_equal(LY_SUCCESS, lyxp_vars_set(&vars, "var", "\"")); assert_int_equal(LY_EVALID, lyd_find_xpath2(tree, "/foo[$pref:var]", vars, &set)); - assert_string_equal("Variable with prefix is not supported.", _UC->err_msg); + CHECK_LOG_CTX("Variable with prefix is not supported.", NULL); LOCAL_TEARDOWN(set, tree, vars); #undef LOCAL_SETUP @@ -1050,6 +1092,154 @@ test_axes(void **state) lyd_free_all(tree); } +static void +test_trim(void **state) +{ + const char *data; + char *str1; + struct lyd_node *tree; + + data = + "<l1 xmlns=\"urn:tests:a\">" + " <a>a1</a>" + " <b>b1</b>" + " <c>c1</c>" + "</l1>" + "<l1 xmlns=\"urn:tests:a\">" + " <a>a2</a>" + " <b>b2</b>" + "</l1>" + "<l1 xmlns=\"urn:tests:a\">" + " <a>a3</a>" + " <b>b3</b>" + "</l1>" + "<l1 xmlns=\"urn:tests:a\">" + " <a>a4</a>" + " <b>b4</b>" + " <c>c4</c>" + "</l1>" + "<l1 xmlns=\"urn:tests:a\">" + " <a>a5</a>" + " <b>b5</b>" + " <c>c5</c>" + "</l1>" + "<foo2 xmlns=\"urn:tests:a\">50</foo2>" + "<c xmlns=\"urn:tests:a\">" + " <x>key2</x>" + " <ll>" + " <a>key1</a>" + " <ll>" + " <a>key11</a>" + " <b>val11</b>" + " </ll>" + " <ll>" + " <a>key12</a>" + " <b>val12</b>" + " </ll>" + " <ll>" + " <a>key13</a>" + " <b>val13</b>" + " </ll>" + " </ll>" + " <ll>" + " <a>key2</a>" + " <ll>" + " <a>key21</a>" + " <b>val21</b>" + " </ll>" + " <ll>" + " <a>key22</a>" + " <b>val22</b>" + " </ll>" + " </ll>" + " <ll>" + " <a>key3</a>" + " <ll>" + " <a>key31</a>" + " <b>val31</b>" + " </ll>" + " <ll>" + " <a>key32</a>" + " <b>val32</b>" + " </ll>" + " </ll>" + "</c>"; + + /* trim #1 */ + assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &tree)); + assert_non_null(tree); + + assert_int_equal(LY_SUCCESS, lyd_trim_xpath(&tree, "/a:c/ll/ll[a='key11']", NULL)); + lyd_print_mem(&str1, tree, LYD_XML, LYD_PRINT_WITHSIBLINGS); + assert_string_equal(str1, + "<c xmlns=\"urn:tests:a\">\n" + " <ll>\n" + " <a>key1</a>\n" + " <ll>\n" + " <a>key11</a>\n" + " <b>val11</b>\n" + " </ll>\n" + " </ll>\n" + "</c>\n"); + + free(str1); + lyd_free_all(tree); + + /* trim #2 */ + assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &tree)); + assert_non_null(tree); + + assert_int_equal(LY_SUCCESS, lyd_trim_xpath(&tree, "/a:c/ll/ll[contains(.,'2')]", NULL)); + lyd_print_mem(&str1, tree, LYD_XML, LYD_PRINT_WITHSIBLINGS); + assert_string_equal(str1, + "<c xmlns=\"urn:tests:a\">\n" + " <ll>\n" + " <a>key1</a>\n" + " <ll>\n" + " <a>key12</a>\n" + " <b>val12</b>\n" + " </ll>\n" + " </ll>\n" + " <ll>\n" + " <a>key2</a>\n" + " <ll>\n" + " <a>key21</a>\n" + " <b>val21</b>\n" + " </ll>\n" + " <ll>\n" + " <a>key22</a>\n" + " <b>val22</b>\n" + " </ll>\n" + " </ll>\n" + " <ll>\n" + " <a>key3</a>\n" + " <ll>\n" + " <a>key32</a>\n" + " <b>val32</b>\n" + " </ll>\n" + " </ll>\n" + "</c>\n"); + + free(str1); + lyd_free_all(tree); + + /* trim #3 */ + assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &tree)); + assert_non_null(tree); + + assert_int_equal(LY_SUCCESS, lyd_trim_xpath(&tree, "/l1[4]//.", NULL)); + lyd_print_mem(&str1, tree, LYD_XML, LYD_PRINT_WITHSIBLINGS); + assert_string_equal(str1, + "<l1 xmlns=\"urn:tests:a\">\n" + " <a>a4</a>\n" + " <b>b4</b>\n" + " <c>c4</c>\n" + "</l1>\n"); + + free(str1); + lyd_free_all(tree); +} + int main(void) { @@ -1058,6 +1248,7 @@ main(void) UTEST(test_union, setup), UTEST(test_invalid, setup), UTEST(test_hash, setup), + UTEST(test_rpc, setup), UTEST(test_toplevel, setup), UTEST(test_atomize, setup), UTEST(test_canonize, setup), @@ -1065,6 +1256,7 @@ main(void) UTEST(test_augment, setup), UTEST(test_variables, setup), UTEST(test_axes, setup), + UTEST(test_trim, setup), }; return cmocka_run_group_tests(tests, NULL, NULL); diff --git a/tests/utests/data/test_diff.c b/tests/utests/data/test_diff.c index 1b7592a..4400b5d 100644 --- a/tests/utests/data/test_diff.c +++ b/tests/utests/data/test_diff.c @@ -4,7 +4,7 @@ * @author Michal Vasko <mvasko@cesnet.cz> * @brief tests for lyd_diff() * - * Copyright (c) 2020 CESNET, z.s.p.o. + * Copyright (c) 2020 - 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. @@ -17,15 +17,15 @@ #include "libyang.h" -#define CHECK_PARSE_LYD(INPUT, MODEL) \ - CHECK_PARSE_LYD_PARAM(INPUT, LYD_XML, LYD_PARSE_ONLY, 0, LY_SUCCESS, MODEL) +#define CHECK_PARSE_LYD(INPUT, OUTPUT) \ + CHECK_PARSE_LYD_PARAM(INPUT, LYD_XML, LYD_PARSE_ONLY, 0, LY_SUCCESS, OUTPUT) -#define CHECK_LYD_STRING(IN_MODEL, TEXT) \ - CHECK_LYD_STRING_PARAM(IN_MODEL, TEXT, LYD_XML, LYD_PRINT_WITHSIBLINGS) +#define CHECK_LYD_STRING(INPUT, TEXT) \ + CHECK_LYD_STRING_PARAM(INPUT, TEXT, LYD_XML, LYD_PRINT_WITHSIBLINGS) -#define CHECK_PARSE_LYD_DIFF(INPUT_1, INPUT_2, OUT_MODEL) \ - assert_int_equal(LY_SUCCESS, lyd_diff_siblings(INPUT_1, INPUT_2, 0, &OUT_MODEL));\ - assert_non_null(OUT_MODEL) +#define CHECK_PARSE_LYD_DIFF(INPUT_1, INPUT_2, OUT_DIFF) \ + assert_int_equal(LY_SUCCESS, lyd_diff_siblings(INPUT_1, INPUT_2, 0, &OUT_DIFF));\ + assert_non_null(OUT_DIFF) #define TEST_DIFF_3(XML1, XML2, XML3, DIFF1, DIFF2, MERGE) \ { \ @@ -117,6 +117,12 @@ const char *schema1 = " leaf l2 {\n" " type int32;\n" " }\n" + "" + " container cont {\n" + " leaf l3 {\n" + " type string;\n" + " }\n" + " }\n" " }\n" "" " leaf-list dllist {\n" @@ -312,6 +318,8 @@ test_invalid(void **state) struct lyd_node *diff = NULL; assert_int_equal(lyd_diff_siblings(model_1, lyd_child(model_1), 0, &diff), LY_EINVAL); + CHECK_LOG_CTX("Invalid arguments - cannot create diff for unrelated data (lyd_diff()).", NULL); + assert_int_equal(lyd_diff_siblings(NULL, NULL, 0, NULL), LY_EINVAL); lyd_free_all(model_1); @@ -637,6 +645,126 @@ test_list(void **state) } static void +test_nested_list(void **state) +{ + struct lyd_node *data1, *data2, *diff; + const char *xml1, *xml2; + + (void) state; + + xml1 = + "<df xmlns=\"urn:libyang:tests:defaults\">" + " <list>" + " <name>n1</name>" + " <value>25</value>" + " <list2>" + " <name2>n22</name2>" + " <value2>26</value2>" + " </list2>" + " </list>" + " <list>" + " <name>n2</name>" + " <value>25</value>" + " <list2>" + " <name2>n22</name2>" + " <value2>26</value2>" + " </list2>" + " </list>" + " <list>" + " <name>n3</name>" + " <value>25</value>" + " <list2>" + " <name2>n22</name2>" + " <value2>26</value2>" + " </list2>" + " </list>" + " <list>" + " <name>n4</name>" + " <value>25</value>" + " <list2>" + " <name2>n22</name2>" + " <value2>26</value2>" + " </list2>" + " </list>" + " <list>" + " <name>n0</name>" + " <value>26</value>" + " <list2>" + " <name2>n22</name2>" + " <value2>26</value2>" + " </list2>" + " <list2>" + " <name2>n23</name2>" + " <value2>26</value2>" + " </list2>" + " </list>" + "</df>"; + xml2 = + "<df xmlns=\"urn:libyang:tests:defaults\">" + " <list>" + " <name>n0</name>" + " <value>30</value>" + " <list2>" + " <name2>n23</name2>" + " <value2>26</value2>" + " </list2>" + " </list>" + "</df>"; + + CHECK_PARSE_LYD(xml1, data1); + CHECK_PARSE_LYD(xml2, data2); + CHECK_PARSE_LYD_DIFF(data1, data2, diff); + + CHECK_LYD_STRING(diff, + "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">\n" + " <list yang:operation=\"delete\">\n" + " <name>n1</name>\n" + " <value>25</value>\n" + " <list2>\n" + " <name2>n22</name2>\n" + " <value2>26</value2>\n" + " </list2>\n" + " </list>\n" + " <list yang:operation=\"delete\">\n" + " <name>n2</name>\n" + " <value>25</value>\n" + " <list2>\n" + " <name2>n22</name2>\n" + " <value2>26</value2>\n" + " </list2>\n" + " </list>\n" + " <list yang:operation=\"delete\">\n" + " <name>n3</name>\n" + " <value>25</value>\n" + " <list2>\n" + " <name2>n22</name2>\n" + " <value2>26</value2>\n" + " </list2>\n" + " </list>\n" + " <list yang:operation=\"delete\">\n" + " <name>n4</name>\n" + " <value>25</value>\n" + " <list2>\n" + " <name2>n22</name2>\n" + " <value2>26</value2>\n" + " </list2>\n" + " </list>\n" + " <list yang:operation=\"none\">\n" + " <name>n0</name>\n" + " <value yang:operation=\"replace\" yang:orig-default=\"false\" yang:orig-value=\"26\">30</value>\n" + " <list2 yang:operation=\"delete\">\n" + " <name2>n22</name2>\n" + " <value2>26</value2>\n" + " </list2>\n" + " </list>\n" + "</df>\n"); + + lyd_free_all(data1); + lyd_free_all(data2); + lyd_free_all(diff); +} + +static void test_userord_llist(void **state) { (void) state; @@ -940,6 +1068,118 @@ test_userord_list2(void **state) } static void +test_userord_list3(void **state) +{ + (void) state; + const char *xml1 = + "<df xmlns=\"urn:libyang:tests:defaults\">\n" + " <ul>\n" + " <l1>a</l1>\n" + " <l2>1</l2>\n" + " </ul>\n" + " <ul>\n" + " <l1>b</l1>\n" + " <l2>2</l2>\n" + " </ul>\n" + " <ul>\n" + " <l1>c</l1>\n" + " <cont>\n" + " <l3>val1</l3>\n" + " </cont>\n" + " </ul>\n" + " <ul>\n" + " <l1>d</l1>\n" + " <l2>4</l2>\n" + " </ul>\n" + "</df>\n"; + const char *xml2 = + "<df xmlns=\"urn:libyang:tests:defaults\">\n" + " <ul>\n" + " <l1>c</l1>\n" + " <l2>3</l2>\n" + " <cont>\n" + " <l3>val2</l3>\n" + " </cont>\n" + " </ul>\n" + " <ul>\n" + " <l1>a</l1>\n" + " <l2>1</l2>\n" + " </ul>\n" + " <ul>\n" + " <l1>d</l1>\n" + " <l2>44</l2>\n" + " </ul>\n" + " <ul>\n" + " <l1>b</l1>\n" + " <l2>2</l2>\n" + " </ul>\n" + "</df>\n"; + const char *xml3 = + "<df xmlns=\"urn:libyang:tests:defaults\">\n" + " <ul>\n" + " <l1>a</l1>\n" + " </ul>\n" + " <ul>\n" + " <l1>c</l1>\n" + " <l2>3</l2>\n" + " <cont>\n" + " <l3>val2</l3>\n" + " </cont>\n" + " </ul>\n" + " <ul>\n" + " <l1>d</l1>\n" + " <l2>44</l2>\n" + " </ul>\n" + " <ul>\n" + " <l1>b</l1>\n" + " <l2>2</l2>\n" + " </ul>\n" + "</df>\n"; + + const char *out_diff_1 = + "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">\n" + " <ul yang:operation=\"replace\" yang:key=\"\" yang:orig-key=\"[l1='b']\">\n" + " <l1>c</l1>\n" + " <l2 yang:operation=\"create\">3</l2>\n" + " <cont yang:operation=\"none\">\n" + " <l3 yang:operation=\"replace\" yang:orig-default=\"false\" yang:orig-value=\"val1\">val2</l3>\n" + " </cont>\n" + " </ul>\n" + " <ul yang:operation=\"replace\" yang:key=\"[l1='a']\" yang:orig-key=\"[l1='b']\">\n" + " <l1>d</l1>\n" + " <l2 yang:operation=\"replace\" yang:orig-default=\"false\" yang:orig-value=\"4\">44</l2>\n" + " </ul>\n" + "</df>\n"; + const char *out_diff_2 = + "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">\n" + " <ul yang:operation=\"replace\" yang:key=\"\" yang:orig-key=\"[l1='c']\">\n" + " <l1>a</l1>\n" + " <l2 yang:operation=\"delete\">1</l2>\n" + " </ul>\n" + "</df>\n"; + const char *out_merge = + "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">\n" + " <ul yang:operation=\"replace\" yang:key=\"\" yang:orig-key=\"[l1='b']\">\n" + " <l1>c</l1>\n" + " <l2 yang:operation=\"create\">3</l2>\n" + " <cont yang:operation=\"none\">\n" + " <l3 yang:operation=\"replace\" yang:orig-default=\"false\" yang:orig-value=\"val1\">val2</l3>\n" + " </cont>\n" + " </ul>\n" + " <ul yang:operation=\"replace\" yang:key=\"[l1='a']\" yang:orig-key=\"[l1='b']\">\n" + " <l1>d</l1>\n" + " <l2 yang:operation=\"replace\" yang:orig-default=\"false\" yang:orig-value=\"4\">44</l2>\n" + " </ul>\n" + " <ul yang:key=\"\" yang:orig-key=\"[l1='c']\" yang:operation=\"replace\">\n" + " <l1>a</l1>\n" + " <l2 yang:operation=\"delete\">1</l2>\n" + " </ul>\n" + "</df>\n"; + + TEST_DIFF_3(xml1, xml2, xml3, out_diff_1, out_diff_2, out_merge); +} + +static void test_keyless_list(void **state) { (void) state; @@ -1207,11 +1447,13 @@ main(void) UTEST(test_delete_merge, setup), UTEST(test_leaf, setup), UTEST(test_list, setup), + UTEST(test_nested_list, setup), UTEST(test_userord_llist, setup), UTEST(test_userord_llist2, setup), UTEST(test_userord_mix, setup), UTEST(test_userord_list, setup), UTEST(test_userord_list2, setup), + UTEST(test_userord_list3, setup), UTEST(test_keyless_list, setup), UTEST(test_state_llist, setup), UTEST(test_wd, setup), diff --git a/tests/utests/data/test_new.c b/tests/utests/data/test_new.c index 7642960..5cee903 100644 --- a/tests/utests/data/test_new.c +++ b/tests/utests/data/test_new.c @@ -55,6 +55,7 @@ const char *schema_a = "module a {\n" " anydata any {\n" " config false;\n" " }\n" + " anyxml anyx;\n" " leaf-list ll2 {\n" " config false;\n" " type string;\n" @@ -128,6 +129,16 @@ test_top_level(void **state) 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_bin(NULL, mod, "l1", (const void **)key_vals, val_lens, 0, &node), LY_SUCCESS); + lyd_free_tree(node); + /* 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']\".", "Schema location \"/a:foo\"."); @@ -290,6 +301,7 @@ test_path(void **state) 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.", "Data location \"/a:c2/l3[1]\"."); ret = lyd_new_path2(root, NULL, "/a:c2/l3[2]/x", "val2", 0, 0, 0, NULL, &node); assert_int_equal(ret, LY_SUCCESS); @@ -348,6 +360,7 @@ test_path(void **state) 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.", "Data location \"/a:ll2[1]\"."); ret = lyd_new_path2(root, NULL, "/a:ll2[2]", "val2", 0, 0, 0, NULL, &node); assert_int_equal(ret, LY_SUCCESS); @@ -362,6 +375,7 @@ test_path(void **state) 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); lyd_print_mem(&str, root, LYD_XML, LYD_PRINT_WITHSIBLINGS); assert_string_equal(str, @@ -391,6 +405,55 @@ test_path(void **state) "}\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 diff --git a/tests/utests/data/test_parser_json.c b/tests/utests/data/test_parser_json.c index d341e31..8feed9c 100644 --- a/tests/utests/data/test_parser_json.c +++ b/tests/utests/data/test_parser_json.c @@ -1,9 +1,10 @@ -/* +/** * @file test_parser_json.c - * @author: Radek Krejci <rkrejci@cesnet.cz> - * @brief unit tests for functions from parser_xml.c + * @author Radek Krejci <rkrejci@cesnet.cz> + * @author Michal Vasko <mvasko@cesnet.cz> + * @brief unit tests for JSON parser * - * Copyright (c) 2019 CESNET, z.s.p.o. + * 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. @@ -44,7 +45,10 @@ setup(void **state) "leaf-list ll1 { type uint8; }" "leaf foo2 { type string; default \"default-val\"; }" "leaf foo3 { type uint32; }" - "notification n2;}"; + "leaf foo4 { type uint64; }" + "rpc r1 {input {leaf l1 {type string;} leaf l2 {type string;}}}" + "notification n2;" + "}"; UTEST_SETUP; @@ -160,6 +164,7 @@ test_leaf(void **state) /* 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.", "Path \"/@a:foo/@a:hi\nt\", line number 1."); } static void @@ -427,12 +432,10 @@ test_list(void **state) 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); - 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); @@ -447,11 +450,16 @@ test_list(void **state) 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); - 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); @@ -460,7 +468,6 @@ test_list(void **state) 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); } @@ -516,6 +523,25 @@ test_opaq(void **state) 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, @@ -555,11 +581,12 @@ test_opaq(void **state) /* 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\".", "Data location \"/@a:foo\"."); + "Unknown module of node \"@a:foo\".", "Path \"/\"."); + CHECK_LOG_CTX("Missing JSON data instance to be coupled with @a:foo metadata.", "Data location \"/@a:foo\", line number 1."); /* empty name */ PARSER_CHECK_ERROR("{\"@a:foo\":{\"\":0}}", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID, - "A JSON object member name cannot be a zero-length string.", "Line number 1."); + "JSON object member name cannot be a zero-length string.", "Data location \"/@a:foo\", line number 1."); /* opaque data tree format print */ data = @@ -626,6 +653,7 @@ 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; @@ -675,8 +703,16 @@ test_rpc(void **state) CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data); lyd_free_all(tree); - /* wrong namespace, element name, whatever... */ - /* TODO */ + /* 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 @@ -772,6 +808,112 @@ test_reply(void **state) /* 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\".", "Path \"/a:c/x/@a:hint\", line number 1."); +} + int main(void) { @@ -787,6 +929,10 @@ main(void) 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); diff --git a/tests/utests/data/test_parser_xml.c b/tests/utests/data/test_parser_xml.c index 7defd9c..4f33f00 100644 --- a/tests/utests/data/test_parser_xml.c +++ b/tests/utests/data/test_parser_xml.c @@ -31,6 +31,7 @@ setup(void **state) " namespace urn:tests:a;\n" " prefix a;\n" " yang-version 1.1;\n" + " import ietf-yang-metadata {prefix md;}" " 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;}}" @@ -42,9 +43,12 @@ setup(void **state) " notification n1 { leaf nl {type string;}}}\n" " container cp {presence \"container switch\"; leaf y {type string;} leaf z {type int8;}}\n" " anydata any {config false;}\n" + " anyxml anyx;\n" " leaf foo2 { type string; default \"default-val\"; }\n" " leaf foo3 { type uint32; }\n" - " notification n2;}"; + " notification n2;" + " md:annotation attr {type enumeration {enum val;}}" + "}"; UTEST_SETUP; @@ -122,6 +126,7 @@ static void test_anydata(void **state) { const char *data; + char *str; struct lyd_node *tree; data = "<any xmlns=\"urn:tests:a\">\n" @@ -145,6 +150,49 @@ test_anydata(void **state) "</any>\n"; CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data_expected); + + assert_int_equal(LY_SUCCESS, lyd_any_value_str(tree, &str)); + lyd_free_all(tree); + + assert_int_equal(LY_SUCCESS, lyd_new_path2(NULL, UTEST_LYCTX, "/a:any", str, strlen(str), LYD_ANYDATA_XML, 0, &tree, NULL)); + free(str); + CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data_expected); + lyd_free_all(tree); +} + +static void +test_anyxml(void **state) +{ + const char *data; + char *str; + struct lyd_node *tree; + + data = "<anyx xmlns=\"urn:tests:a\">\n" + " <element1>\n" + " <element2 x:attr2=\"test\" xmlns:x=\"urn:x\">data</element2>\n" + " </element1>\n" + " <element1a/>\n" + "</anyx>\n"; + CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree); + assert_non_null(tree); + tree = tree->next; + + const char *data_expected = + "<anyx xmlns=\"urn:tests:a\">\n" + " <element1>\n" + " <element2 xmlns:x=\"urn:x\" x:attr2=\"test\">data</element2>\n" + " </element1>\n" + " <element1a/>\n" + "</anyx>\n"; + + CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data_expected); + + assert_int_equal(LY_SUCCESS, lyd_any_value_str(tree, &str)); + lyd_free_all(tree); + + assert_int_equal(LY_SUCCESS, lyd_new_path2(NULL, UTEST_LYCTX, "/a:anyx", str, strlen(str), LYD_ANYDATA_XML, 0, &tree, NULL)); + free(str); + CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data_expected); lyd_free_all(tree); } @@ -170,17 +218,21 @@ test_list(void **state) /* missing keys */ PARSER_CHECK_ERROR("<l1 xmlns=\"urn:tests:a\"><c>1</c><b>b</b></l1>", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID, "List instance is missing its key \"a\".", "Data location \"/a:l1[b='b'][c='1']\", line number 1."); + CHECK_LOG_CTX("Invalid position of the key \"b\" in a list.", NULL); PARSER_CHECK_ERROR("<l1 xmlns=\"urn:tests:a\"><a>a</a></l1>", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID, "List instance is missing its key \"b\".", "Data location \"/a:l1[a='a']\", line number 1."); PARSER_CHECK_ERROR("<l1 xmlns=\"urn:tests:a\"><b>b</b><a>a</a></l1>", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID, "List instance is missing its key \"c\".", "Data location \"/a:l1[a='a'][b='b']\", line number 1."); + CHECK_LOG_CTX("Invalid position of the key \"a\" in a list.", NULL); /* key duplicate */ PARSER_CHECK_ERROR("<l1 xmlns=\"urn:tests:a\"><c>1</c><b>b</b><a>a</a><c>1</c></l1>", 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID, "Duplicate instance of \"c\".", "Data location \"/a:l1[a='a'][b='b'][c='1'][c='1']/c\", line number 1."); + CHECK_LOG_CTX("Invalid position of the key \"a\" in a list.", NULL); + CHECK_LOG_CTX("Invalid position of the key \"b\" in a list.", NULL); /* keys order */ CHECK_PARSE_LYD("<l1 xmlns=\"urn:tests:a\"><d>d</d><a>a</a><c>1</c><b>b</b></l1>", 0, LYD_VALIDATE_PRESENT, tree); @@ -209,6 +261,7 @@ test_list(void **state) 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("Invalid position of the key \"a\" in a list.", NULL); + CHECK_LOG_CTX("Invalid position of the key \"b\" in a list.", NULL); lyd_free_all(tree); PARSER_CHECK_ERROR(data, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, tree, LY_EVALID, @@ -250,14 +303,14 @@ test_opaq(void **state) /* 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_XML, "foo3", 0, 0, NULL, 0, ""); + CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 0, 0, LY_VALUE_XML, "foo3", 0, 0, NULL, 1, ""); CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, "<foo3 xmlns=\"urn:tests:a\"/>\n"); lyd_free_all(tree); /* list, opaq flag */ data = "<l1 xmlns=\"urn:tests:a\"/>"; 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_XML, "l1", 0, 0, NULL, 0, ""); + CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 0, 0, LY_VALUE_XML, "l1", 0, 0, NULL, 1, ""); CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, "<l1 xmlns=\"urn:tests:a\"/>\n"); lyd_free_all(tree); @@ -273,7 +326,7 @@ test_opaq(void **state) /* 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_XML, "l1", 0, 0, NULL, 0, ""); + CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 0, 0x1, LY_VALUE_XML, "l1", 0, 0, NULL, 1, ""); CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data); lyd_free_all(tree); @@ -289,7 +342,7 @@ test_opaq(void **state) /* 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_XML, "l1", 0, 0, NULL, 0, ""); + CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 0, 0x1, LY_VALUE_XML, "l1", 0, 0, NULL, 1, ""); CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data); lyd_free_all(tree); @@ -300,7 +353,7 @@ test_opaq(void **state) " <c xmld:id=\"D\">1</c>\n" "</a>\n", LYD_XML, LYD_PARSE_OPAQ, LYD_VALIDATE_PRESENT, &tree)); - CHECK_LOG_CTX("Unknown XML prefix \"xmld\".", "Line number 3."); + CHECK_LOG_CTX("Unknown XML prefix \"xmld\".", "Data location \"/a\", line number 3."); } static void @@ -358,10 +411,10 @@ test_rpc(void **state) node = lyd_child(node); /* z has no value */ - CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)node, 0x1, 0, LY_VALUE_XML, "z", 0, 0, NULL, 0, ""); + CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)node, 0x1, 0, LY_VALUE_XML, "z", 0, 0, NULL, 1, ""); 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_XML, "l1", 0, 0, NULL, 0, ""); + CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)node, 0x1, 0x1, LY_VALUE_XML, "l1", 0, 0, NULL, 1, ""); CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, "<edit-config xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n" @@ -554,10 +607,10 @@ test_netconf_rpc(void **state) node = lyd_child(node); /* z has no value */ - CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)node, 0x1, 0, LY_VALUE_XML, "z", 0, 0, NULL, 0, ""); + CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)node, 0x1, 0, LY_VALUE_XML, "z", 0, 0, NULL, 1, ""); 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_XML, "l1", 0, 0, NULL, 0, ""); + CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)node, 0x1, 0x1, LY_VALUE_XML, "l1", 0, 0, NULL, 1, ""); CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, "<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" message-id=\"25\"/>\n"); @@ -581,8 +634,33 @@ test_netconf_rpc(void **state) lyd_free_all(tree); lyd_free_all(op); - /* wrong namespace, element name, whatever... */ - /* TODO */ + /* invalid anyxml nested metadata value */ + data = "<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" message-id=\"1\" pid=\"4114692032\">\n" + " <copy-config>\n" + " <target>\n" + " <running/>\n" + " </target>\n" + " <source>\n" + " <config>\n" + " <l1 xmlns=\"urn:tests:a\" xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n" + " <a>val_a</a>\n" + " <b>val_b</b>\n" + " <c>5</c>\n" + " <cont nc:operation=\"merge\">\n" + " <e nc:operation=\"merge2\">false</e>\n" + " </cont>\n" + " </l1>\n" + " </config>\n" + " </source>\n" + " </copy-config>\n" + "</rpc>\n"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in)); + assert_int_equal(LY_EVALID, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_XML, LYD_TYPE_RPC_NETCONF, &tree, &op)); + ly_in_free(in, 0); + CHECK_LOG_CTX("Invalid enumeration value \"merge2\".", + "Path \"/ietf-netconf:copy-config/source/config/a:l1[a='val_a'][b='val_b'][c='5']/cont/e/@ietf-netconf:operation\", line number 13."); + lyd_free_all(tree); + assert_null(op); } static void @@ -678,6 +756,22 @@ test_netconf_reply_or_notification(void **state) lyd_free_all(tree); lyd_free_all(op2); + /* notification with a different order */ + data = "<notification xmlns=\"urn:ietf:params:xml:ns:netconf:notification:1.0\">\n" + "<c xmlns=\"urn:tests:a\">\n" + " <n1>\n" + " <nl>value</nl>\n" + " </n1>\n" + "</c>\n" + "<eventTime>2010-12-06T08:00:01Z</eventTime>\n" + "</notification>\n"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in)); + assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_XML, LYD_TYPE_NOTIF_NETCONF, &tree, &op2)); + ly_in_free(in, 0); + + lyd_free_all(tree); + lyd_free_all(op2); + /* parse a data reply */ data = "<rpc-reply message-id=\"55\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n" " <al xmlns=\"urn:tests:a\">25</al>\n" @@ -739,6 +833,64 @@ test_netconf_reply_or_notification(void **state) } 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 = "<input xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-nmda\">" + "<datastore xmlns:ds=\"urn:ietf:params:xml:ns:yang:ietf-datastores\">ds:running</datastore>" + "<config>" + "<cp xmlns=\"urn:tests:a\"><z xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\" nc:operation=\"replace\"/></cp>" + "<l1 xmlns=\"urn:tests:a\" xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\" nc:operation=\"replace\">" + "<a>val_a</a><b>val_b</b><c>val_c</c>" + "</l1>" + "</config></input>"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in)); + assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, tree, in, LYD_XML, LYD_TYPE_RPC_RESTCONF, &envp, NULL)); + ly_in_free(in, 0); + + /* the same just connected to the edit-data RPC */ + data = "<edit-data xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-nmda\">" + "<datastore xmlns:ds=\"urn:ietf:params:xml:ns:yang:ietf-datastores\">ds:running</datastore>" + "<config>" + "<cp xmlns=\"urn:tests:a\"><z xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\" nc:operation=\"replace\"/></cp>" + "<l1 xmlns=\"urn:tests:a\" xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\" nc:operation=\"replace\">" + "<a>val_a</a><b>val_b</b><c>val_c</c>" + "</l1>" + "</config></edit-data>"; + CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data); + lyd_free_all(tree); + lyd_free_all(envp); +} + +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 = "<output xmlns=\"urn:tests:a\"><al>25</al></output>"; + 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_XML, LYD_TYPE_REPLY_RESTCONF, &envp, NULL)); + ly_in_free(in, 0); + + /* connected to the RPC with the parent */ + data = "<c xmlns=\"urn:tests:a\"><act><al>25</al></act></c>"; + CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data); + lyd_free_all(tree); + lyd_free_all(envp); +} + +static void test_filter_attributes(void **state) { const char *data; @@ -812,12 +964,58 @@ test_data_skip(void **state) lyd_free_all(tree); } +static void +test_metadata(void **state) +{ + const char *data; + struct lyd_node *tree; + + /* invalid metadata value */ + data = "<c xmlns=\"urn:tests:a\" xmlns:a=\"urn:tests:a\"><x a:attr=\"value\">xval</x></c>"; + assert_int_equal(LY_EVALID, lyd_parse_data_mem(_UC->ctx, data, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree)); + assert_null(tree); + CHECK_LOG_CTX("Invalid enumeration value \"value\".", "Path \"/a:c/x/@a:attr\", line number 1."); +} + +static void +test_subtree(void **state) +{ + const char *data; + struct ly_in *in; + struct lyd_node *tree; + + /* prepare data with the parent */ + data = "<l1 xmlns=\"urn:tests:a\">\n" + " <a>val_a</a>\n" + " <b>val_b</b>\n" + " <c>1</c>\n" + "</l1>\n"; + assert_int_equal(LY_SUCCESS, lyd_parse_data_mem(UTEST_LYCTX, data, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree)); + + /* parse a subtree of it */ + data = "<cont xmlns=\"urn:tests:a\">\n" + " <e>true</e>\n" + "</cont>\n"; + assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in)); + assert_int_equal(LY_SUCCESS, lyd_parse_data(UTEST_LYCTX, tree, in, LYD_XML, 0, LYD_VALIDATE_PRESENT, NULL)); + ly_in_free(in, 0); + + /* parse another container, fails */ + assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in)); + assert_int_equal(LY_EVALID, lyd_parse_data(UTEST_LYCTX, tree, in, LYD_XML, 0, LYD_VALIDATE_PRESENT, NULL)); + ly_in_free(in, 0); + CHECK_LOG_CTX("Duplicate instance of \"cont\".", "Data location \"/a:l1[a='val_a'][b='val_b'][c='1']/cont\"."); + + lyd_free_all(tree); +} + int main(void) { const struct CMUnitTest tests[] = { UTEST(test_leaf, setup), UTEST(test_anydata, setup), + UTEST(test_anyxml, setup), UTEST(test_list, setup), UTEST(test_container, setup), UTEST(test_opaq, setup), @@ -828,8 +1026,12 @@ main(void) UTEST(test_netconf_rpc, setup), UTEST(test_netconf_action, setup), UTEST(test_netconf_reply_or_notification, setup), + UTEST(test_restconf_rpc, setup), + UTEST(test_restconf_reply, setup), UTEST(test_filter_attributes, setup), UTEST(test_data_skip, setup), + UTEST(test_metadata, setup), + UTEST(test_subtree, setup), }; return cmocka_run_group_tests(tests, NULL, NULL); diff --git a/tests/utests/data/test_printer_xml.c b/tests/utests/data/test_printer_xml.c index d533c41..6213a37 100644 --- a/tests/utests/data/test_printer_xml.c +++ b/tests/utests/data/test_printer_xml.c @@ -145,7 +145,8 @@ test_anydata(void **state) " <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" + "defs:attr1=\"defaults:val\" attr2=\"/defaults:node/defs:node2\">\n" + " </elem2>\n" " </elem1>\n" " </cont>\n" "</any>\n"; diff --git a/tests/utests/data/test_tree_data.c b/tests/utests/data/test_tree_data.c index 27dba42..494fdf3 100644 --- a/tests/utests/data/test_tree_data.c +++ b/tests/utests/data/test_tree_data.c @@ -1,9 +1,9 @@ /** * @file test_tree_data.c - * @author: Radek Krejci <rkrejci@cesnet.cz> - * @brief unit tests for functions from tress_data.c + * @author Radek Krejci <rkrejci@cesnet.cz> + * @brief unit tests for functions from tree_data.c * - * Copyright (c) 2018-2019 CESNET, z.s.p.o. + * 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. @@ -100,7 +100,7 @@ test_compare(void **state) 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, 0)); + 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); @@ -145,6 +145,14 @@ test_compare(void **state) 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 @@ -196,7 +204,7 @@ test_compare_diff_ctx(void **state) 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(tree1, tree2, 0)); + assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, 0)); lyd_free_all(tree1); lyd_free_all(tree2); @@ -210,7 +218,7 @@ test_compare_diff_ctx(void **state) 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(tree1, tree2, 0)); + assert_int_equal(LY_SUCCESS, lyd_compare_single(tree1, tree2, 0)); lyd_free_all(tree1); lyd_free_all(tree2); @@ -329,8 +337,7 @@ test_dup(void **state) 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(((struct lyd_node_inner *)((struct lyd_node_inner *)tree1->next)->child)->child, NULL, - LYD_DUP_WITH_PARENTS, &tree2)); + 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); @@ -352,8 +359,8 @@ test_dup(void **state) 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(((struct lyd_node_inner *)((struct lyd_node_inner *)tree1->next)->child)->child, - (struct lyd_node_inner *)tree2, LYD_DUP_WITH_PARENTS, NULL)); + 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); @@ -363,6 +370,8 @@ test_dup(void **state) 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); lyd_free_all(tree1); } @@ -488,6 +497,11 @@ test_find_path(void **state) 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.", "Schema location \"/c:cont\"."); + assert_int_equal(LY_SUCCESS, lyd_find_path(root, "nexthop[gateway='2100::1']", 0, NULL)); + lyd_free_all(root); } @@ -525,6 +539,7 @@ test_data_hash(void **state) /* 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\".", "Data location \"/test-data-hash:c/ll[.='']\", line number 1."); lyd_free_all(tree); } diff --git a/tests/utests/data/test_validation.c b/tests/utests/data/test_validation.c index 415e16a..d0dcae5 100644 --- a/tests/utests/data/test_validation.c +++ b/tests/utests/data/test_validation.c @@ -1154,6 +1154,92 @@ test_must(void **state) CHECK_LOG_CTX_APPTAG("l leaf is not left", "Data location \"/i:cont/l3\".", "not-left"); } +static void +test_multi_error(void **state) +{ + struct lyd_node *tree; + const char *schema = + "module ii {\n" + " namespace urn:tests:ii;\n" + " prefix ii;\n" + " yang-version 1.1;\n" + "\n" + " container cont {\n" + " leaf l {\n" + " type string;\n" + " }\n" + " leaf l2 {\n" + " must \"../l = 'right'\";\n" + " type string;\n" + " }\n" + " leaf l3 {\n" + " must \"../l = 'left'\" {\n" + " error-app-tag \"not-left\";\n" + " error-message \"l leaf is not left\";\n" + " }\n" + " type string;\n" + " }\n" + " leaf-list ll {\n" + " type uint32;\n" + " min-elements 2;\n" + " }\n" + " }\n" + "}"; + const char *data; + + UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL); + + /* xml */ + data = + "<cont xmlns=\"urn:tests:ii\">\n" + " <l>wrong</l>\n" + " <l>wrong2</l>\n" + " <l2>val</l2>\n" + " <l3>val</l3>\n" + " <ll>ahoy</ll>\n" + "</cont>\n"; + CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT | LYD_VALIDATE_MULTI_ERROR, LY_EVALID, tree); + CHECK_LOG_CTX_APPTAG("Too few \"ll\" instances.", "Schema location \"/ii:cont/ll\".", "too-few-elements"); + CHECK_LOG_CTX_APPTAG("l leaf is not left", "Data location \"/ii:cont/l3\".", "not-left"); + CHECK_LOG_CTX_APPTAG("Must condition \"../l = 'right'\" not satisfied.", "Data location \"/ii:cont/l2\".", "must-violation"); + CHECK_LOG_CTX_APPTAG("Invalid type uint32 value \"ahoy\".", "Data location \"/ii:cont/ll\", line number 6.", NULL); + + /* json */ + data = "{\n" + " \"ii:cont\": {\n" + " \"l\": \"wrong\",\n" + " \"l\": \"wrong2\",\n" + " \"l2\": \"val\",\n" + " \"l3\": \"val\",\n" + " \"ll\": [\"ahoy\"]\n" + " }\n" + "}\n"; + CHECK_PARSE_LYD_PARAM(data, LYD_JSON, 0, LYD_VALIDATE_PRESENT | LYD_VALIDATE_MULTI_ERROR, LY_EVALID, tree); + CHECK_LOG_CTX_APPTAG("Too few \"ll\" instances.", "Schema location \"/ii:cont/ll\".", "too-few-elements"); + CHECK_LOG_CTX_APPTAG("l leaf is not left", "Data location \"/ii:cont/l3\".", "not-left"); + CHECK_LOG_CTX_APPTAG("Must condition \"../l = 'right'\" not satisfied.", "Data location \"/ii:cont/l2\".", "must-violation"); + CHECK_LOG_CTX_APPTAG("Invalid non-number-encoded uint32 value \"ahoy\".", "Data location \"/ii:cont/ll\", line number 7.", NULL); + + /* validation */ + data = "{\n" + " \"ii:cont\": {\n" + " \"l\": \"wrong\",\n" + " \"l\": \"wrong2\",\n" + " \"l2\": \"val\",\n" + " \"l3\": \"val\",\n" + " \"ll\": [25]\n" + " }\n" + "}\n"; + CHECK_PARSE_LYD_PARAM(data, LYD_JSON, LYD_PARSE_ONLY, 0, LY_SUCCESS, tree); + assert_int_equal(LY_EVALID, lyd_validate_all(&tree, NULL, LYD_VALIDATE_PRESENT | LYD_VALIDATE_MULTI_ERROR, NULL)); + lyd_free_tree(tree); + CHECK_LOG_CTX_APPTAG("Too few \"ll\" instances.", "Schema location \"/ii:cont/ll\".", "too-few-elements"); + CHECK_LOG_CTX_APPTAG("l leaf is not left", "Data location \"/ii:cont/l3\".", "not-left"); + CHECK_LOG_CTX_APPTAG("Must condition \"../l = 'right'\" not satisfied.", "Data location \"/ii:cont/l2\".", "must-violation"); + CHECK_LOG_CTX_APPTAG("Duplicate instance of \"l\".", "Data location \"/ii:cont/l\".", NULL); + CHECK_LOG_CTX_APPTAG("Duplicate instance of \"l\".", "Data location \"/ii:cont/l\".", NULL); +} + const char *schema_j = "module j {\n" " namespace urn:tests:j;\n" @@ -1212,6 +1298,7 @@ test_action(void **state) struct lyd_node *tree, *op_tree; UTEST_ADD_MODULE(schema_j, LYS_IN_YANG, feats_j, NULL); + UTEST_LOG_CTX_CLEAN; assert_int_equal(LY_SUCCESS, ly_in_new_memory( "<cont xmlns=\"urn:tests:j\">\n" @@ -1304,6 +1391,7 @@ test_reply(void **state) struct lyd_node *tree, *op_tree; UTEST_ADD_MODULE(schema_j, LYS_IN_YANG, feats_j, NULL); + UTEST_LOG_CTX_CLEAN; assert_int_equal(LY_SUCCESS, ly_in_new_memory( "<cont xmlns=\"urn:tests:j\">\n" @@ -1422,7 +1510,7 @@ test_case(void **state) " }\n" "}\n", LYD_JSON, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); CHECK_LOG_CTX("Data for both cases \"v0\" and \"v2\" exist.", - "Data location \"/k:ch\", line number 5."); + "Data location \"/k:ch\", line number 6."); CHECK_PARSE_LYD_PARAM( "{\n" @@ -1432,7 +1520,7 @@ test_case(void **state) " }\n" "}\n", LYD_JSON, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); CHECK_LOG_CTX("Data for both cases \"v0\" and \"v2\" exist.", - "Data location \"/k:ch\", line number 5."); + "Data location \"/k:ch\", line number 6."); } int @@ -1450,6 +1538,7 @@ main(void) UTEST(test_defaults), UTEST(test_state), UTEST(test_must), + UTEST(test_multi_error), UTEST(test_action), UTEST(test_rpc), UTEST(test_reply), diff --git a/tests/utests/extensions/test_metadata.c b/tests/utests/extensions/test_metadata.c index 39d29be..f1edd29 100644 --- a/tests/utests/extensions/test_metadata.c +++ b/tests/utests/extensions/test_metadata.c @@ -53,7 +53,7 @@ test_yang(void **state) "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"); + "Path \"/aa:{extension='md:annotation'}/aa\"."); /* not allowed substatement */ data = "module aa {yang-version 1.1; namespace urn:tests:extensions:metadata:aa; prefix aa;" @@ -61,7 +61,7 @@ test_yang(void **state) "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"); + "Path \"/aa:{extension='md:annotation'}/aa\"."); /* invalid cardinality of units substatement */ data = "module aa {yang-version 1.1; namespace urn:tests:extensions:metadata:aa; prefix aa;" @@ -69,7 +69,7 @@ test_yang(void **state) "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"); + "Path \"/aa:{extension='md:annotation'}/aa\"."); /* invalid cardinality of status substatement */ data = "module aa {yang-version 1.1; namespace urn:tests:extensions:metadata:aa; prefix aa;" @@ -77,7 +77,7 @@ test_yang(void **state) "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"); + "Path \"/aa:{extension='md:annotation'}/aa\"."); /* invalid cardinality of status substatement */ data = "module aa {yang-version 1.1; namespace urn:tests:extensions:metadata:aa; prefix aa;" @@ -85,7 +85,7 @@ test_yang(void **state) "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"); + "Path \"/aa:{extension='md:annotation'}/aa\"."); /* duplication of the same annotation */ data = "module aa {yang-version 1.1; namespace urn:tests:extensions:metadata:aa; prefix aa;" @@ -93,7 +93,7 @@ test_yang(void **state) "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"); + "Path \"/aa:{extension='md:annotation'}/aa\"."); } static void @@ -134,7 +134,7 @@ test_yin(void **state) "</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"); + "Path \"/aa:{extension='md:annotation'}/aa\"."); /* 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" @@ -145,7 +145,7 @@ test_yin(void **state) "</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"); + "Path \"/aa:{extension='md:annotation'}/aa\"."); /* 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" @@ -158,7 +158,7 @@ test_yin(void **state) "</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"); + "Path \"/aa:{extension='md:annotation'}/aa\"."); /* 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" @@ -171,7 +171,7 @@ test_yin(void **state) "</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"); + "Path \"/aa:{extension='md:annotation'}/aa\"."); /* 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" @@ -183,7 +183,7 @@ test_yin(void **state) "</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"); + "Path \"/aa:{extension='md:annotation'}/aa\"."); /* 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" @@ -196,7 +196,7 @@ test_yin(void **state) "</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"); + "Path \"/aa:{extension='md:annotation'}/aa\"."); } int diff --git a/tests/utests/extensions/test_nacm.c b/tests/utests/extensions/test_nacm.c index 1c999fb..5f7028e 100644 --- a/tests/utests/extensions/test_nacm.c +++ b/tests/utests/extensions/test_nacm.c @@ -58,7 +58,7 @@ test_deny_all(void **state) 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'}"); + "Path \"/b:{extension='nacm:default-deny-all'}\"."); /* invalid */ data = "module aa {yang-version 1.1; namespace urn:tests:extensions:nacm:aa; prefix en;" @@ -67,7 +67,7 @@ test_deny_all(void **state) 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'}"); + "Path \"/aa:l/{extension='nacm:default-deny-all'}\"."); } static void @@ -100,7 +100,7 @@ test_deny_write(void **state) 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'}"); + "Path \"/b:notif/{extension='nacm:default-deny-write'}\"."); /* invalid */ data = "module aa {yang-version 1.1; namespace urn:tests:extensions:nacm:aa; prefix en;" @@ -109,7 +109,7 @@ test_deny_write(void **state) 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'}"); + "Path \"/aa:l/{extension='nacm:default-deny-write'}\"."); } int diff --git a/tests/utests/extensions/test_schema_mount.c b/tests/utests/extensions/test_schema_mount.c index be879ec..17a4c94 100644 --- a/tests/utests/extensions/test_schema_mount.c +++ b/tests/utests/extensions/test_schema_mount.c @@ -75,7 +75,7 @@ test_schema(void **state) assert_int_equal(LY_EINVAL, lys_parse_mem(UTEST_LYCTX, schema, LYS_IN_YANG, NULL)); CHECK_LOG_CTX("Ext plugin \"ly2 schema mount v1\": " "Extension \"yangmnt:mount-point\" instance not allowed in YANG version 1 module.", - "/sm:root/{extension='yangmnt:mount-point'}/root"); + "Path \"/sm:root/{extension='yangmnt:mount-point'}/root\"."); schema = "module sm {\n" @@ -92,7 +92,7 @@ test_schema(void **state) assert_int_equal(LY_EINVAL, lys_parse_mem(UTEST_LYCTX, schema, LYS_IN_YANG, NULL)); CHECK_LOG_CTX("Ext plugin \"ly2 schema mount v1\": " "Extension \"yangmnt:mount-point\" instance allowed only in container or list statement.", - "/sm:{extension='yangmnt:mount-point'}/root"); + "Path \"/sm:{extension='yangmnt:mount-point'}/root\"."); schema = "module sm {\n" @@ -114,7 +114,7 @@ test_schema(void **state) assert_int_equal(LY_EINVAL, lys_parse_mem(UTEST_LYCTX, schema, LYS_IN_YANG, NULL)); CHECK_LOG_CTX("Ext plugin \"ly2 schema mount v1\": " "Extension \"yangmnt:mount-point\" instance allowed only in container or list statement.", - "/sm:root/l/{extension='yangmnt:mount-point'}/root"); + "Path \"/sm:root/l/{extension='yangmnt:mount-point'}/root\"."); schema = "module sm {\n" @@ -138,7 +138,7 @@ test_schema(void **state) assert_int_equal(LY_EINVAL, lys_parse_mem(UTEST_LYCTX, schema, LYS_IN_YANG, NULL)); CHECK_LOG_CTX("Ext plugin \"ly2 schema mount v1\": " "Multiple extension \"yangmnt:mount-point\" instances.", - "/sm:l/{extension='yangmnt:mount-point'}/root"); + "Path \"/sm:l/{extension='yangmnt:mount-point'}/root\"."); /* valid */ schema = @@ -410,25 +410,25 @@ test_parse_invalid(void **state) CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_EVALID, data); CHECK_LOG_CTX("Ext plugin \"ly2 schema mount v1\": " "Mandatory node \"type\" instance does not exist.", - "Schema location \"/ietf-interfaces:interfaces/interface/type\"."); + "Data location \"/ietf-interfaces:interfaces/interface[name='bu']\"."); CHECK_PARSE_LYD_PARAM(json, LYD_JSON, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_EVALID, data); CHECK_LOG_CTX("Ext plugin \"ly2 schema mount v1\": " "Mandatory node \"type\" instance does not exist.", - "Schema location \"/ietf-interfaces:interfaces/interface/type\"."); + "Data location \"/ietf-interfaces:interfaces/interface[name='bu']\"."); /* same validation fail in separate validation */ CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT | LYD_PARSE_ONLY, 0, LY_SUCCESS, data); assert_int_equal(LY_EVALID, lyd_validate_all(&data, NULL, LYD_VALIDATE_PRESENT, NULL)); CHECK_LOG_CTX("Ext plugin \"ly2 schema mount v1\": " "Mandatory node \"type\" instance does not exist.", - "Schema location \"/ietf-interfaces:interfaces/interface/type\"."); + "Data location \"/ietf-interfaces:interfaces/interface[name='bu']\"."); lyd_free_siblings(data); CHECK_PARSE_LYD_PARAM(json, LYD_JSON, LYD_PARSE_STRICT | LYD_PARSE_ONLY, 0, LY_SUCCESS, data); assert_int_equal(LY_EVALID, lyd_validate_all(&data, NULL, LYD_VALIDATE_PRESENT, NULL)); CHECK_LOG_CTX("Ext plugin \"ly2 schema mount v1\": " "Mandatory node \"type\" instance does not exist.", - "Schema location \"/ietf-interfaces:interfaces/interface/type\"."); + "Data location \"/ietf-interfaces:interfaces/interface[name='bu']\"."); lyd_free_siblings(data); /* success */ @@ -878,7 +878,7 @@ test_parse_shared(void **state) CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_EVALID, data); CHECK_LOG_CTX("Ext plugin \"ly2 schema mount v1\": " "Shared-schema yang-library content-id \"2\" differs from \"1\" used previously.", - "/ietf-yang-library:yang-library/content-id"); + "Path \"/ietf-yang-library:yang-library/content-id\"."); /* data for 2 mount points */ ly_ctx_set_ext_data_clb(UTEST_LYCTX, test_ext_data_clb, @@ -1549,6 +1549,108 @@ test_new(void **state) lyd_free_siblings(data); } +static void +test_lys_getnext(void **state) +{ + const struct lysc_node *parent, *node; + struct ly_ctx *sm_ctx; + + ly_ctx_set_ext_data_clb(UTEST_LYCTX, test_ext_data_clb, + "<yang-library xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\" " + " xmlns:ds=\"urn:ietf:params:xml:ns:yang:ietf-datastores\">" + " <module-set>" + " <name>test-set</name>" + " <module>" + " <name>ietf-datastores</name>" + " <revision>2018-02-14</revision>" + " <namespace>urn:ietf:params:xml:ns:yang:ietf-datastores</namespace>" + " </module>" + " <module>" + " <name>ietf-yang-library</name>" + " <revision>2019-01-04</revision>" + " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace>" + " </module>" + " <module>" + " <name>ietf-yang-schema-mount</name>" + " <revision>2019-01-14</revision>" + " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount</namespace>" + " </module>" + " <module>" + " <name>ietf-interfaces</name>" + " <revision>2014-05-08</revision>" + " <namespace>urn:ietf:params:xml:ns:yang:ietf-interfaces</namespace>" + " </module>" + " <module>" + " <name>iana-if-type</name>" + " <revision>2014-05-08</revision>" + " <namespace>urn:ietf:params:xml:ns:yang:iana-if-type</namespace>" + " </module>" + " <module>" + " <name>ietf-ip</name>" + " <revision>2014-06-16</revision>" + " <namespace>urn:ietf:params:xml:ns:yang:ietf-ip</namespace>" + " </module>" + " <import-only-module>" + " <name>ietf-yang-types</name>" + " <revision>2013-07-15</revision>" + " <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-types</namespace>" + " </import-only-module>" + " </module-set>" + " <schema>" + " <name>test-schema</name>" + " <module-set>test-set</module-set>" + " </schema>" + " <datastore>" + " <name>ds:running</name>" + " <schema>test-schema</schema>" + " </datastore>" + " <datastore>" + " <name>ds:operational</name>" + " <schema>test-schema</schema>" + " </datastore>" + " <content-id>1</content-id>" + "</yang-library>" + "<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">" + " <module-set-id>1</module-set-id>" + "</modules-state>" + "<schema-mounts xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount\">" + " <mount-point>" + " <module>sm</module>" + " <label>root</label>" + " <shared-schema/>" + " </mount-point>" + "</schema-mounts>"); + + parent = lys_find_path(UTEST_LYCTX, NULL, "/sm:root", 0); + assert_non_null(parent); + + node = lys_getnext(NULL, parent, NULL, LYS_GETNEXT_WITHSCHEMAMOUNT); + assert_non_null(node); + assert_string_equal(node->name, "schema-mounts"); + sm_ctx = node->module->ctx; + + node = lys_getnext(node, parent, NULL, LYS_GETNEXT_WITHSCHEMAMOUNT); + assert_non_null(node); + assert_string_equal(node->name, "yang-library"); + + node = lys_getnext(node, parent, NULL, LYS_GETNEXT_WITHSCHEMAMOUNT); + assert_non_null(node); + assert_string_equal(node->name, "modules-state"); + + node = lys_getnext(node, parent, NULL, LYS_GETNEXT_WITHSCHEMAMOUNT); + assert_non_null(node); + assert_string_equal(node->name, "interfaces"); + + node = lys_getnext(node, parent, NULL, LYS_GETNEXT_WITHSCHEMAMOUNT); + assert_non_null(node); + assert_string_equal(node->name, "interfaces-state"); + + node = lys_getnext(node, parent, NULL, LYS_GETNEXT_WITHSCHEMAMOUNT); + assert_null(node); + + ly_ctx_destroy(sm_ctx); +} + int main(void) { @@ -1560,6 +1662,7 @@ main(void) UTEST(test_parse_shared_parent_ref, setup), UTEST(test_parse_config, setup), UTEST(test_new, setup), + UTEST(test_lys_getnext, setup), }; return cmocka_run_group_tests(tests, NULL, NULL); diff --git a/tests/utests/extensions/test_structure.c b/tests/utests/extensions/test_structure.c index 23af450..9bad7a7 100644 --- a/tests/utests/extensions/test_structure.c +++ b/tests/utests/extensions/test_structure.c @@ -148,7 +148,7 @@ test_schema_invalid(void **state) "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"); + "Path \"/a:{extension='sx:structure'}/struct\"."); data = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix self;" "import ietf-yang-structure-ext {prefix sx;}" @@ -156,14 +156,14 @@ test_schema_invalid(void **state) 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"); + "Path \"/a:b/{extension='sx:structure'}/struct\"."); 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, - "Extension instance \"sx:structure\" missing argument element \"name\".", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Extension instance \"sx:structure\" missing argument element \"name\".", NULL); data = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix self;" "import ietf-yang-structure-ext {prefix sx;}" @@ -171,7 +171,7 @@ test_schema_invalid(void **state) "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"); + "Path \"/a:{extension='sx:structure'}/struct\"."); data = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix self;" "import ietf-yang-structure-ext {prefix sx;}" @@ -179,7 +179,7 @@ test_schema_invalid(void **state) "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"); + "Path \"/a:{extension='sx:structure'}/struct\"."); /* augment-structure */ data = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix a;" @@ -199,7 +199,7 @@ test_schema_invalid(void **state) "}}"; 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'}"); + "Path \"/b:{extension='sx:augment-structure'}/{augment='/a:n1'}\"."); } static void diff --git a/tests/utests/extensions/test_yangdata.c b/tests/utests/extensions/test_yangdata.c index 8c0176f..57caaf2 100644 --- a/tests/utests/extensions/test_yangdata.c +++ b/tests/utests/extensions/test_yangdata.c @@ -119,7 +119,7 @@ test_schema(void **state) 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"); + "Path \"/b:b/{extension='rc:yang-data'}/template\"."); assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG_COMPILED, 0)); assert_string_equal(printed, info); free(printed); @@ -168,7 +168,7 @@ test_schema_invalid(void **state) 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"); + "Path \"/a:{extension='rc:yang-data'}/template\"."); 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;}" @@ -177,7 +177,7 @@ test_schema_invalid(void **state) 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"); + "Path \"/a:{extension='rc:yang-data'}/template\"."); 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;}" @@ -186,7 +186,7 @@ test_schema_invalid(void **state) 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"); + "Path \"/a:{extension='rc:yang-data'}/template\"."); 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;}" @@ -195,7 +195,7 @@ test_schema_invalid(void **state) 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"); + "Path \"/a:{extension='rc:yang-data'}/template\"."); 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;}" @@ -204,14 +204,14 @@ test_schema_invalid(void **state) 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"); + "Path \"/a:{extension='rc:yang-data'}/template\"."); 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, - "Extension instance \"rc:yang-data\" missing argument element \"name\".", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Extension instance \"rc:yang-data\" missing argument element \"name\".", NULL); 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;}" @@ -220,7 +220,7 @@ test_schema_invalid(void **state) 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"); + "Path \"/a:{extension='rc:yang-data'}/template\"."); 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;}" @@ -230,7 +230,7 @@ test_schema_invalid(void **state) 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"); + "Path \"/a:{extension='rc:yang-data'}/template\"."); } static void diff --git a/tests/utests/node/list.c b/tests/utests/node/list.c index 8b14ece..987b416 100644 --- a/tests/utests/node/list.c +++ b/tests/utests/node/list.c @@ -169,8 +169,8 @@ test_schema_yang(void **state) "leaf group{type string;}" "}"); UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EVALID); - CHECK_LOG_CTX("Parsing module \"TERR_0\" failed.", NULL, - "Invalid value \"-1\" of \"max-elements\".", "Line number 5."); + CHECK_LOG_CTX("Parsing module \"TERR_0\" failed.", NULL); + CHECK_LOG_CTX("Invalid value \"-1\" of \"max-elements\".", "Line number 5."); schema = MODULE_CREATE_YANG("TERR_0", "list user {" "key uid;" @@ -181,8 +181,8 @@ test_schema_yang(void **state) "leaf group{type string;}" "}"); UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EVALID); - CHECK_LOG_CTX("Parsing module \"TERR_0\" failed.", NULL, - "Value \"4294967298\" is out of \"max-elements\" bounds.", "Line number 5."); + CHECK_LOG_CTX("Parsing module \"TERR_0\" failed.", NULL); + CHECK_LOG_CTX("Value \"4294967298\" is out of \"max-elements\" bounds.", "Line number 5."); schema = MODULE_CREATE_YANG("TERR_0", "list user {" "key uid;" @@ -193,7 +193,7 @@ test_schema_yang(void **state) "leaf group{type string;}" "}"); UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EVALID); - CHECK_LOG_CTX("List min-elements 20 is bigger than max-elements 10.", "/TERR_0:user"); + CHECK_LOG_CTX("List min-elements 20 is bigger than max-elements 10.", "Path \"/TERR_0:user\"."); schema = MODULE_CREATE_YANG("TERR_0", "list user {" "key uid;" @@ -204,8 +204,8 @@ test_schema_yang(void **state) "leaf group{type string;}" "}"); UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EVALID); - CHECK_LOG_CTX("Parsing module \"TERR_0\" failed.", NULL, - "Invalid value \"-1\" of \"min-elements\".", "Line number 5."); + CHECK_LOG_CTX("Parsing module \"TERR_0\" failed.", NULL); + CHECK_LOG_CTX("Invalid value \"-1\" of \"min-elements\".", "Line number 5."); schema = MODULE_CREATE_YANG("TERR_0", "list user {" "key uid;" @@ -215,8 +215,8 @@ test_schema_yang(void **state) "leaf group{type string;}" "}"); UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EVALID); - CHECK_LOG_CTX("Parsing module \"TERR_0\" failed.", NULL, - "Duplicate keyword \"key\".", "Line number 5."); + CHECK_LOG_CTX("Parsing module \"TERR_0\" failed.", NULL); + CHECK_LOG_CTX("Duplicate keyword \"key\".", "Line number 5."); schema = MODULE_CREATE_YANG("T6", "list user {" "config false;" @@ -282,8 +282,8 @@ test_schema_yang(void **state) "leaf group{type string;}" "}"); UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EVALID); - CHECK_LOG_CTX("Parsing module \"TERROR0\" failed.", NULL, - "Invalid value \"systeme\" of \"ordered-by\".", "Line number 5."); + CHECK_LOG_CTX("Parsing module \"TERROR0\" failed.", NULL); + CHECK_LOG_CTX("Invalid value \"systeme\" of \"ordered-by\".", "Line number 5."); schema = MODULE_CREATE_YANG("TERROR0", "list \"\" {" "key uid;" @@ -294,8 +294,8 @@ test_schema_yang(void **state) "leaf group{type string;}" "}"); UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EVALID); - CHECK_LOG_CTX("Parsing module \"TERROR0\" failed.", NULL, - "Statement argument is required.", "Line number 5."); + CHECK_LOG_CTX("Parsing module \"TERROR0\" failed.", NULL); + CHECK_LOG_CTX("Statement argument is required.", "Line number 5."); schema = MODULE_CREATE_YANG("T9", "list user {" "key uid;" @@ -389,7 +389,7 @@ test_schema_yin(void **state) " <leaf name=\"group\"><type name=\"string\"/></leaf>" "</list>"); UTEST_INVALID_MODULE(schema, LYS_IN_YIN, NULL, LY_EVALID); - CHECK_LOG_CTX("The list's key \"u<id\" not found.", "/T00:user"); + CHECK_LOG_CTX("The list's key \"u<id\" not found.", "Path \"/T00:user\"."); schema = MODULE_CREATE_YIN("T1", "<list name=\"user\"> " " <key value=\"uid\"/>" @@ -498,8 +498,8 @@ test_schema_yin(void **state) " <leaf name=\"uid\"> <type name=\"int32\"> </leaf>" "</list>"); UTEST_INVALID_MODULE(schema, LYS_IN_YIN, NULL, LY_EVALID); - CHECK_LOG_CTX("Parsing module \"TERR_0\" failed.", NULL, - "Invalid value \"-1\" of \"value\" attribute in \"max-elements\" element.", "Line number 8."); + CHECK_LOG_CTX("Parsing module \"TERR_0\" failed.", NULL); + CHECK_LOG_CTX("Invalid value \"-1\" of \"value\" attribute in \"max-elements\" element.", "Line number 8."); schema = MODULE_CREATE_YIN("TERR_0", "<list name=\"user\">" @@ -511,8 +511,8 @@ test_schema_yin(void **state) " <leaf name=\"group\"> <type name=\"string\"/> </leaf>" "</list>"); UTEST_INVALID_MODULE(schema, LYS_IN_YIN, NULL, LY_EVALID); - CHECK_LOG_CTX("Parsing module \"TERR_0\" failed.", NULL, - "Value \"4294967298\" of \"value\" attribute in \"max-elements\" element is out of bounds.", "Line number 8."); + CHECK_LOG_CTX("Parsing module \"TERR_0\" failed.", NULL); + CHECK_LOG_CTX("Value \"4294967298\" of \"value\" attribute in \"max-elements\" element is out of bounds.", "Line number 8."); schema = MODULE_CREATE_YIN("TERR_0", "<list name=\"user\">" @@ -524,8 +524,9 @@ test_schema_yin(void **state) " <leaf name=\"group\"> <type name=\"string\"/> </leaf>" "</list>"); UTEST_INVALID_MODULE(schema, LYS_IN_YIN, NULL, LY_EVALID); - CHECK_LOG_CTX("Parsing module \"TERR_0\" failed.", NULL, - "Invalid combination of min-elements and max-elements: min value 20 is bigger than the max value 10.", "Line number 8."); + CHECK_LOG_CTX("Parsing module \"TERR_0\" failed.", NULL); + CHECK_LOG_CTX("Invalid combination of min-elements and max-elements: min value 20 is bigger than the max value 10.", + "Line number 8."); schema = MODULE_CREATE_YIN("TERR_0", "<list name=\"user\">" @@ -537,8 +538,8 @@ test_schema_yin(void **state) " <leaf name=\"group\"> <type name=\"string\"/> </leaf>" "</list>"); UTEST_INVALID_MODULE(schema, LYS_IN_YIN, NULL, LY_EVALID); - CHECK_LOG_CTX("Parsing module \"TERR_0\" failed.", NULL, - "Value \"-1\" of \"value\" attribute in \"min-elements\" element is out of bounds.", "Line number 8."); + CHECK_LOG_CTX("Parsing module \"TERR_0\" failed.", NULL); + CHECK_LOG_CTX("Value \"-1\" of \"value\" attribute in \"min-elements\" element is out of bounds.", "Line number 8."); schema = MODULE_CREATE_YIN("TERR_0", "<list name=\"user\">" @@ -549,8 +550,8 @@ test_schema_yin(void **state) " <leaf name=\"group\"> <type name=\"string\"/> </leaf>" "</list>"); UTEST_INVALID_MODULE(schema, LYS_IN_YIN, NULL, LY_EVALID); - CHECK_LOG_CTX("Parsing module \"TERR_0\" failed.", NULL, - "Redefinition of \"key\" sub-element in \"list\" element.", "Line number 8."); + CHECK_LOG_CTX("Parsing module \"TERR_0\" failed.", NULL); + CHECK_LOG_CTX("Redefinition of \"key\" sub-element in \"list\" element.", "Line number 8."); schema = MODULE_CREATE_YIN("T6", "<list name=\"user\">" @@ -620,8 +621,8 @@ test_schema_yin(void **state) " <leaf name=\"group\"><type name=\"string\"/> </leaf>" "</list>"); UTEST_INVALID_MODULE(schema, LYS_IN_YIN, NULL, LY_EVALID); - CHECK_LOG_CTX("Parsing module \"TERROR0\" failed.", NULL, - "Invalid value \"systeme\" of \"value\" attribute in \"ordered-by\" element. Valid values are \"system\" and \"user\".", + CHECK_LOG_CTX("Parsing module \"TERROR0\" failed.", NULL); + CHECK_LOG_CTX("Invalid value \"systeme\" of \"value\" attribute in \"ordered-by\" element. Valid values are \"system\" and \"user\".", "Line number 8."); schema = MODULE_CREATE_YIN("T_DEFS1", diff --git a/tests/utests/schema/test_printer_tree.c b/tests/utests/schema/test_printer_tree.c index c076ece..40fb15f 100644 --- a/tests/utests/schema/test_printer_tree.c +++ b/tests/utests/schema/test_printer_tree.c @@ -1574,6 +1574,7 @@ print_compiled_node(void **state) " yang-version 1.1;\n" " namespace \"x:y\";\n" " prefix x;\n" + "\n" " container g {\n" " leaf a {\n" " type string;\n" @@ -1586,6 +1587,12 @@ print_compiled_node(void **state) " leaf c {\n" " type string;\n" " }\n" + " list l {\n" + " key \"ip\";\n" + " leaf ip {\n" + " type string;\n" + " }\n" + " }\n" " }\n" " }\n" "}\n"; @@ -1610,13 +1617,31 @@ print_compiled_node(void **state) ly_out_reset(UTEST_OUT); + /* pyang -f tree --tree-path /g/h/l */ + expect = + "module: a26\n" + " +--rw g\n" + " +--rw h\n" + " +--rw l* [ip]\n" + " +--rw ip string\n"; + + node = lys_find_path(UTEST_LYCTX, NULL, "/a26:g/h/l", 0); + CHECK_POINTER(node, 1); + assert_int_equal(LY_SUCCESS, lys_print_node(UTEST_OUT, node, LYS_OUT_TREE, 72, 0)); + assert_int_equal(strlen(expect), ly_out_printed(UTEST_OUT)); + assert_string_equal(printed, expect); + + ly_out_reset(UTEST_OUT); + /* pyang -f tree --tree-path /g/h */ expect = "module: a26\n" " +--rw g\n" " +--rw h\n" " +--rw b string\n" - " +--rw c? string\n"; + " +--rw c? string\n" + " +--rw l* [ip]\n" + " +--rw ip string\n"; node = lys_find_path(UTEST_LYCTX, NULL, "/a26:g/h", 0); CHECK_POINTER(node, 1); @@ -1643,6 +1668,59 @@ print_compiled_node(void **state) TEST_LOCAL_TEARDOWN; } +static void +print_compiled_node_augment(void **state) +{ + TEST_LOCAL_SETUP; + const struct lysc_node *node; + + orig = + "module b26xx {\n" + " yang-version 1.1;\n" + " namespace \"xx:y\";\n" + " prefix xx;\n" + " container c;\n" + "}\n"; + + UTEST_ADD_MODULE(orig, LYS_IN_YANG, NULL, &mod); + + /* module with import statement */ + orig = + "module b26 {\n" + " yang-version 1.1;\n" + " namespace \"x:y\";\n" + " prefix x;\n" + "\n" + " import b26xx {\n" + " prefix xx;\n" + " }\n" + "\n" + " augment \"/xx:c\" {\n" + " container e;\n" + " }\n" + "}\n"; + + UTEST_ADD_MODULE(orig, LYS_IN_YANG, NULL, &mod); + + /* pyang -f tree --tree-path /c/e ... but prefixes modified */ + expect = + "module: b26\n" + " +--rw xx:c\n" + " +--rw e\n"; + + /* using lysc tree */ + ly_ctx_set_options(UTEST_LYCTX, LY_CTX_SET_PRIV_PARSED); + node = lys_find_path(UTEST_LYCTX, NULL, "/b26xx:c/b26:e", 0); + CHECK_POINTER(node, 1); + assert_int_equal(LY_SUCCESS, lys_print_node(UTEST_OUT, node, LYS_OUT_TREE, 72, 0)); + assert_int_equal(strlen(expect), ly_out_printed(UTEST_OUT)); + assert_string_equal(printed, expect); + ly_out_reset(UTEST_OUT); + ly_ctx_unset_options(UTEST_LYCTX, LY_CTX_SET_PRIV_PARSED); + + TEST_LOCAL_TEARDOWN; +} + static LY_ERR local_imp_clb(const char *UNUSED(mod_name), const char *UNUSED(mod_rev), const char *UNUSED(submod_name), const char *UNUSED(sub_rev), void *user_data, LYS_INFORMAT *format, @@ -2365,6 +2443,43 @@ structure(void **state) TEST_LOCAL_TEARDOWN; } +static void +annotation(void **state) +{ + TEST_LOCAL_SETUP; + + orig = + "module ann {\n" + " yang-version 1.1;\n" + " namespace \"urn:example:ann\";\n" + " prefix an;\n" + "\n" + " import ietf-yang-metadata {\n" + " prefix md;\n" + " }\n" + "\n" + " leaf lf1 {\n" + " type string;\n" + " }\n" + " md:annotation avalue {\n" + " type string;\n" + " }\n" + "}\n"; + + expect = + "module: ann\n" + " +--rw lf1? string\n"; + + /* annotation is ignored without error message */ + UTEST_ADD_MODULE(orig, LYS_IN_YANG, NULL, &mod); + TEST_LOCAL_PRINT(mod, 72); + assert_int_equal(strlen(expect), ly_out_printed(UTEST_OUT)); + assert_string_equal(printed, expect); + ly_out_reset(UTEST_OUT); + + TEST_LOCAL_TEARDOWN; +} + int main(void) { @@ -2395,10 +2510,12 @@ main(void) UTEST(transition_between_rpc_and_notif), UTEST(local_augment), UTEST(print_compiled_node), + UTEST(print_compiled_node_augment), UTEST(print_parsed_submodule), UTEST(yang_data), UTEST(mount_point), UTEST(structure), + UTEST(annotation), }; return cmocka_run_group_tests(tests, NULL, NULL); diff --git a/tests/utests/schema/test_schema.c b/tests/utests/schema/test_schema.c index 175b569..17c4e4f 100644 --- a/tests/utests/schema/test_schema.c +++ b/tests/utests/schema/test_schema.c @@ -91,7 +91,8 @@ test_imp_clb(const char *UNUSED(mod_name), const char *UNUSED(mod_rev), const ch const char *test_str__; \ TEST_SCHEMA_STR(RFC7950, YIN, MOD_NAME, CONTENT, test_str__) \ assert_int_not_equal(lys_parse_mem(UTEST_LYCTX, test_str__, YIN ? LYS_IN_YIN : LYS_IN_YANG, NULL), LY_SUCCESS); \ - CHECK_LOG_CTX("Parsing module \""MOD_NAME"\" failed.", NULL, ERRMSG, ERRPATH); \ + CHECK_LOG_CTX("Parsing module \""MOD_NAME"\" failed.", NULL); \ + CHECK_LOG_CTX(ERRMSG, ERRPATH); \ } #define TEST_STMT_DUP(RFC7950, YIN, STMT, MEMBER, VALUE1, VALUE2, LINE) \ @@ -283,12 +284,12 @@ test_revisions(void **state) strcpy(rev->date, "2018-12-31"); assert_int_equal(2, LY_ARRAY_COUNT(revs)); - assert_string_equal("2018-01-01", &revs[0]); - assert_string_equal("2018-12-31", &revs[1]); + assert_string_equal("2018-01-01", revs[0].date); + assert_string_equal("2018-12-31", revs[1].date); /* the order should be fixed, so the newest revision will be the first in the array */ lysp_sort_revisions(revs); - assert_string_equal("2018-12-31", &revs[0]); - assert_string_equal("2018-01-01", &revs[1]); + assert_string_equal("2018-12-31", revs[0].date); + assert_string_equal("2018-01-01", revs[1].date); LY_ARRAY_FREE(revs); } @@ -306,80 +307,80 @@ test_collision_typedef(void **state) /* collision with a built-in type */ str = "module a {namespace urn:a; prefix a; typedef binary {type string;}}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"binary\" of typedef statement - name collision with a built-in type.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"binary\" of typedef statement - name collision with a built-in type.", NULL); str = "module a {namespace urn:a; prefix a; typedef bits {type string;}}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"bits\" of typedef statement - name collision with a built-in type.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"bits\" of typedef statement - name collision with a built-in type.", NULL); str = "module a {namespace urn:a; prefix a; typedef boolean {type string;}}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"boolean\" of typedef statement - name collision with a built-in type.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"boolean\" of typedef statement - name collision with a built-in type.", NULL); str = "module a {namespace urn:a; prefix a; typedef decimal64 {type string;}}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"decimal64\" of typedef statement - name collision with a built-in type.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"decimal64\" of typedef statement - name collision with a built-in type.", NULL); str = "module a {namespace urn:a; prefix a; typedef empty {type string;}}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"empty\" of typedef statement - name collision with a built-in type.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"empty\" of typedef statement - name collision with a built-in type.", NULL); str = "module a {namespace urn:a; prefix a; typedef enumeration {type string;}}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"enumeration\" of typedef statement - name collision with a built-in type.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"enumeration\" of typedef statement - name collision with a built-in type.", NULL); str = "module a {namespace urn:a; prefix a; typedef int8 {type string;}}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"int8\" of typedef statement - name collision with a built-in type.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"int8\" of typedef statement - name collision with a built-in type.", NULL); str = "module a {namespace urn:a; prefix a; typedef int16 {type string;}}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"int16\" of typedef statement - name collision with a built-in type.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"int16\" of typedef statement - name collision with a built-in type.", NULL); str = "module a {namespace urn:a; prefix a; typedef int32 {type string;}}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"int32\" of typedef statement - name collision with a built-in type.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"int32\" of typedef statement - name collision with a built-in type.", NULL); str = "module a {namespace urn:a; prefix a; typedef int64 {type string;}}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"int64\" of typedef statement - name collision with a built-in type.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"int64\" of typedef statement - name collision with a built-in type.", NULL); str = "module a {namespace urn:a; prefix a; typedef instance-identifier {type string;}}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"instance-identifier\" of typedef statement - name collision with a built-in type.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"instance-identifier\" of typedef statement - name collision with a built-in type.", NULL); str = "module a {namespace urn:a; prefix a; typedef identityref {type string;}}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"identityref\" of typedef statement - name collision with a built-in type.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"identityref\" of typedef statement - name collision with a built-in type.", NULL); str = "module a {namespace urn:a; prefix a; typedef leafref {type string;}}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"leafref\" of typedef statement - name collision with a built-in type.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"leafref\" of typedef statement - name collision with a built-in type.", NULL); str = "module a {namespace urn:a; prefix a; typedef string {type int8;}}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"string\" of typedef statement - name collision with a built-in type.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"string\" of typedef statement - name collision with a built-in type.", NULL); str = "module a {namespace urn:a; prefix a; typedef union {type string;}}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"union\" of typedef statement - name collision with a built-in type.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"union\" of typedef statement - name collision with a built-in type.", NULL); str = "module a {namespace urn:a; prefix a; typedef uint8 {type string;}}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"uint8\" of typedef statement - name collision with a built-in type.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"uint8\" of typedef statement - name collision with a built-in type.", NULL); str = "module a {namespace urn:a; prefix a; typedef uint16 {type string;}}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"uint16\" of typedef statement - name collision with a built-in type.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"uint16\" of typedef statement - name collision with a built-in type.", NULL); str = "module a {namespace urn:a; prefix a; typedef uint32 {type string;}}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"uint32\" of typedef statement - name collision with a built-in type.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"uint32\" of typedef statement - name collision with a built-in type.", NULL); str = "module a {namespace urn:a; prefix a; typedef uint64 {type string;}}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"uint64\" of typedef statement - name collision with a built-in type.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"uint64\" of typedef statement - name collision with a built-in type.", NULL); str = "module mytypes {namespace urn:types; prefix t; typedef binary_ {type string;} typedef bits_ {type string;} typedef boolean_ {type string;} " "typedef decimal64_ {type string;} typedef empty_ {type string;} typedef enumeration_ {type string;} typedef int8_ {type string;} typedef int16_ {type string;}" @@ -391,34 +392,34 @@ test_collision_typedef(void **state) /* collision in node's scope */ str = "module a {namespace urn:a; prefix a; container c {typedef y {type int8;} typedef y {type string;}}}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"y\" of typedef statement - name collision with sibling type.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"y\" of typedef statement - name collision with sibling type.", NULL); /* collision with parent node */ str = "module a {namespace urn:a; prefix a; container c {container d {typedef y {type int8;}} typedef y {type string;}}}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"y\" of typedef statement - name collision with another scoped type.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"y\" of typedef statement - name collision with another scoped type.", NULL); /* collision with module's top-level */ str = "module a {namespace urn:a; prefix a; typedef x {type string;} container c {typedef x {type int8;}}}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"x\" of typedef statement - scoped type collide with a top-level type.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"x\" of typedef statement - scoped type collide with a top-level type.", NULL); /* collision of submodule's node with module's top-level */ ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, "submodule b {belongs-to a {prefix a;} container c {typedef x {type string;}}}"); str = "module a {namespace urn:a; prefix a; include b; typedef x {type int8;}}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"x\" of typedef statement - scoped type collide with a top-level type.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"x\" of typedef statement - scoped type collide with a top-level type.", NULL); /* collision of module's node with submodule's top-level */ ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, "submodule b {belongs-to a {prefix a;} typedef x {type int8;}}"); str = "module a {namespace urn:a; prefix a; include b; container c {typedef x {type string;}}}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"x\" of typedef statement - scoped type collide with a top-level type.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"x\" of typedef statement - scoped type collide with a top-level type.", NULL); /* collision of submodule's node with another submodule's top-level */ str = "module a {yang-version 1.1; namespace urn:a; prefix a; include asub; include bsub;}"; @@ -426,29 +427,29 @@ test_collision_typedef(void **state) list[1].data = "submodule bsub {belongs-to a {prefix a;} container c {typedef g {type int;}}}"; ly_ctx_set_module_imp_clb(UTEST_LYCTX, module_clb, list); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"g\" of typedef statement - scoped type collide with a top-level type.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"g\" of typedef statement - scoped type collide with a top-level type.", NULL); /* collision of module's top-levels */ str = "module a {namespace urn:a; prefix a; typedef test {type string;} typedef test {type int8;}}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"test\" of typedef statement - name collision with another top-level type.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"test\" of typedef statement - name collision with another top-level type.", NULL); /* collision of submodule's top-levels */ submod = "submodule asub {belongs-to a {prefix a;} typedef g {type int;} typedef g {type int;}}"; str = "module a {yang-version 1.1; namespace urn:a; prefix a; include asub;}"; ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, submod); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"g\" of typedef statement - name collision with another top-level type.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"g\" of typedef statement - name collision with another top-level type.", NULL); /* collision of module's top-level with submodule's top-levels */ ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, "submodule b {belongs-to a {prefix a;} typedef x {type string;}}"); str = "module a {namespace urn:a; prefix a; include b; typedef x {type int8;}}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"x\" of typedef statement - name collision with another top-level type.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"x\" of typedef statement - name collision with another top-level type.", NULL); /* collision of submodule's top-level with another submodule's top-levels */ str = "module a {yang-version 1.1; namespace urn:a; prefix a; include asub; include bsub;}"; @@ -456,15 +457,14 @@ test_collision_typedef(void **state) list[1].data = "submodule bsub {belongs-to a {prefix a;} typedef g {type int;}}"; ly_ctx_set_module_imp_clb(UTEST_LYCTX, module_clb, list); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"g\" of typedef statement - name collision with another top-level type.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"g\" of typedef statement - name collision with another top-level type.", NULL); /* error in type-stmt */ str = "module a {namespace urn:a; prefix a; container c {typedef x {type t{}}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Unexpected end-of-input.", "Line number 1."); - UTEST_LOG_CLEAN; + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Unexpected end-of-input.", "Line number 1."); /* no collision if the same names are in different scope */ str = "module a {yang-version 1.1; namespace urn:a; prefix a;" @@ -485,34 +485,34 @@ test_collision_grouping(void **state) /* collision in node's scope */ str = "module a {namespace urn:a; prefix a; container c {grouping y; grouping y;}}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"y\" of grouping statement - name collision with sibling grouping.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"y\" of grouping statement - name collision with sibling grouping.", NULL); /* collision with parent node */ str = "module a {namespace urn:a; prefix a; container c {container d {grouping y;} grouping y;}}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"y\" of grouping statement - name collision with another scoped grouping.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"y\" of grouping statement - name collision with another scoped grouping.", NULL); /* collision with module's top-level */ str = "module a {namespace urn:a; prefix a; grouping x; container c {grouping x;}}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"x\" of grouping statement - scoped grouping collide with a top-level grouping.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"x\" of grouping statement - scoped grouping collide with a top-level grouping.", NULL); /* collision of submodule's node with module's top-level */ ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, "submodule b {belongs-to a {prefix a;} container c {grouping x;}}"); str = "module a {namespace urn:a; prefix a; include b; grouping x;}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"x\" of grouping statement - scoped grouping collide with a top-level grouping.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"x\" of grouping statement - scoped grouping collide with a top-level grouping.", NULL); /* collision of module's node with submodule's top-level */ ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, "submodule b {belongs-to a {prefix a;} grouping x;}"); str = "module a {namespace urn:a; prefix a; include b; container c {grouping x;}}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"x\" of grouping statement - scoped grouping collide with a top-level grouping.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"x\" of grouping statement - scoped grouping collide with a top-level grouping.", NULL); /* collision of submodule's node with another submodule's top-level */ str = "module a {yang-version 1.1; namespace urn:a; prefix a; include asub; include bsub;}"; @@ -520,29 +520,29 @@ test_collision_grouping(void **state) list[1].data = "submodule bsub {belongs-to a {prefix a;} container c {grouping g;}}"; ly_ctx_set_module_imp_clb(UTEST_LYCTX, module_clb, list); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"g\" of grouping statement - scoped grouping collide with a top-level grouping.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"g\" of grouping statement - scoped grouping collide with a top-level grouping.", NULL); /* collision of module's top-levels */ str = "module a {namespace urn:a; prefix a; grouping test; grouping test;}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"test\" of grouping statement - name collision with another top-level grouping.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"test\" of grouping statement - name collision with another top-level grouping.", NULL); /* collision of submodule's top-levels */ submod = "submodule asub {belongs-to a {prefix a;} grouping g; grouping g;}"; str = "module a {yang-version 1.1; namespace urn:a; prefix a; include asub;}"; ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, submod); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"g\" of grouping statement - name collision with another top-level grouping.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"g\" of grouping statement - name collision with another top-level grouping.", NULL); /* collision of module's top-level with submodule's top-levels */ ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, "submodule b {belongs-to a {prefix a;} grouping x;}"); str = "module a {namespace urn:a; prefix a; include b; grouping x;}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"x\" of grouping statement - name collision with another top-level grouping.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"x\" of grouping statement - name collision with another top-level grouping.", NULL); /* collision of submodule's top-level with another submodule's top-levels */ str = "module a {yang-version 1.1; namespace urn:a; prefix a; include asub; include bsub;}"; @@ -550,25 +550,27 @@ test_collision_grouping(void **state) list[1].data = "submodule bsub {belongs-to a {prefix a;} grouping g;}"; ly_ctx_set_module_imp_clb(UTEST_LYCTX, module_clb, list); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"g\" of grouping statement - name collision with another top-level grouping.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"g\" of grouping statement - name collision with another top-level grouping.", NULL); /* collision in nested groupings, top-level */ str = "module a {namespace urn:a; prefix a; grouping g {grouping g;}}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"g\" of grouping statement - scoped grouping collide with a top-level grouping.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"g\" of grouping statement - scoped grouping collide with a top-level grouping.", NULL); /* collision in nested groupings, in node */ str = "module a {namespace urn:a; prefix a; container c {grouping g {grouping g;}}}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"g\" of grouping statement - name collision with another scoped grouping.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"g\" of grouping statement - name collision with another scoped grouping.", NULL); /* no collision if the same names are in different scope */ str = "module a {yang-version 1.1; namespace urn:a; prefix a;" "container c {grouping g;} container d {grouping g;}}"; assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL)); + CHECK_LOG_CTX("Locally scoped grouping \"g\" not used.", NULL); + CHECK_LOG_CTX("Locally scoped grouping \"g\" not used.", NULL); } static void @@ -584,24 +586,24 @@ test_collision_identity(void **state) /* collision of module's top-levels */ str = "module a {yang-version 1.1; namespace urn:a; prefix a; identity g; identity g;}"; assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"g\" of identity statement - name collision with another top-level identity.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"g\" of identity statement - name collision with another top-level identity.", NULL); /* collision of submodule's top-levels */ submod = "submodule asub {belongs-to a {prefix a;} identity g; identity g;}"; str = "module a {yang-version 1.1; namespace urn:a; prefix a; include asub;}"; ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, submod); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"g\" of identity statement - name collision with another top-level identity.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"g\" of identity statement - name collision with another top-level identity.", NULL); /* collision of module's top-level with submodule's top-levels */ submod = "submodule asub {belongs-to a {prefix a;} identity g;}"; str = "module a {yang-version 1.1; namespace urn:a; prefix a; include asub; identity g;}"; ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, submod); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"g\" of identity statement - name collision with another top-level identity.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"g\" of identity statement - name collision with another top-level identity.", NULL); /* collision of submodule's top-level with another submodule's top-levels */ str = "module a {yang-version 1.1; namespace urn:a; prefix a; include asub; include bsub;}"; @@ -609,8 +611,8 @@ test_collision_identity(void **state) list[1].data = "submodule bsub {belongs-to a {prefix a;} identity g;}"; ly_ctx_set_module_imp_clb(UTEST_LYCTX, module_clb, list); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"g\" of identity statement - name collision with another top-level identity.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"g\" of identity statement - name collision with another top-level identity.", NULL); } static void @@ -626,24 +628,24 @@ test_collision_feature(void **state) /* collision of module's top-levels */ str = "module a {yang-version 1.1; namespace urn:a; prefix a; feature g; feature g;}"; assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"g\" of feature statement - name collision with another top-level feature.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"g\" of feature statement - name collision with another top-level feature.", NULL); /* collision of submodule's top-levels */ submod = "submodule asub {belongs-to a {prefix a;} feature g; feature g;}"; str = "module a {yang-version 1.1; namespace urn:a; prefix a; include asub;}"; ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, submod); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"g\" of feature statement - name collision with another top-level feature.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"g\" of feature statement - name collision with another top-level feature.", NULL); /* collision of module's top-level with submodule's top-levels */ submod = "submodule asub {belongs-to a {prefix a;} feature g;}"; str = "module a {yang-version 1.1; namespace urn:a; prefix a; include asub; feature g;}"; ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, submod); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"g\" of feature statement - name collision with another top-level feature.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"g\" of feature statement - name collision with another top-level feature.", NULL); /* collision of submodule's top-level with another submodule's top-levels */ str = "module a {yang-version 1.1; namespace urn:a; prefix a; include asub; include bsub;}"; @@ -651,8 +653,8 @@ test_collision_feature(void **state) list[1].data = "submodule bsub {belongs-to a {prefix a;} feature g;}"; ly_ctx_set_module_imp_clb(UTEST_LYCTX, module_clb, list); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL, - "Duplicate identifier \"g\" of feature statement - name collision with another top-level feature.", NULL); + CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"g\" of feature statement - name collision with another top-level feature.", NULL); } static void @@ -1046,15 +1048,15 @@ test_includes(void **state) ly_ctx_set_module_imp_clb(UTEST_LYCTX, module_clb, list); mod = ly_ctx_load_module(UTEST_LYCTX, "main_b", NULL, NULL); assert_null(mod); - CHECK_LOG_CTX("Loading \"main_b\" module failed.", NULL, - "Data model \"main_b\" not found in local searchdirs.", NULL, - "Parsing module \"main_b\" failed.", NULL, - "Including \"sub_b_one\" submodule into \"main_b\" failed.", NULL, - "Data model \"sub_b_one\" not found in local searchdirs.", NULL, - "Parsing submodule \"sub_b_one\" failed.", NULL, - "YANG 1.1 requires all submodules to be included from main module. But submodule \"sub_b_one\" includes " - "submodule \"sub_b_two\" which is not included by main module \"main_b\".", NULL, - "YANG version 1.1 expects all includes in main module, includes in submodules (sub_b_one) are not necessary.", NULL); + CHECK_LOG_CTX("Loading \"main_b\" module failed.", NULL); + CHECK_LOG_CTX("Data model \"main_b\" not found in local searchdirs.", NULL); + CHECK_LOG_CTX("Parsing module \"main_b\" failed.", NULL); + CHECK_LOG_CTX("Including \"sub_b_one\" submodule into \"main_b\" failed.", NULL); + CHECK_LOG_CTX("Data model \"sub_b_one\" not found in local searchdirs.", NULL); + CHECK_LOG_CTX("Parsing submodule \"sub_b_one\" failed.", NULL); + CHECK_LOG_CTX("YANG 1.1 requires all submodules to be included from main module. But submodule \"sub_b_one\" includes " + "submodule \"sub_b_two\" which is not included by main module \"main_b\".", NULL); + CHECK_LOG_CTX("YANG version 1.1 expects all includes in main module, includes in submodules (sub_b_one) are not necessary.", NULL); } { @@ -1073,6 +1075,7 @@ test_includes(void **state) assert_false(mod->parsed->includes[1].injected); /* result is ok, but log includes the warning */ CHECK_LOG_CTX("YANG version 1.1 expects all includes in main module, includes in submodules (sub_c_two) are not necessary.", NULL); + CHECK_LOG_CTX("YANG version 1.1 expects all includes in main module, includes in submodules (sub_c_one) are not necessary.", NULL); } } @@ -1083,7 +1086,8 @@ test_key_order(void **state) const struct lysc_node *node; struct module_clb_list list1[] = { - {"a", "module a {" + { + "a", "module a {" "yang-version 1.1;" "namespace urn:test:a;" "prefix a;" @@ -1092,7 +1096,8 @@ test_key_order(void **state) " leaf k2 {type string;}" " leaf k1 {type string;}" "}" - "}"}, + "}" + }, {NULL, NULL} }; @@ -1106,7 +1111,8 @@ test_key_order(void **state) assert_string_equal("k2", node->name); struct module_clb_list list2[] = { - {"b", "module b {" + { + "b", "module b {" "yang-version 1.1;" "namespace urn:test:b;" "prefix b;" @@ -1121,7 +1127,8 @@ test_key_order(void **state) " leaf k1 {type string;}" " leaf k3 {type string;}" "}" - "}"}, + "}" + }, {NULL, NULL} }; @@ -1156,7 +1163,7 @@ test_disabled_enum(void **state) "}}" "}"; assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Enumeration type of node \"l\" without any (or all disabled) valid values.", "Schema location \"/a:l\"."); + CHECK_LOG_CTX("Node \"l\" without any (or all disabled) valid values.", "Schema location \"/a:l\"."); /* disabled default value */ str = "module a {" @@ -1263,10 +1270,10 @@ test_identity(void **state) assert_ptr_equal(mod->identities[1].derived[0], &mod->identities[0]); ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, "submodule inv_sub {belongs-to inv {prefix inv;} identity i1;}"); - TEST_SCHEMA_ERR(0, 0, "inv", "identity i1 {base i2;}", "Unable to find base (i2) of identity \"i1\".", "/inv:{identity='i1'}"); - TEST_SCHEMA_ERR(0, 0, "inv", "identity i1 {base i1;}", "Identity \"i1\" is derived from itself.", "/inv:{identity='i1'}"); + TEST_SCHEMA_ERR(0, 0, "inv", "identity i1 {base i2;}", "Unable to find base (i2) of identity \"i1\".", "Path \"/inv:{identity='i1'}\"."); + TEST_SCHEMA_ERR(0, 0, "inv", "identity i1 {base i1;}", "Identity \"i1\" is derived from itself.", "Path \"/inv:{identity='i1'}\"."); TEST_SCHEMA_ERR(0, 0, "inv", "identity i1 {base i2;}identity i2 {base i3;}identity i3 {base i1;}", - "Identity \"i1\" is indirectly derived from itself.", "/inv:{identity='i3'}"); + "Identity \"i1\" is indirectly derived from itself.", "Path \"/inv:{identity='i3'}\"."); /* base in non-implemented module */ ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, @@ -1606,8 +1613,8 @@ test_extension_argument_element(void **state) /* invalid */ mod_test_yang = "module x { namespace \"urn:x\"; prefix x; import a { prefix a; } a:e; }"; assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, mod_test_yang, LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Parsing module \"x\" failed.", NULL, - "Extension instance \"a:e\" missing argument element \"name\".", NULL); + CHECK_LOG_CTX("Parsing module \"x\" failed.", NULL); + CHECK_LOG_CTX("Extension instance \"a:e\" missing argument element \"name\".", NULL); mod_test_yin = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" "<module name=\"x\"\n" @@ -1622,8 +1629,8 @@ test_extension_argument_element(void **state) " <a:e/>\n" "</module>\n"; assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, mod_test_yin, LYS_IN_YIN, NULL)); - CHECK_LOG_CTX("Parsing module \"x\" failed.", NULL, - "Extension instance \"a:e\" missing argument element \"name\".", NULL); + CHECK_LOG_CTX("Parsing module \"x\" failed.", NULL); + CHECK_LOG_CTX("Extension instance \"a:e\" missing argument element \"name\".", NULL); mod_test_yin = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" "<module name=\"x\"\n" @@ -1638,8 +1645,8 @@ test_extension_argument_element(void **state) " <a:e name=\"xxx\"/>\n" "</module>\n"; assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, mod_test_yin, LYS_IN_YIN, NULL)); - CHECK_LOG_CTX("Parsing module \"x\" failed.", NULL, - "Extension instance \"a:e\" missing argument element \"name\".", NULL); + CHECK_LOG_CTX("Parsing module \"x\" failed.", NULL); + CHECK_LOG_CTX("Extension instance \"a:e\" missing argument element \"name\".", NULL); mod_test_yin = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" "<module name=\"x\"\n" @@ -1656,8 +1663,8 @@ test_extension_argument_element(void **state) " </a:e>\n" "</module>\n"; assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, mod_test_yin, LYS_IN_YIN, NULL)); - CHECK_LOG_CTX("Parsing module \"x\" failed.", NULL, - "Extension instance \"a:e\" element and its argument element \"name\" are expected in the same namespace, but they differ.", + CHECK_LOG_CTX("Parsing module \"x\" failed.", NULL); + CHECK_LOG_CTX("Extension instance \"a:e\" element and its argument element \"name\" are expected in the same namespace, but they differ.", NULL); mod_test_yin = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" @@ -1675,8 +1682,8 @@ test_extension_argument_element(void **state) " </a:e>\n" "</module>\n"; assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, mod_test_yin, LYS_IN_YIN, NULL)); - CHECK_LOG_CTX("Parsing module \"x\" failed.", NULL, - "Extension instance \"a:e\" expects argument element \"name\" as its first XML child, but \"value\" element found.", + CHECK_LOG_CTX("Parsing module \"x\" failed.", NULL); + CHECK_LOG_CTX("Extension instance \"a:e\" expects argument element \"name\" as its first XML child, but \"value\" element found.", NULL); } diff --git a/tests/utests/schema/test_tree_schema_compile.c b/tests/utests/schema/test_tree_schema_compile.c index d6f0538..85da486 100644 --- a/tests/utests/schema/test_tree_schema_compile.c +++ b/tests/utests/schema/test_tree_schema_compile.c @@ -1,9 +1,10 @@ -/* +/** * @file test_tree_schema_compile.c - * @author: Radek Krejci <rkrejci@cesnet.cz> + * @author Radek Krejci <rkrejci@cesnet.cz> + * @author Michal Vasko <mvasko@cesnet.cz> * @brief unit tests for functions from parser_yang.c * - * Copyright (c) 2018 CESNET, z.s.p.o. + * 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. @@ -82,6 +83,7 @@ test_module(void **state) ly_in_free(in, 0); assert_int_equal(0, mod->implemented); assert_int_equal(LY_EINVAL, lys_set_implemented(mod, feats)); + CHECK_LOG_CTX("Feature \"invalid\" not found in module \"test\".", NULL); assert_int_equal(LY_SUCCESS, lys_set_implemented(mod, NULL)); assert_non_null(mod->compiled); assert_string_equal("test", mod->name); @@ -112,7 +114,7 @@ test_module(void **state) assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in)); assert_int_equal(LY_EEXIST, lys_parse(UTEST_LYCTX, in, LYS_IN_YANG, NULL, &mod)); ly_in_free(in, 0); - CHECK_LOG_CTX("Duplicate identifier \"a\" of data definition/RPC/action/notification statement.", "/aa:a"); + CHECK_LOG_CTX("Duplicate identifier \"a\" of data definition/RPC/action/notification statement.", "Path \"/aa:a\"."); } static void @@ -127,7 +129,7 @@ test_name_collisions(void **state) " leaf c {type empty;}" "}"; assert_int_equal(LY_EEXIST, lys_parse_mem(UTEST_LYCTX, yang_data, LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Duplicate identifier \"c\" of data definition/RPC/action/notification statement.", "/a:c"); + CHECK_LOG_CTX("Duplicate identifier \"c\" of data definition/RPC/action/notification statement.", "Path \"/a:c\"."); UTEST_LOG_CLEAN; yang_data = "module a {namespace urn:a;prefix a;" @@ -136,7 +138,7 @@ test_name_collisions(void **state) " notification c;" "}"; assert_int_equal(LY_EEXIST, lys_parse_mem(UTEST_LYCTX, yang_data, LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Duplicate identifier \"c\" of data definition/RPC/action/notification statement.", "/a:c"); + CHECK_LOG_CTX("Duplicate identifier \"c\" of data definition/RPC/action/notification statement.", "Path \"/a:c\"."); UTEST_LOG_CLEAN; yang_data = "module a {namespace urn:a;prefix a;" @@ -145,7 +147,7 @@ test_name_collisions(void **state) " rpc c;" "}"; assert_int_equal(LY_EEXIST, lys_parse_mem(UTEST_LYCTX, yang_data, LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Duplicate identifier \"c\" of data definition/RPC/action/notification statement.", "/a:c"); + CHECK_LOG_CTX("Duplicate identifier \"c\" of data definition/RPC/action/notification statement.", "Path \"/a:c\"."); UTEST_LOG_CLEAN; yang_data = "module a {namespace urn:a;prefix a;" @@ -159,7 +161,7 @@ test_name_collisions(void **state) " }" "}"; assert_int_equal(LY_EEXIST, lys_parse_mem(UTEST_LYCTX, yang_data, LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Duplicate identifier \"c\" of data definition/RPC/action/notification statement.", "/a:ch/c/c"); + CHECK_LOG_CTX("Duplicate identifier \"c\" of data definition/RPC/action/notification statement.", "Path \"/a:ch/c/c\"."); UTEST_LOG_CLEAN; /* nested */ @@ -168,7 +170,7 @@ test_name_collisions(void **state) "container a;" "}}}"; assert_int_equal(LY_EEXIST, lys_parse_mem(UTEST_LYCTX, yang_data, LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Duplicate identifier \"a\" of data definition/RPC/action/notification statement.", "/a:c/l/a"); + CHECK_LOG_CTX("Duplicate identifier \"a\" of data definition/RPC/action/notification statement.", "Path \"/a:c/l/a\"."); UTEST_LOG_CLEAN; yang_data = "module a {yang-version 1.1;namespace urn:a;prefix a;container c { list l {key \"k\"; leaf k {type string;}" @@ -176,7 +178,7 @@ test_name_collisions(void **state) "notification a;" "}}}"; assert_int_equal(LY_EEXIST, lys_parse_mem(UTEST_LYCTX, yang_data, LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Duplicate identifier \"a\" of data definition/RPC/action/notification statement.", "/a:c/l/a"); + CHECK_LOG_CTX("Duplicate identifier \"a\" of data definition/RPC/action/notification statement.", "Path \"/a:c/l/a\"."); UTEST_LOG_CLEAN; yang_data = "module a {yang-version 1.1;namespace urn:a;prefix a;container c { list l {key \"k\"; leaf k {type string;}" @@ -184,7 +186,7 @@ test_name_collisions(void **state) "action a;" "}}}"; assert_int_equal(LY_EEXIST, lys_parse_mem(UTEST_LYCTX, yang_data, LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Duplicate identifier \"a\" of data definition/RPC/action/notification statement.", "/a:c/l/a"); + CHECK_LOG_CTX("Duplicate identifier \"a\" of data definition/RPC/action/notification statement.", "Path \"/a:c/l/a\"."); UTEST_LOG_CLEAN; /* grouping */ @@ -250,15 +252,6 @@ test_node_leaflist(void **state) assert_non_null(((struct lysc_type_leafref *)type)->realtype); assert_int_equal(LY_TYPE_INT8, ((struct lysc_type_leafref *)type)->realtype->basetype); - /* now test for string type is in file ./tests/utests/types/string.c */ -#if 0 - assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module b {namespace urn:b;prefix b;leaf-list ll {type string;}}", LYS_IN_YANG, &mod)); - assert_non_null(mod->compiled); - assert_non_null((ll = (struct lysc_node_leaflist *)mod->compiled->data)); - assert_int_equal(0, ll->min); - assert_int_equal((uint32_t)-1, ll->max); -#endif - assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module c {yang-version 1.1;namespace urn:c;prefix c;typedef mytype {type int8;default 10;}" "leaf-list ll1 {type mytype;default 1; default 1; config false;}" "leaf-list ll2 {type mytype; ordered-by user;}}", LYS_IN_YANG, &mod)); @@ -304,7 +297,7 @@ test_node_leaflist(void **state) /* invalid */ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module aa {namespace urn:aa;prefix aa;leaf-list ll {type empty;}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Leaf-list of type \"empty\" is allowed only in YANG 1.1 modules.", "/aa:ll"); + CHECK_LOG_CTX("Leaf-list of type \"empty\" is allowed only in YANG 1.1 modules.", "Path \"/aa:ll\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module bb {yang-version 1.1;namespace urn:bb;prefix bb;leaf-list ll {type empty; default x;}}", LYS_IN_YANG, NULL)); CHECK_LOG_CTX("Invalid default - value does not fit the type (Invalid empty value length 1.).", "Schema location \"/bb:ll\"."); @@ -317,12 +310,12 @@ test_node_leaflist(void **state) assert_int_equal(3, LY_ARRAY_COUNT(ll->dflts)); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module dd {yang-version 1.1;namespace urn:dd;prefix dd;" "leaf-list ll {type string; default one;default two;default one;}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Configuration leaf-list has multiple defaults of the same value \"one\".", "/dd:ll"); + CHECK_LOG_CTX("Configuration leaf-list has multiple defaults of the same value \"one\".", "Path \"/dd:ll\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ee {yang-version 1.1; namespace urn:ee;prefix ee;" "leaf ref {type instance-identifier {require-instance true;} default \"/ee:g\";}}", LYS_IN_YANG, NULL)); CHECK_LOG_CTX("Invalid default - value does not fit the type " - "(Invalid instance-identifier \"/ee:g\" value - semantic error.).", "Schema location \"/ee:ref\"."); + "(Invalid instance-identifier \"/ee:g\" value - semantic error: Not found node \"g\" in path.).", "Schema location \"/ee:ref\"."); } static void @@ -412,11 +405,11 @@ test_node_list(void **state) /* invalid */ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module aa {namespace urn:aa;prefix aa;list l;}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Missing key in list representing configuration data.", "/aa:l"); + CHECK_LOG_CTX("Missing key in list representing configuration data.", "Path \"/aa:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module bb {yang-version 1.1; namespace urn:bb;prefix bb;" "list l {key x; leaf x {type string; when 1;}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("List's key must not have any \"when\" statement.", "/bb:l/x"); + CHECK_LOG_CTX("List's key must not have any \"when\" statement.", "Path \"/bb:l/x\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module cc {yang-version 1.1;namespace urn:cc;prefix cc;feature f;" "list l {key x; leaf x {type string; if-feature f;}}}", LYS_IN_YANG, NULL)); @@ -424,43 +417,43 @@ test_node_list(void **state) assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module dd {namespace urn:dd;prefix dd;" "list l {key x; leaf x {type string; config false;}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Key of a configuration list must not be a state leaf.", "/dd:l/x"); + CHECK_LOG_CTX("Key of a configuration list must not be a state leaf.", "Path \"/dd:l/x\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ee {namespace urn:ee;prefix ee;" "list l {config false;key x; leaf x {type string; config true;}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Configuration node cannot be child of any state data node.", "/ee:l/x"); + CHECK_LOG_CTX("Configuration node cannot be child of any state data node.", "Path \"/ee:l/x\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ff {namespace urn:ff;prefix ff;" "list l {key x; leaf-list x {type string;}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("The list's key \"x\" not found.", "/ff:l"); + CHECK_LOG_CTX("The list's key \"x\" not found.", "Path \"/ff:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module gg {namespace urn:gg;prefix gg;" "list l {key x; unique y;leaf x {type string;} leaf-list y {type string;}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Unique's descendant-schema-nodeid \"y\" refers to leaf-list node instead of a leaf.", "/gg:l"); + CHECK_LOG_CTX("Unique's descendant-schema-nodeid \"y\" refers to leaf-list node instead of a leaf.", "Path \"/gg:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module hh {namespace urn:hh;prefix hh;" "list l {key x; unique \"x y\";leaf x {type string;} leaf y {config false; type string;}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Unique statement \"x y\" refers to leaves with different config type.", "/hh:l"); + CHECK_LOG_CTX("Unique statement \"x y\" refers to leaves with different config type.", "Path \"/hh:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ii {namespace urn:ii;prefix ii;" "list l {key x; unique a:x;leaf x {type string;}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Invalid descendant-schema-nodeid value \"a:x\" - prefix \"a\" not defined in module \"ii\".", "/ii:l"); + CHECK_LOG_CTX("Invalid descendant-schema-nodeid value \"a:x\" - prefix \"a\" not defined in module \"ii\".", "Path \"/ii:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module jj {namespace urn:jj;prefix jj;" "list l {key x; unique c/x;leaf x {type string;}container c {leaf y {type string;}}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Invalid descendant-schema-nodeid value \"c/x\" - target node not found.", "/jj:l"); + CHECK_LOG_CTX("Invalid descendant-schema-nodeid value \"c/x\" - target node not found.", "Path \"/jj:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module kk {namespace urn:kk;prefix kk;" "list l {key x; unique c^y;leaf x {type string;}container c {leaf y {type string;}}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Invalid descendant-schema-nodeid value \"c^\" - missing \"/\" as node-identifier separator.", "/kk:l"); + CHECK_LOG_CTX("Invalid descendant-schema-nodeid value \"c^\" - missing \"/\" as node-identifier separator.", "Path \"/kk:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ll {namespace urn:ll;prefix ll;" "list l {key \"x y x\";leaf x {type string;}leaf y {type string;}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Duplicated key identifier \"x\".", "/ll:l"); + CHECK_LOG_CTX("Duplicated key identifier \"x\".", "Path \"/ll:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module mm {namespace urn:mm;prefix mm;" "list l {key x;leaf x {type empty;}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("List's key cannot be of \"empty\" type until it is in YANG 1.1 module.", "/mm:l/x"); + CHECK_LOG_CTX("List key of the \"empty\" type is allowed only in YANG 1.1 modules.", "Path \"/mm:l/x\"."); } static void @@ -499,26 +492,26 @@ test_node_choice(void **state) assert_int_equal(LY_EEXIST, lys_parse_mem(UTEST_LYCTX, "module aa {namespace urn:aa;prefix aa;" "choice ch {case a {leaf x {type string;}}leaf x {type string;}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Duplicate identifier \"x\" of data definition/RPC/action/notification statement.", "/aa:ch/x/x"); + CHECK_LOG_CTX("Duplicate identifier \"x\" of data definition/RPC/action/notification statement.", "Path \"/aa:ch/x/x\"."); assert_int_equal(LY_EEXIST, lys_parse_mem(UTEST_LYCTX, "module aa2 {namespace urn:aa2;prefix aa;" "choice ch {case a {leaf y {type string;}}case b {leaf y {type string;}}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Duplicate identifier \"y\" of data definition/RPC/action/notification statement.", "/aa2:ch/b/y"); + CHECK_LOG_CTX("Duplicate identifier \"y\" of data definition/RPC/action/notification statement.", "Path \"/aa2:ch/b/y\"."); assert_int_equal(LY_EEXIST, lys_parse_mem(UTEST_LYCTX, "module bb {namespace urn:bb;prefix bb;" "choice ch {case a {leaf x {type string;}}leaf a {type string;}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Duplicate identifier \"a\" of case statement.", "/bb:ch/a"); + CHECK_LOG_CTX("Duplicate identifier \"a\" of case statement.", "Path \"/bb:ch/a\"."); assert_int_equal(LY_EEXIST, lys_parse_mem(UTEST_LYCTX, "module bb2 {namespace urn:bb2;prefix bb;" "choice ch {case b {leaf x {type string;}}case b {leaf y {type string;}}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Duplicate identifier \"b\" of case statement.", "/bb2:ch/b"); + CHECK_LOG_CTX("Duplicate identifier \"b\" of case statement.", "Path \"/bb2:ch/b\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ca {namespace urn:ca;prefix ca;" "choice ch {default c;case a {leaf x {type string;}}case b {leaf y {type string;}}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Default case \"c\" not found.", "/ca:ch"); + CHECK_LOG_CTX("Default case \"c\" not found.", "Path \"/ca:ch\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module cb {namespace urn:cb;prefix cb; import a {prefix a;}" "choice ch {default a:a;case a {leaf x {type string;}}case b {leaf y {type string;}}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Default case \"a:a\" not found.", "/cb:ch"); + CHECK_LOG_CTX("Default case \"a:a\" not found.", "Path \"/cb:ch\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module cc {namespace urn:cc;prefix cc;" "choice ch {default a;case a {leaf x {mandatory true;type string;}}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Mandatory node \"x\" under the default case \"a\".", "/cc:ch"); + CHECK_LOG_CTX("Mandatory node \"x\" under the default case \"a\".", "Path \"/cc:ch\"."); /* TODO check with mandatory nodes from augment placed into the case */ } @@ -544,8 +537,9 @@ test_node_anydata(void **state) /* invalid */ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module aa {namespace urn:aa;prefix aa;anydata any;}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Parsing module \"aa\" failed.", NULL, - "Invalid keyword \"anydata\" as a child of \"module\" - the statement is allowed only in YANG 1.1 modules.", "Line number 1."); + CHECK_LOG_CTX("Parsing module \"aa\" failed.", NULL); + CHECK_LOG_CTX("Invalid keyword \"anydata\" as a child of \"module\" - the statement is allowed only in YANG 1.1 modules.", + "Line number 1."); } static void @@ -579,31 +573,32 @@ test_action(void **state) /* invalid */ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module aa {namespace urn:aa;prefix aa;container top {action x;}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Parsing module \"aa\" failed.", NULL, - "Invalid keyword \"action\" as a child of \"container\" - the statement is allowed only in YANG 1.1 modules.", "Line number 1."); + CHECK_LOG_CTX("Parsing module \"aa\" failed.", NULL); + CHECK_LOG_CTX("Invalid keyword \"action\" as a child of \"container\" - the statement is allowed only in YANG 1.1 modules.", + "Line number 1."); assert_int_equal(LY_EEXIST, lys_parse_mem(UTEST_LYCTX, "module bb {namespace urn:bb;prefix bb;leaf x{type string;} rpc x;}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Duplicate identifier \"x\" of data definition/RPC/action/notification statement.", "/bb:x"); + CHECK_LOG_CTX("Duplicate identifier \"x\" of data definition/RPC/action/notification statement.", "Path \"/bb:x\"."); assert_int_equal(LY_EEXIST, lys_parse_mem(UTEST_LYCTX, "module cc {yang-version 1.1; namespace urn:cc;prefix cc;container c {leaf y {type string;} action y;}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Duplicate identifier \"y\" of data definition/RPC/action/notification statement.", "/cc:c/y"); + CHECK_LOG_CTX("Duplicate identifier \"y\" of data definition/RPC/action/notification statement.", "Path \"/cc:c/y\"."); assert_int_equal(LY_EEXIST, lys_parse_mem(UTEST_LYCTX, "module dd {yang-version 1.1; namespace urn:dd;prefix dd;container c {action z; action z;}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Duplicate identifier \"z\" of data definition/RPC/action/notification statement.", "/dd:c/z"); + CHECK_LOG_CTX("Duplicate identifier \"z\" of data definition/RPC/action/notification statement.", "Path \"/dd:c/z\"."); ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, "submodule eesub {belongs-to ee {prefix ee;} notification w;}"); assert_int_equal(LY_EEXIST, lys_parse_mem(UTEST_LYCTX, "module ee {yang-version 1.1; namespace urn:ee;prefix ee;include eesub; rpc w;}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Duplicate identifier \"w\" of data definition/RPC/action/notification statement.", "/ee:w"); + CHECK_LOG_CTX("Duplicate identifier \"w\" of data definition/RPC/action/notification statement.", "Path \"/ee:w\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ff {yang-version 1.1; namespace urn:ff;prefix ff; rpc test {input {container a {leaf b {type string;}}}}" "augment /test/input/a {action invalid {input {leaf x {type string;}}}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Action \"invalid\" is placed inside another RPC/action.", "/ff:{augment='/test/input/a'}/invalid"); + CHECK_LOG_CTX("Action \"invalid\" is placed inside another RPC/action.", "Path \"/ff:{augment='/test/input/a'}/invalid\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module gg {yang-version 1.1; namespace urn:gg;prefix gg; notification test {container a {leaf b {type string;}}}" "augment /test/a {action invalid {input {leaf x {type string;}}}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Action \"invalid\" is placed inside notification.", "/gg:{augment='/test/a'}/invalid"); + CHECK_LOG_CTX("Action \"invalid\" is placed inside notification.", "Path \"/gg:{augment='/test/a'}/invalid\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module hh {yang-version 1.1; namespace urn:hh;prefix hh; notification test {container a {uses grp;}}" "grouping grp {action invalid {input {leaf x {type string;}}}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Action \"invalid\" is placed inside notification.", "/hh:test/a/{uses='grp'}/invalid"); + CHECK_LOG_CTX("Action \"invalid\" is placed inside notification.", "Path \"/hh:test/a/{uses='grp'}/invalid\"."); } static void @@ -650,30 +645,31 @@ test_notification(void **state) /* invalid */ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module aa {namespace urn:aa;prefix aa;container top {notification x;}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Parsing module \"aa\" failed.", NULL, - "Invalid keyword \"notification\" as a child of \"container\" - the statement is allowed only in YANG 1.1 modules.", "Line number 1."); + CHECK_LOG_CTX("Parsing module \"aa\" failed.", NULL); + CHECK_LOG_CTX("Invalid keyword \"notification\" as a child of \"container\" - the statement is allowed only in YANG 1.1 modules.", + "Line number 1."); assert_int_equal(LY_EEXIST, lys_parse_mem(UTEST_LYCTX, "module bb {namespace urn:bb;prefix bb;leaf x{type string;} notification x;}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Duplicate identifier \"x\" of data definition/RPC/action/notification statement.", "/bb:x"); + CHECK_LOG_CTX("Duplicate identifier \"x\" of data definition/RPC/action/notification statement.", "Path \"/bb:x\"."); assert_int_equal(LY_EEXIST, lys_parse_mem(UTEST_LYCTX, "module cc {yang-version 1.1; namespace urn:cc;prefix cc;container c {leaf y {type string;} notification y;}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Duplicate identifier \"y\" of data definition/RPC/action/notification statement.", "/cc:c/y"); + CHECK_LOG_CTX("Duplicate identifier \"y\" of data definition/RPC/action/notification statement.", "Path \"/cc:c/y\"."); assert_int_equal(LY_EEXIST, lys_parse_mem(UTEST_LYCTX, "module dd {yang-version 1.1; namespace urn:dd;prefix dd;container c {notification z; notification z;}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Duplicate identifier \"z\" of data definition/RPC/action/notification statement.", "/dd:c/z"); + CHECK_LOG_CTX("Duplicate identifier \"z\" of data definition/RPC/action/notification statement.", "Path \"/dd:c/z\"."); ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, "submodule eesub {belongs-to ee {prefix ee;} rpc w;}"); assert_int_equal(LY_EEXIST, lys_parse_mem(UTEST_LYCTX, "module ee {yang-version 1.1; namespace urn:ee;prefix ee;include eesub; notification w;}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Duplicate identifier \"w\" of data definition/RPC/action/notification statement.", "/ee:w"); + CHECK_LOG_CTX("Duplicate identifier \"w\" of data definition/RPC/action/notification statement.", "Path \"/ee:w\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ff {yang-version 1.1; namespace urn:ff;prefix ff; rpc test {input {container a {leaf b {type string;}}}}" "augment /test/input/a {notification invalid {leaf x {type string;}}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Notification \"invalid\" is placed inside RPC/action.", "/ff:{augment='/test/input/a'}/invalid"); + CHECK_LOG_CTX("Notification \"invalid\" is placed inside RPC/action.", "Path \"/ff:{augment='/test/input/a'}/invalid\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module gg {yang-version 1.1; namespace urn:gg;prefix gg; notification test {container a {leaf b {type string;}}}" "augment /test/a {notification invalid {leaf x {type string;}}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Notification \"invalid\" is placed inside another notification.", "/gg:{augment='/test/a'}/invalid"); + CHECK_LOG_CTX("Notification \"invalid\" is placed inside another notification.", "Path \"/gg:{augment='/test/a'}/invalid\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module hh {yang-version 1.1; namespace urn:hh;prefix hh; rpc test {input {container a {uses grp;}}}" "grouping grp {notification invalid {leaf x {type string;}}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Notification \"invalid\" is placed inside RPC/action.", "/hh:test/input/a/{uses='grp'}/invalid"); + CHECK_LOG_CTX("Notification \"invalid\" is placed inside RPC/action.", "Path \"/hh:test/input/a/{uses='grp'}/invalid\"."); } /** @@ -686,21 +682,6 @@ test_type_range(void **state) struct lys_module *mod; struct lysc_type *type; -#if 0 - /*test about int8 should be in tests/utests/types/int8.c*/ - assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module a {namespace urn:a;prefix a;leaf l {type int8 {range min..10|max;}}}", LYS_IN_YANG, &mod)); - type = ((struct lysc_node_leaf *)mod->compiled->data)->type; - assert_non_null(type); - assert_int_equal(LY_TYPE_INT8, type->basetype); - assert_non_null(((struct lysc_type_num *)type)->range); - assert_non_null(((struct lysc_type_num *)type)->range->parts); - assert_int_equal(2, LY_ARRAY_COUNT(((struct lysc_type_num *)type)->range->parts)); - assert_int_equal(-128, ((struct lysc_type_num *)type)->range->parts[0].min_64); - assert_int_equal(10, ((struct lysc_type_num *)type)->range->parts[0].max_64); - assert_int_equal(127, ((struct lysc_type_num *)type)->range->parts[1].min_64); - assert_int_equal(127, ((struct lysc_type_num *)type)->range->parts[1].max_64); -#endif - assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module b {namespace urn:b;prefix b;leaf l {type int16 {range min..10|max;}}}", LYS_IN_YANG, &mod)); type = ((struct lysc_node_leaf *)mod->compiled->data)->type; assert_non_null(type); @@ -937,83 +918,56 @@ test_type_length(void **state) assert_int_equal(10, ((struct lysc_type_bin *)type)->length->parts[0].min_u64); assert_int_equal(100, ((struct lysc_type_bin *)type)->length->parts[0].max_u64); - /* new string is tested in file ./tests/utests/types/string.c */ -#if 0 - assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module l {namespace urn:l;prefix l;typedef mytype {type string {length 10..100;}}" - "typedef mytype2 {type mytype {pattern '[0-9]*';}} leaf l {type mytype2 {pattern '[0-4]*';}}}", LYS_IN_YANG, &mod)); - type = ((struct lysc_node_leaf *)mod->compiled->data)->type; - assert_non_null(type); - assert_int_equal(LY_TYPE_STRING, type->basetype); - assert_int_equal(1, type->refcount); - assert_non_null(((struct lysc_type_str *)type)->length); - assert_non_null(((struct lysc_type_str *)type)->length->parts); - assert_int_equal(1, LY_ARRAY_COUNT(((struct lysc_type_str *)type)->length->parts)); - assert_int_equal(10, ((struct lysc_type_str *)type)->length->parts[0].min_u64); - assert_int_equal(100, ((struct lysc_type_str *)type)->length->parts[0].max_u64); - - assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module m {namespace urn:m;prefix m;typedef mytype {type string {length 10;}}" - "leaf l {type mytype {length min..max;}}}", LYS_IN_YANG, &mod)); - type = ((struct lysc_node_leaf *)mod->compiled->data)->type; - assert_non_null(type); - assert_int_equal(LY_TYPE_STRING, type->basetype); - assert_int_equal(1, type->refcount); - assert_non_null(((struct lysc_type_str *)type)->length); - assert_non_null(((struct lysc_type_str *)type)->length->parts); - assert_int_equal(1, LY_ARRAY_COUNT(((struct lysc_type_str *)type)->length->parts)); - assert_int_equal(10, ((struct lysc_type_str *)type)->length->parts[0].min_u64); - assert_int_equal(10, ((struct lysc_type_str *)type)->length->parts[0].max_u64); -#endif - /* invalid values */ assert_int_equal(LY_EDENIED, lys_parse_mem(UTEST_LYCTX, "module aa {namespace urn:aa;prefix aa;leaf l {type binary {length -10;}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Invalid length restriction - value \"-10\" does not fit the type limitations.", "/aa:l"); + CHECK_LOG_CTX("Invalid length restriction - value \"-10\" does not fit the type limitations.", "Path \"/aa:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module bb {namespace urn:bb;prefix bb;leaf l {type binary {length 18446744073709551616;}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Invalid length restriction - invalid value \"18446744073709551616\".", "/bb:l"); + CHECK_LOG_CTX("Invalid length restriction - invalid value \"18446744073709551616\".", "Path \"/bb:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module cc {namespace urn:cc;prefix cc;leaf l {type binary {length \"max .. 10\";}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Invalid length restriction - unexpected data after max keyword (.. 10).", "/cc:l"); + CHECK_LOG_CTX("Invalid length restriction - unexpected data after max keyword (.. 10).", "Path \"/cc:l\"."); assert_int_equal(LY_EEXIST, lys_parse_mem(UTEST_LYCTX, "module dd {namespace urn:dd;prefix dd;leaf l {type binary {length 50..10;}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Invalid length restriction - values are not in ascending order (10).", "/dd:l"); + CHECK_LOG_CTX("Invalid length restriction - values are not in ascending order (10).", "Path \"/dd:l\"."); assert_int_equal(LY_EEXIST, lys_parse_mem(UTEST_LYCTX, "module ee {namespace urn:ee;prefix ee;leaf l {type binary {length \"50 | 10\";}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Invalid length restriction - values are not in ascending order (10).", "/ee:l"); + CHECK_LOG_CTX("Invalid length restriction - values are not in ascending order (10).", "Path \"/ee:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ff {namespace urn:ff;prefix ff;leaf l {type binary {length \"x\";}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Invalid length restriction - unexpected data (x).", "/ff:l"); + CHECK_LOG_CTX("Invalid length restriction - unexpected data (x).", "Path \"/ff:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module gg {namespace urn:gg;prefix gg;leaf l {type binary {length \"50 | min\";}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Invalid length restriction - unexpected data before min keyword (50 | ).", "/gg:l"); + CHECK_LOG_CTX("Invalid length restriction - unexpected data before min keyword (50 | ).", "Path \"/gg:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module hh {namespace urn:hh;prefix hh;leaf l {type binary {length \"| 50\";}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Invalid length restriction - unexpected beginning of the expression (| 50).", "/hh:l"); + CHECK_LOG_CTX("Invalid length restriction - unexpected beginning of the expression (| 50).", "Path \"/hh:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ii {namespace urn:ii;prefix ii;leaf l {type binary {length \"10 ..\";}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Invalid length restriction - unexpected end of the expression after \"..\" (10 ..).", "/ii:l"); + CHECK_LOG_CTX("Invalid length restriction - unexpected end of the expression after \"..\" (10 ..).", "Path \"/ii:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module jj {namespace urn:jj;prefix jj;leaf l {type binary {length \".. 10\";}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Invalid length restriction - unexpected \"..\" without a lower bound.", "/jj:l"); + CHECK_LOG_CTX("Invalid length restriction - unexpected \"..\" without a lower bound.", "Path \"/jj:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module kk {namespace urn:kk;prefix kk;leaf l {type binary {length \"10 |\";}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Invalid length restriction - unexpected end of the expression (10 |).", "/kk:l"); + CHECK_LOG_CTX("Invalid length restriction - unexpected end of the expression (10 |).", "Path \"/kk:l\"."); assert_int_equal(LY_EEXIST, lys_parse_mem(UTEST_LYCTX, "module kl {namespace urn:kl;prefix kl;leaf l {type binary {length \"10..20 | 15..30\";}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Invalid length restriction - values are not in ascending order (15).", "/kl:l"); + CHECK_LOG_CTX("Invalid length restriction - values are not in ascending order (15).", "Path \"/kl:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ll {namespace urn:ll;prefix ll;typedef mytype {type binary {length 10;}}" "leaf l {type mytype {length 11;}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Invalid length restriction - the derived restriction (11) is not equally or more limiting.", "/ll:l"); + CHECK_LOG_CTX("Invalid length restriction - the derived restriction (11) is not equally or more limiting.", "Path \"/ll:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module mm {namespace urn:mm;prefix mm;typedef mytype {type binary {length 10..100;}}" "leaf l {type mytype {length 1..11;}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Invalid length restriction - the derived restriction (1..11) is not equally or more limiting.", "/mm:l"); + CHECK_LOG_CTX("Invalid length restriction - the derived restriction (1..11) is not equally or more limiting.", "Path \"/mm:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module nn {namespace urn:nn;prefix nn;typedef mytype {type binary {length 10..100;}}" "leaf l {type mytype {length 20..110;}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Invalid length restriction - the derived restriction (20..110) is not equally or more limiting.", "/nn:l"); + CHECK_LOG_CTX("Invalid length restriction - the derived restriction (20..110) is not equally or more limiting.", "Path \"/nn:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module oo {namespace urn:oo;prefix oo;typedef mytype {type binary {length 10..100;}}" "leaf l {type mytype {length 20..30|110..120;}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Invalid length restriction - the derived restriction (20..30|110..120) is not equally or more limiting.", "/oo:l"); + CHECK_LOG_CTX("Invalid length restriction - the derived restriction (20..30|110..120) is not equally or more limiting.", "Path \"/oo:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module pp {namespace urn:pp;prefix pp;typedef mytype {type binary {length 10..11;}}" "leaf l {type mytype {length 15;}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Invalid length restriction - the derived restriction (15) is not equally or more limiting.", "/pp:l"); + CHECK_LOG_CTX("Invalid length restriction - the derived restriction (15) is not equally or more limiting.", "Path \"/pp:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module qq {namespace urn:qq;prefix qq;typedef mytype {type binary {length 10..20|30..40;}}" "leaf l {type mytype {length 15..35;}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Invalid length restriction - the derived restriction (15..35) is not equally or more limiting.", "/qq:l"); + CHECK_LOG_CTX("Invalid length restriction - the derived restriction (15..35) is not equally or more limiting.", "Path \"/qq:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module rr {namespace urn:rr;prefix rr;typedef mytype {type binary {length 10;}}" "leaf l {type mytype {length 10..35;}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Invalid length restriction - the derived restriction (10..35) is not equally or more limiting.", "/rr:l"); + CHECK_LOG_CTX("Invalid length restriction - the derived restriction (10..35) is not equally or more limiting.", "Path \"/rr:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ss {namespace urn:ss;prefix ss;leaf l {type binary {pattern '[0-9]*';}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Invalid type restrictions for binary type.", "/ss:l"); + CHECK_LOG_CTX("Invalid type restrictions for binary type.", "Path \"/ss:l\"."); } static void @@ -1152,61 +1106,63 @@ test_type_enum(void **state) /* invalid cases */ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module aa {namespace urn:aa;prefix aa; feature f; leaf l {type enumeration {" "enum one {if-feature f;}}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Parsing module \"aa\" failed.", NULL, - "Invalid keyword \"if-feature\" as a child of \"enum\" - the statement is allowed only in YANG 1.1 modules.", "Line number 1."); + CHECK_LOG_CTX("Parsing module \"aa\" failed.", NULL); + CHECK_LOG_CTX("Invalid keyword \"if-feature\" as a child of \"enum\" - the statement is allowed only in YANG 1.1 modules.", + "Line number 1."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module aa {namespace urn:aa;prefix aa; leaf l {type enumeration {" "enum one {value -2147483649;}}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Parsing module \"aa\" failed.", NULL, - "Invalid value \"-2147483649\" of \"value\".", "Line number 1."); + CHECK_LOG_CTX("Parsing module \"aa\" failed.", NULL); + CHECK_LOG_CTX("Invalid value \"-2147483649\" of \"value\".", "Line number 1."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module aa {namespace urn:aa;prefix aa; leaf l {type enumeration {" "enum one {value 2147483648;}}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Parsing module \"aa\" failed.", NULL, - "Invalid value \"2147483648\" of \"value\".", "Line number 1."); + CHECK_LOG_CTX("Parsing module \"aa\" failed.", NULL); + CHECK_LOG_CTX("Invalid value \"2147483648\" of \"value\".", "Line number 1."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module aa {namespace urn:aa;prefix aa; leaf l {type enumeration {" "enum one; enum one;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Parsing module \"aa\" failed.", NULL, - "Duplicate identifier \"one\" of enum statement.", "Line number 1."); + CHECK_LOG_CTX("Parsing module \"aa\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"one\" of enum statement.", "Line number 1."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module aa {namespace urn:aa;prefix aa; leaf l {type enumeration {" "enum '';}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Parsing module \"aa\" failed.", NULL, - "Enum name must not be zero-length.", "Line number 1."); + CHECK_LOG_CTX("Parsing module \"aa\" failed.", NULL); + CHECK_LOG_CTX("Enum name must not be zero-length.", "Line number 1."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module aa {namespace urn:aa;prefix aa; leaf l {type enumeration {" "enum ' x';}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Parsing module \"aa\" failed.", NULL, - "Enum name must not have any leading or trailing whitespaces (\" x\").", "Line number 1."); + CHECK_LOG_CTX("Parsing module \"aa\" failed.", NULL); + CHECK_LOG_CTX("Enum name must not have any leading or trailing whitespaces (\" x\").", "Line number 1."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module aa {namespace urn:aa;prefix aa; leaf l {type enumeration {" "enum 'x ';}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Parsing module \"aa\" failed.", NULL, - "Enum name must not have any leading or trailing whitespaces (\"x \").", "Line number 1."); + CHECK_LOG_CTX("Parsing module \"aa\" failed.", NULL); + CHECK_LOG_CTX("Enum name must not have any leading or trailing whitespaces (\"x \").", "Line number 1."); assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module aa {namespace urn:aa;prefix aa; leaf l {type enumeration {" "enum 'inva\nlid';}}}", LYS_IN_YANG, &mod)); CHECK_LOG_CTX("Control characters in enum name should be avoided (\"inva\nlid\", character number 5).", NULL); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module bb {namespace urn:bb;prefix bb; leaf l {type enumeration;}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Missing enum substatement for enumeration type.", "/bb:l"); + CHECK_LOG_CTX("Missing enum substatement for enumeration type.", "Path \"/bb:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module cc {yang-version 1.1;namespace urn:cc;prefix cc;typedef mytype {type enumeration {enum one;}}" "leaf l {type mytype {enum two;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid enumeration - derived type adds new item \"two\".", "/cc:l"); + CHECK_LOG_CTX("Invalid enumeration - derived type adds new item \"two\".", "Path \"/cc:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module dd {yang-version 1.1;namespace urn:dd;prefix dd;typedef mytype {type enumeration {enum one;}}" "leaf l {type mytype {enum one {value 1;}}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid enumeration - value of the item \"one\" has changed from 0 to 1 in the derived type.", "/dd:l"); + CHECK_LOG_CTX("Invalid enumeration - value of the item \"one\" has changed from 0 to 1 in the derived type.", "Path \"/dd:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ee {namespace urn:ee;prefix ee;leaf l {type enumeration {enum x {value 2147483647;}enum y;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid enumeration - it is not possible to auto-assign enum value for \"y\" since the highest value is already 2147483647.", "/ee:l"); + CHECK_LOG_CTX("Invalid enumeration - it is not possible to auto-assign enum value for \"y\" since the highest value is already 2147483647.", + "Path \"/ee:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ff {namespace urn:ff;prefix ff;leaf l {type enumeration {enum x {value 1;}enum y {value 1;}}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid enumeration - value 1 collide in items \"y\" and \"x\".", "/ff:l"); + CHECK_LOG_CTX("Invalid enumeration - value 1 collide in items \"y\" and \"x\".", "Path \"/ff:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module gg {namespace urn:gg;prefix gg;typedef mytype {type enumeration;}" "leaf l {type mytype {enum one;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Missing enum substatement for enumeration type mytype.", "/gg:l"); + CHECK_LOG_CTX("Missing enum substatement for enumeration type mytype.", "Path \"/gg:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module hh {namespace urn:hh;prefix hh; typedef mytype {type enumeration {enum one;}}" "leaf l {type mytype {enum one;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Enumeration type can be subtyped only in YANG 1.1 modules.", "/hh:l"); + CHECK_LOG_CTX("Enumeration type can be subtyped only in YANG 1.1 modules.", "Path \"/hh:l\"."); } static void @@ -1256,43 +1212,43 @@ test_type_dec64(void **state) /* invalid cases */ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module aa {namespace urn:aa;prefix aa; leaf l {type decimal64 {fraction-digits 0;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Parsing module \"aa\" failed.", NULL, - "Invalid value \"0\" of \"fraction-digits\".", "Line number 1."); + CHECK_LOG_CTX("Parsing module \"aa\" failed.", NULL); + CHECK_LOG_CTX("Invalid value \"0\" of \"fraction-digits\".", "Line number 1."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module aa {namespace urn:aa;prefix aa; leaf l {type decimal64 {fraction-digits -1;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Parsing module \"aa\" failed.", NULL, - "Invalid value \"-1\" of \"fraction-digits\".", "Line number 1."); + CHECK_LOG_CTX("Parsing module \"aa\" failed.", NULL); + CHECK_LOG_CTX("Invalid value \"-1\" of \"fraction-digits\".", "Line number 1."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module aa {namespace urn:aa;prefix aa; leaf l {type decimal64 {fraction-digits 19;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Parsing module \"aa\" failed.", NULL, - "Value \"19\" is out of \"fraction-digits\" bounds.", "Line number 1."); + CHECK_LOG_CTX("Parsing module \"aa\" failed.", NULL); + CHECK_LOG_CTX("Value \"19\" is out of \"fraction-digits\" bounds.", "Line number 1."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module aa {namespace urn:aa;prefix aa; leaf l {type decimal64;}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Missing fraction-digits substatement for decimal64 type.", "/aa:l"); + CHECK_LOG_CTX("Missing fraction-digits substatement for decimal64 type.", "Path \"/aa:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ab {namespace urn:ab;prefix ab; typedef mytype {type decimal64;}leaf l {type mytype;}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Missing fraction-digits substatement for decimal64 type mytype.", "/ab:l"); + CHECK_LOG_CTX("Missing fraction-digits substatement for decimal64 type mytype.", "Path \"/ab:l\"."); assert_int_equal(LY_EINVAL, lys_parse_mem(UTEST_LYCTX, "module bb {namespace urn:bb;prefix bb; leaf l {type decimal64 {fraction-digits 2;" "range '3.142';}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Range boundary \"3.142\" of decimal64 type exceeds defined number (2) of fraction digits.", "/bb:l"); + CHECK_LOG_CTX("Range boundary \"3.142\" of decimal64 type exceeds defined number (2) of fraction digits.", "Path \"/bb:l\"."); assert_int_equal(LY_EEXIST, lys_parse_mem(UTEST_LYCTX, "module cc {namespace urn:cc;prefix cc; leaf l {type decimal64 {fraction-digits 2;" "range '4 | 3.14';}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid range restriction - values are not in ascending order (3.14).", "/cc:l"); + CHECK_LOG_CTX("Invalid range restriction - values are not in ascending order (3.14).", "Path \"/cc:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module dd {namespace urn:dd;prefix dd; typedef mytype {type decimal64 {fraction-digits 2;}}" "leaf l {type mytype {fraction-digits 3;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid fraction-digits substatement for type not directly derived from decimal64 built-in type.", "/dd:l"); + CHECK_LOG_CTX("Invalid fraction-digits substatement for type not directly derived from decimal64 built-in type.", "Path \"/dd:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module de {namespace urn:de;prefix de; typedef mytype {type decimal64 {fraction-digits 2;}}" "typedef mytype2 {type mytype {fraction-digits 3;}}leaf l {type mytype2;}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid fraction-digits substatement for type \"mytype2\" not directly derived from decimal64 built-in type.", "/de:l"); + CHECK_LOG_CTX("Invalid fraction-digits substatement for type \"mytype2\" not directly derived from decimal64 built-in type.", "Path \"/de:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ee {namespace urn:ee;prefix ee;typedef mytype {type decimal64 {" "fraction-digits 18;range '-10 .. 0';}}leaf l {type mytype;}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid range restriction - invalid value \"-10000000000000000000\".", "/ee:l"); + CHECK_LOG_CTX("Invalid range restriction - invalid value \"-10000000000000000000\".", "Path \"/ee:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ee {namespace urn:ee;prefix ee;typedef mytype {type decimal64 {" "fraction-digits 18;range '0 .. 10';}}leaf l {type mytype;}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid range restriction - invalid value \"10000000000000000000\".", "/ee:l"); + CHECK_LOG_CTX("Invalid range restriction - invalid value \"10000000000000000000\".", "Path \"/ee:l\"."); } static void @@ -1321,11 +1277,11 @@ test_type_instanceid(void **state) /* invalid cases */ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module aa {namespace urn:aa;prefix aa; leaf l {type instance-identifier {require-instance yes;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Parsing module \"aa\" failed.", NULL, - "Invalid value \"yes\" of \"require-instance\".", "Line number 1."); + CHECK_LOG_CTX("Parsing module \"aa\" failed.", NULL); + CHECK_LOG_CTX("Invalid value \"yes\" of \"require-instance\".", "Line number 1."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module aa {namespace urn:aa;prefix aa; leaf l {type instance-identifier {fraction-digits 1;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid type restrictions for instance-identifier type.", "/aa:l"); + CHECK_LOG_CTX("Invalid type restrictions for instance-identifier type.", "Path \"/aa:l\"."); } static ly_bool @@ -1721,29 +1677,29 @@ test_type_identityref(void **state) /* invalid cases */ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module aa {namespace urn:aa;prefix aa; leaf l {type identityref;}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Missing base substatement for identityref type.", "/aa:l"); + CHECK_LOG_CTX("Missing base substatement for identityref type.", "Path \"/aa:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module bb {namespace urn:bb;prefix bb; typedef mytype {type identityref;}" "leaf l {type mytype;}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Missing base substatement for identityref type mytype.", "/bb:l"); + CHECK_LOG_CTX("Missing base substatement for identityref type mytype.", "Path \"/bb:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module cc {namespace urn:cc;prefix cc; identity i; typedef mytype {type identityref {base i;}}" "leaf l {type mytype {base i;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid base substatement for the type not directly derived from identityref built-in type.", "/cc:l"); + CHECK_LOG_CTX("Invalid base substatement for the type not directly derived from identityref built-in type.", "Path \"/cc:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module dd {namespace urn:dd;prefix dd; identity i; typedef mytype {type identityref {base i;}}" "typedef mytype2 {type mytype {base i;}}leaf l {type mytype2;}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid base substatement for the type \"mytype2\" not directly derived from identityref built-in type.", "/dd:l"); + CHECK_LOG_CTX("Invalid base substatement for the type \"mytype2\" not directly derived from identityref built-in type.", "Path \"/dd:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ee {namespace urn:ee;prefix ee; identity i; identity j;" "leaf l {type identityref {base i;base j;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Multiple bases in identityref type are allowed only in YANG 1.1 modules.", "/ee:l"); + CHECK_LOG_CTX("Multiple bases in identityref type are allowed only in YANG 1.1 modules.", "Path \"/ee:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ff {namespace urn:ff;prefix ff; identity i;leaf l {type identityref {base j;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Unable to find base (j) of identityref.", "/ff:l"); + CHECK_LOG_CTX("Unable to find base (j) of identityref.", "Path \"/ff:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module gg {namespace urn:gg;prefix gg;leaf l {type identityref {base x:j;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid prefix used for base (x:j) of identityref.", "/gg:l"); + CHECK_LOG_CTX("Invalid prefix used for base (x:j) of identityref.", "Path \"/gg:l\"."); } static void @@ -1759,18 +1715,27 @@ test_type_leafref(void **state) path = "invalid_path"; assert_int_equal(LY_EVALID, ly_path_parse(UTEST_LYCTX, NULL, path, strlen(path), 1, LY_PATH_BEGIN_EITHER, LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &expr)); + CHECK_LOG_CTX("Unexpected XPath token \"NameTest\" (\"invalid_path\"), expected \"..\".", NULL); + path = ".."; assert_int_equal(LY_EVALID, ly_path_parse(UTEST_LYCTX, NULL, path, strlen(path), 1, LY_PATH_BEGIN_EITHER, LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &expr)); + CHECK_LOG_CTX("Unexpected XPath expression end.", NULL); + path = "..["; assert_int_equal(LY_EVALID, ly_path_parse(UTEST_LYCTX, NULL, path, strlen(path), 1, LY_PATH_BEGIN_EITHER, LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &expr)); + CHECK_LOG_CTX("Unexpected XPath token \"[\" (\"[\"), expected \"Operator(Path)\".", NULL); + path = "../"; assert_int_equal(LY_EVALID, ly_path_parse(UTEST_LYCTX, NULL, path, strlen(path), 1, LY_PATH_BEGIN_EITHER, LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &expr)); + CHECK_LOG_CTX("Unexpected XPath expression end.", NULL); + path = "/"; assert_int_equal(LY_EVALID, ly_path_parse(UTEST_LYCTX, NULL, path, strlen(path), 1, LY_PATH_BEGIN_EITHER, LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &expr)); + CHECK_LOG_CTX("Unexpected XPath expression end.", NULL); path = "../../pref:id/xxx[predicate]/invalid!!!"; assert_int_equal(LY_EVALID, ly_path_parse(UTEST_LYCTX, NULL, path, strlen(path), 1, LY_PATH_BEGIN_EITHER, @@ -1861,6 +1826,7 @@ test_type_leafref(void **state) "leaf target {if-feature 'f1'; type boolean;}}"; assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, &mod)); CHECK_LOG_CTX("Target of leafref \"ref1\" cannot be referenced because it is disabled.", "Schema location \"/e:ref1\"."); + CHECK_LOG_CTX("Not found node \"target\" in path.", "Schema location \"/e:ref1\"."); str = "module en {yang-version 1.1;namespace urn:en;prefix en;feature f1;" "leaf ref1 {if-feature 'f1'; type leafref {path /target;}}" @@ -1881,6 +1847,7 @@ test_type_leafref(void **state) "leaf ref {must \"/cl:h > 0\"; type uint16;}}", LYS_IN_YANG, &mod)); ly_ctx_unset_options(UTEST_LYCTX, LY_CTX_REF_IMPLEMENTED); CHECK_LOG_CTX("Target of leafref \"g\" cannot be referenced because it is disabled.", "Schema location \"/cl:g\"."); + CHECK_LOG_CTX("Not found node \"f\" in path.", "Schema location \"/cl:g\"."); assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module f {namespace urn:f;prefix f;" "list interface{key name;leaf name{type string;}list address {key ip;leaf ip {type string;}}}" @@ -1956,6 +1923,13 @@ test_type_leafref(void **state) assert_int_equal(LY_TYPE_BOOL, ((struct lysc_node_leaf *)mod->compiled->data)->dflt->realtype->basetype); assert_int_equal(1, ((struct lysc_node_leaf *)mod->compiled->data)->dflt->boolean); + /* union reference */ + assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module m {namespace urn:m;prefix m;" + "typedef s-ref {type union {type leafref {path '/str';}}}" + "leaf str {type string {length \"1..16\" {error-message \"Custom message\";}}}" + "leaf ref1 {type s-ref;}" + "leaf ref2 {type s-ref;}}", LYS_IN_YANG, NULL)); + /* invalid paths */ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module aa {namespace urn:aa;prefix aa;container a {leaf target2 {type uint8;}}" "leaf ref1 {type leafref {path ../a/invalid;}}}", LYS_IN_YANG, &mod)); @@ -1972,8 +1946,8 @@ test_type_leafref(void **state) CHECK_LOG_CTX("List predicate defined for container \"a\" in path.", "Schema location \"/dd:ref1\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ee {namespace urn:ee;prefix ee;\n container a {leaf target2 {type uint8;}}\n" "leaf ref1 {type leafref {path /a!invalid;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Parsing module \"ee\" failed.", NULL, - "Invalid character 0x21 ('!'), perhaps \"a\" is supposed to be a function call.", "Line number 3."); + CHECK_LOG_CTX("Parsing module \"ee\" failed.", NULL); + CHECK_LOG_CTX("Invalid character 0x21 ('!'), perhaps \"a\" is supposed to be a function call.", "Line number 3."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ff {namespace urn:ff;prefix ff;container a {leaf target2 {type uint8;}}" "leaf ref1 {type leafref {path /a;}}}", LYS_IN_YANG, &mod)); CHECK_LOG_CTX("Invalid leafref path \"/a\" - target node is container instead of leaf or leaf-list.", "Schema location \"/ff:ref1\"."); @@ -1983,36 +1957,36 @@ test_type_leafref(void **state) "Schema location \"/gg:ref1\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module hh {namespace urn:hh;prefix hh;" "leaf ref1 {type leafref;}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Missing path substatement for leafref type.", "/hh:ref1"); + CHECK_LOG_CTX("Missing path substatement for leafref type.", "Path \"/hh:ref1\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ii {namespace urn:ii;prefix ii;typedef mytype {type leafref;}" "leaf ref1 {type mytype;}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Missing path substatement for leafref type mytype.", "/ii:ref1"); + CHECK_LOG_CTX("Missing path substatement for leafref type mytype.", "Path \"/ii:ref1\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module kk {namespace urn:kk;prefix kk;" "leaf ref {type leafref {path /target;}}leaf target {type string;config false;}}", LYS_IN_YANG, &mod)); CHECK_LOG_CTX("Invalid leafref path \"/target\" - target is supposed to represent configuration data (as the leafref does), but it does not.", "Schema location \"/kk:ref\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ll {namespace urn:ll;prefix ll;" "leaf ref {type leafref {path /target; require-instance true;}}leaf target {type string;}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Leafref type can be restricted by require-instance statement only in YANG 1.1 modules.", "/ll:ref"); + CHECK_LOG_CTX("Leafref type can be restricted by require-instance statement only in YANG 1.1 modules.", "Path \"/ll:ref\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module mm {namespace urn:mm;prefix mm;typedef mytype {type leafref {path /target;require-instance false;}}" "leaf ref {type mytype;}leaf target {type string;}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Leafref type \"mytype\" can be restricted by require-instance statement only in YANG 1.1 modules.", "/mm:ref"); + CHECK_LOG_CTX("Leafref type \"mytype\" can be restricted by require-instance statement only in YANG 1.1 modules.", "Path \"/mm:ref\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module nn {namespace urn:nn;prefix nn;\n" "list interface{key name;leaf name{type string;}leaf ip {type string;}}\n" "leaf ifname{type leafref{ path \"../interface/name\";}}\n" "leaf address {type leafref{\n path \"/interface[name is current()/../ifname]/ip\";}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Parsing module \"nn\" failed.", NULL, - "Invalid character 0x69 ('i'), perhaps \"name\" is supposed to be a function call.", "Line number 5."); + CHECK_LOG_CTX("Parsing module \"nn\" failed.", NULL); + CHECK_LOG_CTX("Invalid character 0x69 ('i'), perhaps \"name\" is supposed to be a function call.", "Line number 5."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module oo {namespace urn:oo;prefix oo;\n" "list interface{key name;leaf name{type string;}leaf ip {type string;}}\n" "leaf ifname{type leafref{ path \"../interface/name\";}}\n" "leaf address {type leafref{\n path \"/interface[name=current()/../ifname/ip\";}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Parsing module \"oo\" failed.", NULL, - "Unexpected XPath expression end.", "Line number 5."); + CHECK_LOG_CTX("Parsing module \"oo\" failed.", NULL); + CHECK_LOG_CTX("Unexpected XPath expression end.", "Line number 5."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module pp {namespace urn:pp;prefix pp;" "list interface{key name;leaf name{type string;}leaf ip {type string;}}" @@ -2034,56 +2008,56 @@ test_type_leafref(void **state) "leaf ifname{type leafref{ path \"../interface/name\";}}leaf test{type string;}\n" "leaf address {type leafref{ path \"/interface[name=current() / .. / ifname][name=current()/../test]/ip\";}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Parsing module \"rr\" failed.", NULL, - "Duplicate predicate key \"name\" in path.", "Line number 4."); + CHECK_LOG_CTX("Parsing module \"rr\" failed.", NULL); + CHECK_LOG_CTX("Duplicate predicate key \"name\" in path.", "Line number 4."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ss {namespace urn:ss;prefix ss;\n" "list interface{key name;leaf name{type string;}leaf ip {type string;}}\n" "leaf ifname{type leafref{ path \"../interface/name\";}}leaf test{type string;}\n" "leaf address {type leafref{ path \"/interface[name = ../ifname]/ip\";}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Parsing module \"ss\" failed.", NULL, - "Unexpected XPath token \"..\" (\"../ifname]/ip\"), expected \"FunctionName\".", "Line number 4."); + CHECK_LOG_CTX("Parsing module \"ss\" failed.", NULL); + CHECK_LOG_CTX("Unexpected XPath token \"..\" (\"../ifname]/ip\"), expected \"FunctionName\".", "Line number 4."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module tt {namespace urn:tt;prefix tt;\n" "list interface{key name;leaf name{type string;}leaf ip {type string;}}\n" "leaf ifname{type leafref{ path \"../interface/name\";}}leaf test{type string;}\n" "leaf address {type leafref{ path \"/interface[name = current()../ifname]/ip\";}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Parsing module \"tt\" failed.", NULL, - "Unexpected XPath token \"..\" (\"../ifname]/ip\"), expected \"]\".", "Line number 4."); + CHECK_LOG_CTX("Parsing module \"tt\" failed.", NULL); + CHECK_LOG_CTX("Unexpected XPath token \"..\" (\"../ifname]/ip\"), expected \"Operator(Path)\".", "Line number 4."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module uu {namespace urn:uu;prefix uu;\n" "list interface{key name;leaf name{type string;}leaf ip {type string;}}\n" "leaf ifname{type leafref{ path \"../interface/name\";}}leaf test{type string;}\n" "leaf address {type leafref{ path \"/interface[name = current()/..ifname]/ip\";}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Parsing module \"uu\" failed.", NULL, - "Invalid character 'i'[31] of expression '/interface[name = current()/..ifname]/ip'.", "Line number 4."); + CHECK_LOG_CTX("Parsing module \"uu\" failed.", NULL); + CHECK_LOG_CTX("Invalid character 'i'[31] of expression '/interface[name = current()/..ifname]/ip'.", "Line number 4."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module vv {namespace urn:vv;prefix vv;\n" "list interface{key name;leaf name{type string;}leaf ip {type string;}}\n" "leaf ifname{type leafref{ path \"../interface/name\";}}leaf test{type string;}\n" "leaf address {type leafref{ path \"/interface[name = current()/ifname]/ip\";}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Parsing module \"vv\" failed.", NULL, - "Unexpected XPath token \"NameTest\" (\"ifname]/ip\"), expected \"..\".", "Line number 4."); + CHECK_LOG_CTX("Parsing module \"vv\" failed.", NULL); + CHECK_LOG_CTX("Unexpected XPath token \"NameTest\" (\"ifname]/ip\"), expected \"..\".", "Line number 4."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ww {namespace urn:ww;prefix ww;\n" "list interface{key name;leaf name{type string;}leaf ip {type string;}}\n" "leaf ifname{type leafref{ path \"../interface/name\";}}leaf test{type string;}\n" "leaf address {type leafref{ path \"/interface[name = current()/../]/ip\";}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Parsing module \"ww\" failed.", NULL, - "Unexpected XPath token \"]\" (\"]/ip\").", "Line number 4."); + CHECK_LOG_CTX("Parsing module \"ww\" failed.", NULL); + CHECK_LOG_CTX("Unexpected XPath token \"]\" (\"]/ip\"), expected \"NameTest\".", "Line number 4."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module xx {namespace urn:xx;prefix xx;\n" "list interface{key name;leaf name{type string;}leaf ip {type string;}}\n" "leaf ifname{type leafref{ path \"../interface/name\";}}leaf test{type string;}\n" "leaf address {type leafref{ path \"/interface[name = current()/../#node]/ip\";}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Parsing module \"xx\" failed.", NULL, - "Invalid character '#'[32] of expression '/interface[name = current()/../#node]/ip'.", "Line number 4."); + CHECK_LOG_CTX("Parsing module \"xx\" failed.", NULL); + CHECK_LOG_CTX("Invalid character '#'[32] of expression '/interface[name = current()/../#node]/ip'.", "Line number 4."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module yy {namespace urn:yy;prefix yy;\n" "list interface{key name;leaf name{type string;}leaf ip {type string;}}\n" @@ -2143,7 +2117,7 @@ test_type_empty(void **state) assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module bb {namespace urn:bb;prefix bb;typedef mytype {type empty; default x;}" "leaf l {type mytype;}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Invalid type \"mytype\" - \"empty\" type must not have a default value (x).", "/bb:l"); + CHECK_LOG_CTX("Invalid type \"mytype\" - \"empty\" type must not have a default value (x).", "Path \"/bb:l\"."); } static void @@ -2197,25 +2171,25 @@ test_type_union(void **state) /* invalid unions */ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module aa {namespace urn:aa;prefix aa;typedef mytype {type union;}" "leaf l {type mytype;}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Missing type substatement for union type mytype.", "/aa:l"); + CHECK_LOG_CTX("Missing type substatement for union type mytype.", "Path \"/aa:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module bb {namespace urn:bb;prefix bb;leaf l {type union;}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Missing type substatement for union type.", "/bb:l"); + CHECK_LOG_CTX("Missing type substatement for union type.", "Path \"/bb:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module cc {namespace urn:cc;prefix cc;typedef mytype {type union{type int8; type string;}}" "leaf l {type mytype {type string;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid type substatement for the type not directly derived from union built-in type.", "/cc:l"); + CHECK_LOG_CTX("Invalid type substatement for the type not directly derived from union built-in type.", "Path \"/cc:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module dd {namespace urn:dd;prefix dd;typedef mytype {type union{type int8; type string;}}" "typedef mytype2 {type mytype {type string;}}leaf l {type mytype2;}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid type substatement for the type \"mytype2\" not directly derived from union built-in type.", "/dd:l"); + CHECK_LOG_CTX("Invalid type substatement for the type \"mytype2\" not directly derived from union built-in type.", "Path \"/dd:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ee {namespace urn:ee;prefix ee;typedef mytype {type union{type mytype; type string;}}" "leaf l {type mytype;}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid \"mytype\" type reference - circular chain of types detected.", "/ee:l"); + CHECK_LOG_CTX("Invalid \"mytype\" type reference - circular chain of types detected.", "Path \"/ee:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ef {namespace urn:ef;prefix ef;typedef mytype {type mytype2;}" "typedef mytype2 {type mytype;} leaf l {type mytype;}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid \"mytype\" type reference - circular chain of types detected.", "/ef:l"); + CHECK_LOG_CTX("Invalid \"mytype\" type reference - circular chain of types detected.", "Path \"/ef:l\"."); } static void @@ -2304,20 +2278,173 @@ test_type_dflt(void **state) } static void +test_type_exts(void **state) +{ + const char *schema1, *schema2, *schema3, *schema4; + struct lys_module *mod; + const struct lysc_node *snode; + struct lysc_type *type; + struct lysc_type_union *type_u; + + schema1 = "module my-extensions {\n" + " namespace \"urn:my-extensions\";\n" + " prefix my-ext;\n" + "\n" + " extension shortdesc {\n" + " argument shortdsc;\n" + " }\n" + "}\n"; + schema2 = "module module-inet {\n" + " yang-version 1.1;\n" + " namespace \"urn:module-inet\";\n" + " prefix mod-inet;\n" + "\n" + " import ietf-inet-types {\n" + " prefix inet;\n" + " }\n" + "\n" + " import my-extensions {\n" + " prefix my-ext;\n" + " }\n" + "\n" + " typedef domain-name {\n" + " type inet:domain-name {\n" + " my-ext:shortdesc \"<host-name>\";\n" + " }\n" + " }\n" + "\n" + " typedef ipv4-address {\n" + " type inet:ipv4-address-no-zone {\n" + " my-ext:shortdesc \"<A.B.C.D>\";\n" + " }\n" + " }\n" + " typedef my-enum {\n" + " type enumeration {\n" + " enum one;\n" + " enum two;\n" + " enum three;\n" + " }\n" + " }\n" + "}\n"; + schema3 = "module module-a {\n" + " yang-version 1.1;\n" + " namespace \"urn:module-a\";\n" + " prefix mod-a;\n" + "\n" + " import module-inet {\n" + " prefix mod-inet;\n" + " }\n" + "\n" + " import my-extensions {\n" + " prefix my-ext;\n" + " }\n" + "\n" + " typedef server-address {\n" + " type union {\n" + " type mod-inet:ipv4-address {\n" + " my-ext:shortdesc \"<ipv4-address>\";\n" + " }\n" + " type mod-inet:domain-name {\n" + " my-ext:shortdesc \"<fqdn>\";\n" + " }\n" + " }\n" + " }\n" + "}\n"; + schema4 = "module main-module {\n" + " yang-version 1.1;\n" + " namespace \"urn:main-module\";\n" + " prefix main;\n" + "\n" + " import module-a {\n" + " prefix mod-a;\n" + " }\n" + "\n" + " import module-inet {\n" + " prefix mod-inet;\n" + " }\n" + "\n" + " import my-extensions {\n" + " prefix my-ext;\n" + " }\n" + "\n" + " container config {\n" + " leaf server {\n" + " type mod-a:server-address {\n" + " my-ext:shortdesc \"<server-address>\";\n" + " }\n" + " }\n" + "\n" + " leaf hostname {\n" + " type union {\n" + " type mod-inet:domain-name;\n" + " type string;\n" + " }\n" + " }\n" + " }\n" + "\n" + " leaf my-leaf {\n" + " type mod-inet:my-enum {\n" + " my-ext:shortdesc \"my enum\";\n" + " }\n" + " }\n" + "}\n"; + + assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, schema1, LYS_IN_YANG, NULL)); + assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, schema2, LYS_IN_YANG, NULL)); + assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, schema3, LYS_IN_YANG, NULL)); + assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, schema4, LYS_IN_YANG, &mod)); + + /* server */ + snode = lys_find_path(UTEST_LYCTX, NULL, "/main-module:config/server", 0); + assert_non_null(snode); + + type = ((struct lysc_node_leaf *)snode)->type; + assert_int_equal(LY_ARRAY_COUNT(type->exts), 1); + assert_string_equal(type->exts[0].argument, "<server-address>"); + type_u = (struct lysc_type_union *)type; + assert_int_equal(LY_ARRAY_COUNT(type_u->types), 2); + + type = type_u->types[0]; + assert_int_equal(LY_ARRAY_COUNT(type->exts), 2); + assert_string_equal(type->exts[0].argument, "<A.B.C.D>"); + assert_string_equal(type->exts[1].argument, "<ipv4-address>"); + + type = type_u->types[1]; + assert_int_equal(LY_ARRAY_COUNT(type->exts), 2); + assert_string_equal(type->exts[0].argument, "<host-name>"); + assert_string_equal(type->exts[1].argument, "<fqdn>"); + + /* hostname */ + snode = lys_find_path(UTEST_LYCTX, NULL, "/main-module:config/hostname", 0); + assert_non_null(snode); + type = ((struct lysc_node_leaf *)snode)->type; + assert_int_equal(LY_ARRAY_COUNT(type->exts), 0); + type_u = (struct lysc_type_union *)type; + assert_int_equal(LY_ARRAY_COUNT(type_u->types), 2); + + type = type_u->types[0]; + assert_int_equal(LY_ARRAY_COUNT(type->exts), 1); + assert_string_equal(type->exts[0].argument, "<host-name>"); + + type = type_u->types[1]; + assert_int_equal(LY_ARRAY_COUNT(type->exts), 0); +} + +static void test_status(void **state) { assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module aa {namespace urn:aa;prefix aa;" "container c {status deprecated; leaf l {status current; type string;}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Status \"current\" of \"l\" is in conflict with \"deprecated\" status of parent \"c\".", "/aa:c/l"); + CHECK_LOG_CTX("Status \"current\" of \"l\" is in conflict with \"deprecated\" status of parent \"c\".", "Path \"/aa:c/l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module bb {namespace urn:bb;prefix bb;" "container c {status obsolete; leaf l {status current; type string;}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Status \"current\" of \"l\" is in conflict with \"obsolete\" status of parent \"c\".", "/bb:c/l"); + CHECK_LOG_CTX("Status \"current\" of \"l\" is in conflict with \"obsolete\" status of parent \"c\".", "Path \"/bb:c/l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module cc {namespace urn:cc;prefix cc;" "container c {status obsolete; leaf l {status deprecated; type string;}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Status \"deprecated\" of \"l\" is in conflict with \"obsolete\" status of parent \"c\".", "/cc:c/l"); + CHECK_LOG_CTX("Status \"deprecated\" of \"l\" is in conflict with \"obsolete\" status of parent \"c\".", "Path \"/cc:c/l\"."); /* just a warning */ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module cc {namespace urn:dd;prefix d;" @@ -2344,11 +2471,12 @@ test_grouping(void **state) /* invalid - error in a non-instantiated grouping */ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module aa {namespace urn:aa;prefix aa;" "grouping grp {leaf x {type leafref;}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Missing path substatement for leafref type.", "/aa:{grouping='grp'}/x"); - UTEST_LOG_CLEAN; + CHECK_LOG_CTX("Missing path substatement for leafref type.", "Path \"/aa:{grouping='grp'}/x\"."); + assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module aa {namespace urn:aa;prefix aa;" "container a {grouping grp {leaf x {type leafref;}}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Missing path substatement for leafref type.", "/aa:a/{grouping='grp'}/x"); + CHECK_LOG_CTX("Missing path substatement for leafref type.", "Path \"/aa:a/{grouping='grp'}/x\"."); + CHECK_LOG_CTX("Locally scoped grouping \"grp\" not used.", NULL); /* config check */ ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, "module z1 {namespace urn:z1;prefix z1;" @@ -2519,52 +2647,53 @@ test_uses(void **state) /* invalid */ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module aa {namespace urn:aa;prefix aa;uses missinggrp;}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Grouping \"missinggrp\" referenced by a uses statement not found.", "/aa:{uses='missinggrp'}"); + CHECK_LOG_CTX("Grouping \"missinggrp\" referenced by a uses statement not found.", "Path \"/aa:{uses='missinggrp'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module bb {namespace urn:bb;prefix bb;uses grp;" "grouping grp {leaf a{type string;}uses grp1;}" "grouping grp1 {leaf b {type string;}uses grp2;}" "grouping grp2 {leaf c {type string;}uses grp;}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Grouping \"grp\" references itself through a uses statement.", "/bb:{uses='grp'}/{uses='grp1'}/{uses='grp2'}/{uses='grp'}"); + CHECK_LOG_CTX("Grouping \"grp\" references itself through a uses statement.", "Path \"/bb:{uses='grp'}/{uses='grp1'}/{uses='grp2'}/{uses='grp'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module cc {namespace urn:cc;prefix cc;uses a:missingprefix;}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid prefix used for grouping \"a:missingprefix\" reference.", "/cc:{uses='a:missingprefix'}"); + CHECK_LOG_CTX("Invalid prefix used for grouping \"a:missingprefix\" reference.", "Path \"/cc:{uses='a:missingprefix'}\"."); assert_int_equal(LY_EEXIST, lys_parse_mem(UTEST_LYCTX, "module dd {namespace urn:dd;prefix dd;grouping grp{leaf a{type string;}}" "leaf a {type string;}uses grp;}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Duplicate identifier \"a\" of data definition/RPC/action/notification statement.", "/dd:{uses='grp'}/dd:a"); + CHECK_LOG_CTX("Duplicate identifier \"a\" of data definition/RPC/action/notification statement.", "Path \"/dd:{uses='grp'}/dd:a\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ee {namespace urn:ee;prefix ee;grouping grp {leaf l {type string; status deprecated;}}" "uses grp {status obsolete;}}", LYS_IN_YANG, &mod)); CHECK_LOG_CTX("Inherited schema-only status \"obsolete\" is in conflict with \"deprecated\" status of \"l\".", - "/ee:{uses='grp'}/ee:l"); + "Path \"/ee:{uses='grp'}/ee:l\"."); assert_int_equal(LY_EEXIST, lys_parse_mem(UTEST_LYCTX, "module ff {namespace urn:ff;prefix ff;grouping grp {leaf l {type string;}}" "leaf l {type int8;}uses grp;}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Duplicate identifier \"l\" of data definition/RPC/action/notification statement.", "/ff:{uses='grp'}/ff:l"); + CHECK_LOG_CTX("Duplicate identifier \"l\" of data definition/RPC/action/notification statement.", "Path \"/ff:{uses='grp'}/ff:l\"."); assert_int_equal(LY_EEXIST, lys_parse_mem(UTEST_LYCTX, "module fg {namespace urn:fg;prefix fg;grouping grp {leaf m {type string;}}" "uses grp;leaf m {type int8;}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Duplicate identifier \"m\" of data definition/RPC/action/notification statement.", "/fg:m"); + CHECK_LOG_CTX("Duplicate identifier \"m\" of data definition/RPC/action/notification statement.", "Path \"/fg:m\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module gg {namespace urn:gg;prefix gg; grouping grp {container g;}" "leaf g {type string;}" "container top {uses grp {augment /g {leaf x {type int8;}}}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid descendant-schema-nodeid value \"/g\" - name test expected instead of \"/\".", "/gg:top/{uses='grp'}/{augment='/g'}"); + CHECK_LOG_CTX("Invalid descendant-schema-nodeid value \"/g\" - name test expected instead of \"/\".", + "Path \"/gg:top/{uses='grp'}/{augment='/g'}\"."); assert_int_equal(LY_ENOTFOUND, lys_parse_mem(UTEST_LYCTX, "module hh {yang-version 1.1;namespace urn:hh;prefix hh;" "grouping grp {notification g { description \"super g\";}}" "container top {notification h; uses grp {refine h {description \"ultra h\";}}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Refine(s) target node \"h\" in grouping \"grp\" was not found.", "/hh:top/{uses='grp'}"); + CHECK_LOG_CTX("Refine(s) target node \"h\" in grouping \"grp\" was not found.", "Path \"/hh:top/{uses='grp'}\"."); assert_int_equal(LY_ENOTFOUND, lys_parse_mem(UTEST_LYCTX, "module ii {yang-version 1.1;namespace urn:ii;prefix ii;" "grouping grp {action g { description \"super g\";}}" "container top {action i; uses grp {refine i {description \"ultra i\";}}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Refine(s) target node \"i\" in grouping \"grp\" was not found.", "/ii:top/{uses='grp'}"); + CHECK_LOG_CTX("Refine(s) target node \"i\" in grouping \"grp\" was not found.", "Path \"/ii:top/{uses='grp'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module jj {yang-version 1.1;namespace urn:jj;prefix jj;" "grouping grp {leaf j { when \"1\"; type invalid;}}" "container top {uses grp;}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Referenced type \"invalid\" not found.", "/jj:top/{uses='grp'}/j"); + CHECK_LOG_CTX("Referenced type \"invalid\" not found.", "Path \"/jj:top/{uses='grp'}/j\"."); } static void @@ -2666,65 +2795,71 @@ test_refine(void **state) /* invalid */ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module aa {namespace urn:aa;prefix aa;import grp {prefix g;}" "uses g:grp {refine c {default hello;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid refine of container node - it is not possible to replace \"default\" property.", "/aa:{uses='g:grp'}/aa:c/{refine='c'}"); + CHECK_LOG_CTX("Invalid refine of container node - it is not possible to replace \"default\" property.", + "Path \"/aa:{uses='g:grp'}/aa:c/{refine='c'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module bb {namespace urn:bb;prefix bb;import grp {prefix g;}" "uses g:grp {refine c/l {default hello; default world;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid refine of leaf with too many (2) default properties.", "/bb:{uses='g:grp'}/bb:c/l/{refine='c/l'}"); + CHECK_LOG_CTX("Invalid refine of leaf with too many (2) default properties.", "Path \"/bb:{uses='g:grp'}/bb:c/l/{refine='c/l'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module cc {namespace urn:cc;prefix cc;import grp {prefix g;}" "uses g:grp {refine c/ll {default hello; default world;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid refine of default in leaf-list - the default statement is allowed only in YANG 1.1 modules.", "/cc:{uses='g:grp'}/cc:c/ll/{refine='c/ll'}"); + CHECK_LOG_CTX("Invalid refine of default in leaf-list - the default statement is allowed only in YANG 1.1 modules.", + "Path \"/cc:{uses='g:grp'}/cc:c/ll/{refine='c/ll'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module dd {namespace urn:dd;prefix dd;import grp {prefix g;}" "uses g:grp {refine c/ll {mandatory true;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid refine of leaf-list node - it is not possible to replace \"mandatory\" property.", "/dd:{uses='g:grp'}/dd:c/ll/{refine='c/ll'}"); + CHECK_LOG_CTX("Invalid refine of leaf-list node - it is not possible to replace \"mandatory\" property.", + "Path \"/dd:{uses='g:grp'}/dd:c/ll/{refine='c/ll'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ee {namespace urn:ee;prefix ee;import grp {prefix g;}" "uses g:grp {refine c/l {mandatory true;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "/ee:{uses='g:grp'}/ee:c/l", - "Invalid mandatory leaf with a default value.", "/ee:{uses='g:grp'}/ee:c/l"); + CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "Path \"/ee:{uses='g:grp'}/ee:c/l\"."); + CHECK_LOG_CTX("Invalid mandatory leaf with a default value.", "Path \"/ee:{uses='g:grp'}/ee:c/l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ef {namespace urn:ef;prefix ef;import grp {prefix g;}" "uses g:grp {refine c/ch {mandatory true;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "/ef:{uses='g:grp'}/ef:c/ch", - "Invalid mandatory choice with a default case.", "/ef:{uses='g:grp'}/ef:c/ch"); + CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "Path \"/ef:{uses='g:grp'}/ef:c/ch\"."); + CHECK_LOG_CTX("Invalid mandatory choice with a default case.", "Path \"/ef:{uses='g:grp'}/ef:c/ch\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ff {namespace urn:ff;prefix ff;import grp {prefix g;}" "uses g:grp {refine c/ch/ca/ca {mandatory true;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Mandatory node \"ca\" under the default case \"ca\".", "/ff:{uses='g:grp'}/ff:c/ch"); + CHECK_LOG_CTX("Mandatory node \"ca\" under the default case \"ca\".", "Path \"/ff:{uses='g:grp'}/ff:c/ch\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module gg {namespace urn:gg;prefix gg;import grp {prefix g;}" "uses g:grp {refine c/x {default hello;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "/gg:{uses='g:grp'}/gg:c/x", - "Invalid mandatory leaf with a default value.", "/gg:{uses='g:grp'}/gg:c/x"); + CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "Path \"/gg:{uses='g:grp'}/gg:c/x\"."); + CHECK_LOG_CTX("Invalid mandatory leaf with a default value.", "Path \"/gg:{uses='g:grp'}/gg:c/x\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module hh {namespace urn:hh;prefix hh;import grp {prefix g;}" "uses g:grp {refine c/c/l {config true;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "/hh:{uses='g:grp'}/hh:c/c/l", - "Configuration node cannot be child of any state data node.", "/hh:{uses='g:grp'}/hh:c/c/l"); + CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "Path \"/hh:{uses='g:grp'}/hh:c/c/l\"."); + CHECK_LOG_CTX("Configuration node cannot be child of any state data node.", "Path \"/hh:{uses='g:grp'}/hh:c/c/l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ii {namespace urn:ii;prefix ii;grouping grp {leaf l {type string; status deprecated;}}" "uses grp {status obsolete;}}", LYS_IN_YANG, &mod)); CHECK_LOG_CTX("Inherited schema-only status \"obsolete\" is in conflict with \"deprecated\" status of \"l\".", - "/ii:{uses='grp'}/ii:l"); + "Path \"/ii:{uses='grp'}/ii:l\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module jj {namespace urn:jj;prefix jj;import grp {prefix g;}" "uses g:grp {refine c/x {presence nonsence;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid refine of leaf node - it is not possible to replace \"presence\" property.", "/jj:{uses='g:grp'}/jj:c/x/{refine='c/x'}"); + CHECK_LOG_CTX("Invalid refine of leaf node - it is not possible to replace \"presence\" property.", + "Path \"/jj:{uses='g:grp'}/jj:c/x/{refine='c/x'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module kk {namespace urn:kk;prefix kk;import grp {prefix g;}" "uses g:grp {refine c/ch {must 1;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid refine of choice node - it is not possible to add \"must\" property.", "/kk:{uses='g:grp'}/kk:c/ch/{refine='c/ch'}"); + CHECK_LOG_CTX("Invalid refine of choice node - it is not possible to add \"must\" property.", + "Path \"/kk:{uses='g:grp'}/kk:c/ch/{refine='c/ch'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ll {namespace urn:ll;prefix ll;import grp {prefix g;}" "uses g:grp {refine c/x {min-elements 1;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid refine of leaf node - it is not possible to replace \"min-elements\" property.", "/ll:{uses='g:grp'}/ll:c/x/{refine='c/x'}"); + CHECK_LOG_CTX("Invalid refine of leaf node - it is not possible to replace \"min-elements\" property.", + "Path \"/ll:{uses='g:grp'}/ll:c/x/{refine='c/x'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module mm {namespace urn:mm;prefix mm;import grp {prefix g;}" "uses g:grp {refine c/ll {min-elements 1;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "/mm:{uses='g:grp'}/mm:c/ll", - "The default statement is present on leaf-list with a nonzero min-elements.", "/mm:{uses='g:grp'}/mm:c/ll"); + CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "Path \"/mm:{uses='g:grp'}/mm:c/ll\"."); + CHECK_LOG_CTX("The default statement is present on leaf-list with a nonzero min-elements.", "Path \"/mm:{uses='g:grp'}/mm:c/ll\"."); } static void @@ -2867,40 +3002,41 @@ test_augment(void **state) assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module aa {namespace urn:aa;prefix aa; container c {leaf a {type string;}}" "augment /x/ {leaf a {type int8;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid absolute-schema-nodeid value \"/x/\" - unexpected end of expression.", "/aa:{augment='/x/'}"); + CHECK_LOG_CTX("Invalid absolute-schema-nodeid value \"/x/\" - unexpected end of expression.", "Path \"/aa:{augment='/x/'}\"."); assert_int_equal(LY_ENOTFOUND, lys_parse_mem(UTEST_LYCTX, "module aa {namespace urn:aa;prefix aa; container c {leaf a {type string;}}" "augment /x {leaf a {type int8;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Augment target node \"/x\" from module \"aa\" was not found.", "/aa:{augment='/x'}"); + CHECK_LOG_CTX("Augment target node \"/x\" from module \"aa\" was not found.", "Path \"/aa:{augment='/x'}\"."); assert_int_equal(LY_EEXIST, lys_parse_mem(UTEST_LYCTX, "module bb {namespace urn:bb;prefix bb; container c {leaf a {type string;}}" "augment /c {leaf a {type int8;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Duplicate identifier \"a\" of data definition/RPC/action/notification statement.", "/bb:{augment='/c'}/a"); + CHECK_LOG_CTX("Duplicate identifier \"a\" of data definition/RPC/action/notification statement.", "Path \"/bb:{augment='/c'}/a\"."); assert_int_equal(LY_ENOTFOUND, lys_parse_mem(UTEST_LYCTX, "module cc {namespace urn:cc;prefix cc; container c {leaf a {type string;}}" "augment /c/a {leaf a {type int8;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Augment target node \"/c/a\" from module \"cc\" was not found.", "/cc:{augment='/c/a'}"); + CHECK_LOG_CTX("Augment target node \"/c/a\" from module \"cc\" was not found.", "Path \"/cc:{augment='/c/a'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module dd {namespace urn:dd;prefix dd; container c {leaf a {type string;}}" "augment /c {case b {leaf d {type int8;}}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid augment of container node which is not allowed to contain case node \"b\".", "/dd:{augment='/c'}"); + CHECK_LOG_CTX("Invalid augment of container node which is not allowed to contain case node \"b\".", "Path \"/dd:{augment='/c'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ee {namespace urn:ee;prefix ee; import himp {prefix hi;}" "augment /hi:top {container c {leaf d {mandatory true; type int8;}}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid augment adding mandatory node \"c\" without making it conditional via when statement.", "/ee:{augment='/hi:top'}"); + CHECK_LOG_CTX("Invalid augment adding mandatory node \"c\" without making it conditional via when statement.", "Path \"/ee:{augment='/hi:top'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ff {namespace urn:ff;prefix ff; container top;" "augment ../top {leaf x {type int8;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid absolute-schema-nodeid value \"../top\" - \"/\" expected instead of \"..\".", "/ff:{augment='../top'}"); + CHECK_LOG_CTX("Invalid absolute-schema-nodeid value \"../top\" - \"/\" expected instead of \"..\".", "Path \"/ff:{augment='../top'}\"."); assert_int_equal(LY_ENOTFOUND, lys_parse_mem(UTEST_LYCTX, "module gg {namespace urn:gg;prefix gg; rpc func;" "augment /func {leaf x {type int8;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Augment target node \"/func\" from module \"gg\" was not found.", "/gg:{augment='/func'}"); + CHECK_LOG_CTX("Augment target node \"/func\" from module \"gg\" was not found.", "Path \"/gg:{augment='/func'}\"."); assert_int_equal(LY_ENOTFOUND, lys_parse_mem(UTEST_LYCTX, "module hh {namespace urn:hh;prefix hh;import himp {prefix hi;}" "augment /hi:func/input {leaf x {type string;}}" "augment /hi:func/output {leaf y {type string;}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Augment target node \"/hi:func/input\" from module \"hh\" was not found.", "/hh:{augment='/hi:func/input'}"); + CHECK_LOG_CTX("Augment target node \"/hi:func/input\" from module \"hh\" was not found.", "Path \"/hh:{augment='/hi:func/input'}\"."); + CHECK_LOG_CTX("Augment target node \"/hi:func/output\" from module \"hh\" was not found.", "Path \"/hh:{augment='/hi:func/output'}\"."); } static void @@ -3104,18 +3240,18 @@ test_deviation(void **state) assert_true(node->flags & LYS_CONFIG_R); assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module l {namespace urn:l;prefix l; leaf a {config false; type string;}" - "container top {config false; leaf x {type string;}}" + "container top {leaf x {type string;}}" "deviation /a {deviate replace {config true;}}" - "deviation /top {deviate replace {config true;}}}", LYS_IN_YANG, &mod)); + "deviation /top {deviate replace {config false;}}}", LYS_IN_YANG, &mod)); assert_non_null(node = mod->compiled->data); assert_string_equal("a", node->name); assert_true(node->flags & LYS_CONFIG_W); assert_non_null(node = node->next); assert_string_equal("top", node->name); - assert_true(node->flags & LYS_CONFIG_W); + assert_true(node->flags & LYS_CONFIG_R); assert_non_null(node = lysc_node_child(node)); assert_string_equal("x", node->name); - assert_true(node->flags & LYS_CONFIG_W); + assert_true(node->flags & LYS_CONFIG_R); assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, "module m {namespace urn:m;prefix m;" "container a {leaf a {type string;}}" @@ -3356,194 +3492,199 @@ test_deviation(void **state) assert_int_equal(LY_ENOTFOUND, lys_parse_mem(UTEST_LYCTX, "module aa1 {namespace urn:aa1;prefix aa1;import a {prefix a;}" "deviation /a:top/a:z {deviate not-supported;}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Deviation(s) target node \"/a:top/a:z\" from module \"aa1\" was not found.", "/a:{deviation='/a:top/a:z'}"); + CHECK_LOG_CTX("Deviation(s) target node \"/a:top/a:z\" from module \"aa1\" was not found.", "Path \"/a:{deviation='/a:top/a:z'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module aa2 {namespace urn:aa2;prefix aa2;import a {prefix a;}" "deviation /a:top/a:a {deviate not-supported;}" "deviation /a:top/a:a {deviate add {default error;}}}", LYS_IN_YANG, NULL)); - CHECK_LOG_CTX("Multiple deviations of \"/a:top/a:a\" with one of them being \"not-supported\".", "/aa2:{deviation='/a:top/a:a'}"); + CHECK_LOG_CTX("Multiple deviations of \"/a:top/a:a\" with one of them being \"not-supported\".", "Path \"/aa2:{deviation='/a:top/a:a'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module bb {namespace urn:bb;prefix bb;import a {prefix a;}" "deviation a:top/a:a {deviate not-supported;}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid absolute-schema-nodeid value \"a:top/a:a\" - \"/\" expected instead of \"a:top\".", "/bb:{deviation='a:top/a:a'}"); + CHECK_LOG_CTX("Invalid absolute-schema-nodeid value \"a:top/a:a\" - \"/\" expected instead of \"a:top\".", "Path \"/bb:{deviation='a:top/a:a'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module cc {namespace urn:cc;prefix cc; container c;" "deviation /c {deviate add {units meters;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation of container node - it is not possible to add \"units\" property.", "/cc:{deviation='/c'}"); + CHECK_LOG_CTX("Invalid deviation of container node - it is not possible to add \"units\" property.", "Path \"/cc:{deviation='/c'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module cd {namespace urn:cd;prefix cd; leaf c {type string; units centimeters;}" "deviation /c {deviate add {units meters;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation adding \"units\" property which already exists (with value \"centimeters\").", "/cd:{deviation='/c'}"); + CHECK_LOG_CTX("Invalid deviation adding \"units\" property which already exists (with value \"centimeters\").", "Path \"/cd:{deviation='/c'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module dd1 {namespace urn:dd1;prefix dd1; container c;" "deviation /c {deviate delete {units meters;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation of container node - it is not possible to delete \"units\" property.", "/dd1:{deviation='/c'}"); + CHECK_LOG_CTX("Invalid deviation of container node - it is not possible to delete \"units\" property.", "Path \"/dd1:{deviation='/c'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module dd2 {namespace urn:dd2;prefix dd2; leaf c {type string;}" "deviation /c {deviate delete {units meters;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation deleting \"units\" property \"meters\" which is not present.", "/dd2:{deviation='/c'}"); + CHECK_LOG_CTX("Invalid deviation deleting \"units\" property \"meters\" which is not present.", "Path \"/dd2:{deviation='/c'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module dd3 {namespace urn:dd3;prefix dd3; leaf c {type string; units centimeters;}" "deviation /c {deviate delete {units meters;}}}", LYS_IN_YANG, &mod)); CHECK_LOG_CTX("Invalid deviation deleting \"units\" property \"meters\" which does not match the target's property value \"centimeters\".", - "/dd3:{deviation='/c'}"); + "Path \"/dd3:{deviation='/c'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ee1 {namespace urn:ee1;prefix ee1; container c;" "deviation /c {deviate replace {units meters;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation of container node - it is not possible to replace \"units\" property.", "/ee1:{deviation='/c'}"); + CHECK_LOG_CTX("Invalid deviation of container node - it is not possible to replace \"units\" property.", "Path \"/ee1:{deviation='/c'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ee2 {namespace urn:ee2;prefix ee2; leaf c {type string;}" "deviation /c {deviate replace {units meters;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation replacing \"units\" property \"meters\" which is not present.", "/ee2:{deviation='/c'}"); + CHECK_LOG_CTX("Invalid deviation replacing \"units\" property \"meters\" which is not present.", "Path \"/ee2:{deviation='/c'}\"."); /* the default is already deleted in /e:a byt module f */ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ff1 {namespace urn:ff1;prefix ff1; import e {prefix e;}" "deviation /e:a {deviate delete {default x:aa;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation deleting \"default\" property \"x:aa\" which is not present.", "/ff1:{deviation='/e:a'}"); + CHECK_LOG_CTX("Invalid deviation deleting \"default\" property \"x:aa\" which is not present.", "Path \"/ff1:{deviation='/e:a'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ff3 {namespace urn:ff3;prefix ff3; import e {prefix e;}" "deviation /e:b {deviate delete {default e:b;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation deleting \"default\" property \"e:b\" which does not match the target's property value \"x:ba\".", "/ff3:{deviation='/e:b'}"); + CHECK_LOG_CTX("Invalid deviation deleting \"default\" property \"e:b\" which does not match the target's property value \"x:ba\".", + "Path \"/ff3:{deviation='/e:b'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ff5 {namespace urn:ff5;prefix ff5; anyxml a;" "deviation /a {deviate delete {default x;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation of anyxml node - it is not possible to delete \"default\" property.", "/ff5:{deviation='/a'}"); + CHECK_LOG_CTX("Invalid deviation of anyxml node - it is not possible to delete \"default\" property.", "Path \"/ff5:{deviation='/a'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ff6 {namespace urn:ff6;prefix ff6; import e {prefix e;}" "deviation /e:c {deviate delete {default hi;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation deleting \"default\" property \"hi\" which does not match the target's property value \"hello\".", "/ff6:{deviation='/e:c'}"); + CHECK_LOG_CTX("Invalid deviation deleting \"default\" property \"hi\" which does not match the target's property value \"hello\".", + "Path \"/ff6:{deviation='/e:c'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ff7 {namespace urn:ff7;prefix ff7; import e {prefix e;}" "deviation /e:d {deviate delete {default hi;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation deleting \"default\" property \"hi\" which does not match any of the target's property values.", "/ff7:{deviation='/e:d'}"); + CHECK_LOG_CTX("Invalid deviation deleting \"default\" property \"hi\" which does not match any of the target's property values.", + "Path \"/ff7:{deviation='/e:d'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module gg1 {namespace urn:gg1;prefix gg1; import e {prefix e;}" "deviation /e:b {deviate add {default e:a;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation adding \"default\" property which already exists (with value \"x:ba\").", "/gg1:{deviation='/e:b'}"); + CHECK_LOG_CTX("Invalid deviation adding \"default\" property which already exists (with value \"x:ba\").", "Path \"/gg1:{deviation='/e:b'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module gg2 {namespace urn:gg2;prefix gg2; import e {prefix e;}" "deviation /e:a {deviate add {default x:a;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "/e:a", - "Default case prefix \"x\" not found in imports of \"gg2\".", "/e:a"); + CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "Path \"/e:a\"."); + CHECK_LOG_CTX("Default case prefix \"x\" not found in imports of \"gg2\".", "Path \"/e:a\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module gg3 {namespace urn:gg3;prefix gg3; import e {prefix e;}" "deviation /e:a {deviate add {default a;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "/e:a", - "Default case \"a\" not found.", "/e:a"); + CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "Path \"/e:a\"."); + CHECK_LOG_CTX("Default case \"a\" not found.", "Path \"/e:a\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module gg4 {namespace urn:gg4;prefix gg4; import e {prefix e;}" "deviation /e:c {deviate add {default hi;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation adding \"default\" property which already exists (with value \"hello\").", "/gg4:{deviation='/e:c'}"); + CHECK_LOG_CTX("Invalid deviation adding \"default\" property which already exists (with value \"hello\").", "Path \"/gg4:{deviation='/e:c'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module gg4 {namespace urn:gg4;prefix gg4; import e {prefix e;}" "deviation /e:a {deviate add {default e:ac;}}}", LYS_IN_YANG, &mod)); - /*CHECK_LOG_CTX("Invalid deviation adding \"default\" property \"e:ac\" of choice - mandatory node \"ac\" under the default case.", "/gg4:{deviation='/e:a'}");*/ - CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "/e:a"); + CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "Path \"/e:a\"."); + CHECK_LOG_CTX("Mandatory node \"ac\" under the default case \"e:ac\".", "Path \"/e:a\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module gg5 {namespace urn:gg5;prefix gg5; leaf x {type string; mandatory true;}" "deviation /x {deviate add {default error;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "/gg5:{deviation='/x'}", - "Invalid mandatory leaf with a default value.", "/gg5:{deviation='/x'}"); + CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "Path \"/gg5:{deviation='/x'}\"."); + CHECK_LOG_CTX("Invalid mandatory leaf with a default value.", "Path \"/gg5:{deviation='/x'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module hh1 {yang-version 1.1; namespace urn:hh1;prefix hh1; import e {prefix e;}" "deviation /e:d {deviate replace {default hi;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation of leaf-list node - it is not possible to replace \"default\" property.", "/hh1:{deviation='/e:d'}"); + CHECK_LOG_CTX("Invalid deviation of leaf-list node - it is not possible to replace \"default\" property.", + "Path \"/hh1:{deviation='/e:d'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ii1 {namespace urn:ii1;prefix ii1; import i {prefix i;}" "deviation /i:l1 {deviate delete {unique x;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation deleting \"unique\" property \"x\" which does not match any of the target's property values.", "/ii1:{deviation='/i:l1'}"); + CHECK_LOG_CTX("Invalid deviation deleting \"unique\" property \"x\" which does not match any of the target's property values.", + "Path \"/ii1:{deviation='/i:l1'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ii2 {namespace urn:ii2;prefix ii2; import i {prefix i;} leaf x { type string;}" "deviation /i:l2 {deviate delete {unique d;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation deleting \"unique\" property \"d\" which does not match any of the target's property values.", "/ii2:{deviation='/i:l2'}"); + CHECK_LOG_CTX("Invalid deviation deleting \"unique\" property \"d\" which does not match any of the target's property values.", + "Path \"/ii2:{deviation='/i:l2'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ii3 {namespace urn:ii3;prefix ii3; leaf x { type string;}" "deviation /x {deviate delete {unique d;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation of leaf node - it is not possible to delete \"unique\" property.", "/ii3:{deviation='/x'}"); + CHECK_LOG_CTX("Invalid deviation of leaf node - it is not possible to delete \"unique\" property.", "Path \"/ii3:{deviation='/x'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ii4 {namespace urn:ii4;prefix ii4; leaf x { type string;}" "deviation /x {deviate add {unique d;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation of leaf node - it is not possible to add \"unique\" property.", "/ii4:{deviation='/x'}"); + CHECK_LOG_CTX("Invalid deviation of leaf node - it is not possible to add \"unique\" property.", "Path \"/ii4:{deviation='/x'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module jj1 {namespace urn:jj1;prefix jj1; choice ch {case a {leaf a{type string;}}}" "deviation /ch/a {deviate add {config false;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation of case node - it is not possible to add \"config\" property.", "/jj1:{deviation='/ch/a'}"); + CHECK_LOG_CTX("Invalid deviation of case node - it is not possible to add \"config\" property.", "Path \"/jj1:{deviation='/ch/a'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module jj2 {namespace urn:jj2;prefix jj2; container top {config false; leaf x {type string;}}" "deviation /top/x {deviate add {config true;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "/jj2:{deviation='/top/x'}", - "Configuration node cannot be child of any state data node.", "/jj2:{deviation='/top/x'}"); - assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module jj3 {namespace urn:jj3;prefix jj3; container top {leaf x {type string;}}" - "deviation /top/x {deviate replace {config false;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation replacing \"config\" property \"config false\" which is not present.", "/jj3:{deviation='/top/x'}"); + CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "Path \"/jj2:{deviation='/top/x'}\"."); + CHECK_LOG_CTX("Configuration node cannot be child of any state data node.", "Path \"/jj2:{deviation='/top/x'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module jj4 {namespace urn:jj4;prefix jj4; choice ch {case a {leaf a{type string;}}}" "deviation /ch/a {deviate replace {config false;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation of case node - it is not possible to replace \"config\" property.", "/jj4:{deviation='/ch/a'}"); + CHECK_LOG_CTX("Invalid deviation of case node - it is not possible to replace \"config\" property.", "Path \"/jj4:{deviation='/ch/a'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module jj5 {namespace urn:jj5;prefix jj5; container top {leaf x {type string; config true;}}" "deviation /top {deviate add {config false;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "/jj5:top", - "Configuration node cannot be child of any state data node.", "/jj5:top/x"); + CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "Path \"/jj5:top\"."); + CHECK_LOG_CTX("Configuration node cannot be child of any state data node.", "Path \"/jj5:top/x\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module jj6 {namespace urn:jj6;prefix jj6; leaf x {config false; type string;}" "deviation /x {deviate add {config true;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation adding \"config\" property which already exists (with value \"config false\").", "/jj6:{deviation='/x'}"); + CHECK_LOG_CTX("Invalid deviation adding \"config\" property which already exists (with value \"config false\").", + "Path \"/jj6:{deviation='/x'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module kk1 {namespace urn:kk1;prefix kk1; container top {leaf a{type string;}}" "deviation /top {deviate add {mandatory true;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation of container node - it is not possible to add \"mandatory\" property.", "/kk1:{deviation='/top'}"); + CHECK_LOG_CTX("Invalid deviation of container node - it is not possible to add \"mandatory\" property.", "Path \"/kk1:{deviation='/top'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module kk2 {namespace urn:kk2;prefix kk2; container top {leaf a{type string;}}" "deviation /top {deviate replace {mandatory true;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation of container node - it is not possible to replace \"mandatory\" property.", "/kk2:{deviation='/top'}"); + CHECK_LOG_CTX("Invalid deviation of container node - it is not possible to replace \"mandatory\" property.", "Path \"/kk2:{deviation='/top'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module kk3 {namespace urn:kk3;prefix kk3; container top {leaf x {type string;}}" "deviation /top/x {deviate replace {mandatory true;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation replacing \"mandatory\" property \"mandatory true\" which is not present.", "/kk3:{deviation='/top/x'}"); + CHECK_LOG_CTX("Invalid deviation replacing \"mandatory\" property \"mandatory true\" which is not present.", "Path \"/kk3:{deviation='/top/x'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module kk4 {namespace urn:kk4;prefix kk4; leaf x {mandatory true; type string;}" "deviation /x {deviate add {mandatory false;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation adding \"mandatory\" property which already exists (with value \"mandatory true\").", "/kk4:{deviation='/x'}"); + CHECK_LOG_CTX("Invalid deviation adding \"mandatory\" property which already exists (with value \"mandatory true\").", + "Path \"/kk4:{deviation='/x'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ll1 {namespace urn:ll1;prefix ll1; leaf x {default test; type string;}" "deviation /x {deviate add {mandatory true;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "/ll1:{deviation='/x'}", - "Invalid mandatory leaf with a default value.", "/ll1:{deviation='/x'}"); + CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "Path \"/ll1:{deviation='/x'}\"."); + CHECK_LOG_CTX("Invalid mandatory leaf with a default value.", "Path \"/ll1:{deviation='/x'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ll2 {yang-version 1.1; namespace urn:ll2;prefix ll2; leaf-list x {default test; type string;}" "deviation /x {deviate add {min-elements 1;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "/ll2:{deviation='/x'}", - "The default statement is present on leaf-list with a nonzero min-elements.", "/ll2:{deviation='/x'}"); + CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "Path \"/ll2:{deviation='/x'}\"."); + CHECK_LOG_CTX("The default statement is present on leaf-list with a nonzero min-elements.", "Path \"/ll2:{deviation='/x'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ll2 {namespace urn:ll2;prefix ll2; choice ch {default a; leaf a {type string;} leaf b {type string;}}" "deviation /ch {deviate add {mandatory true;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "/ll2:ch", - "Invalid mandatory choice with a default case.", "/ll2:ch"); + CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "Path \"/ll2:ch\"."); + CHECK_LOG_CTX("Invalid mandatory choice with a default case.", "Path \"/ll2:ch\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module mm1 {namespace urn:mm1;prefix mm1; leaf-list x {min-elements 10; type string;}" "deviation /x {deviate add {max-elements 5;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "/mm1:{deviation='/x'}", - "Leaf-list min-elements 10 is bigger than max-elements 5.", "/mm1:{deviation='/x'}"); + CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "Path \"/mm1:{deviation='/x'}\"."); + CHECK_LOG_CTX("Leaf-list min-elements 10 is bigger than max-elements 5.", "Path \"/mm1:{deviation='/x'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module mm2 {namespace urn:mm2;prefix mm2; leaf-list x {max-elements 10; type string;}" "deviation /x {deviate add {min-elements 20;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "/mm2:{deviation='/x'}", - "Leaf-list min-elements 20 is bigger than max-elements 10.", "/mm2:{deviation='/x'}"); + CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "Path \"/mm2:{deviation='/x'}\"."); + CHECK_LOG_CTX("Leaf-list min-elements 20 is bigger than max-elements 10.", "Path \"/mm2:{deviation='/x'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module mm3 {namespace urn:mm3;prefix mm3; list x {min-elements 5; max-elements 10; config false;}" "deviation /x {deviate replace {max-elements 1;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "/mm3:{deviation='/x'}", - "List min-elements 5 is bigger than max-elements 1.", "/mm3:{deviation='/x'}"); + CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "Path \"/mm3:{deviation='/x'}\"."); + CHECK_LOG_CTX("List min-elements 5 is bigger than max-elements 1.", "Path \"/mm3:{deviation='/x'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module mm4 {namespace urn:mm4;prefix mm4; list x {min-elements 5; max-elements 10; config false;}" "deviation /x {deviate replace {min-elements 20;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "/mm4:{deviation='/x'}", - "List min-elements 20 is bigger than max-elements 10.", "/mm4:{deviation='/x'}"); + CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "Path \"/mm4:{deviation='/x'}\"."); + CHECK_LOG_CTX("List min-elements 20 is bigger than max-elements 10.", "Path \"/mm4:{deviation='/x'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module mm5 {namespace urn:mm5;prefix mm5; leaf-list x {type string; min-elements 5;}" "deviation /x {deviate add {min-elements 1;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation adding \"min-elements\" property which already exists (with value \"5\").", "/mm5:{deviation='/x'}"); + CHECK_LOG_CTX("Invalid deviation adding \"min-elements\" property which already exists (with value \"5\").", "Path \"/mm5:{deviation='/x'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module mm6 {namespace urn:mm6;prefix mm6; list x {config false; min-elements 5;}" "deviation /x {deviate add {min-elements 1;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation adding \"min-elements\" property which already exists (with value \"5\").", "/mm6:{deviation='/x'}"); + CHECK_LOG_CTX("Invalid deviation adding \"min-elements\" property which already exists (with value \"5\").", "Path \"/mm6:{deviation='/x'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module mm7 {namespace urn:mm7;prefix mm7; leaf-list x {type string; max-elements 5;}" "deviation /x {deviate add {max-elements 1;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation adding \"max-elements\" property which already exists (with value \"5\").", "/mm7:{deviation='/x'}"); + CHECK_LOG_CTX("Invalid deviation adding \"max-elements\" property which already exists (with value \"5\").", "Path \"/mm7:{deviation='/x'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module mm8 {namespace urn:mm8;prefix mm8; list x {config false; max-elements 5;}" "deviation /x {deviate add {max-elements 1;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation adding \"max-elements\" property which already exists (with value \"5\").", "/mm8:{deviation='/x'}"); + CHECK_LOG_CTX("Invalid deviation adding \"max-elements\" property which already exists (with value \"5\").", "Path \"/mm8:{deviation='/x'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module mm9 {namespace urn:mm9;prefix mm9; leaf-list x {type string;}" "deviation /x {deviate replace {min-elements 1;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation replacing \"min-elements\" property which is not present.", "/mm9:{deviation='/x'}"); + CHECK_LOG_CTX("Invalid deviation replacing \"min-elements\" property which is not present.", "Path \"/mm9:{deviation='/x'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module mm10 {namespace urn:mm10;prefix mm10; list x {config false;}" "deviation /x {deviate replace {min-elements 1;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation replacing \"min-elements\" property which is not present.", "/mm10:{deviation='/x'}"); + CHECK_LOG_CTX("Invalid deviation replacing \"min-elements\" property which is not present.", "Path \"/mm10:{deviation='/x'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module mm11 {namespace urn:mm11;prefix mm11; leaf-list x {type string;}" "deviation /x {deviate replace {max-elements 1;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation replacing \"max-elements\" property which is not present.", "/mm11:{deviation='/x'}"); + CHECK_LOG_CTX("Invalid deviation replacing \"max-elements\" property which is not present.", "Path \"/mm11:{deviation='/x'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module mm12 {namespace urn:mm12;prefix mm12; list x {config false; }" "deviation /x {deviate replace {max-elements 1;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation replacing \"max-elements\" property which is not present.", "/mm12:{deviation='/x'}"); + CHECK_LOG_CTX("Invalid deviation replacing \"max-elements\" property which is not present.", "Path \"/mm12:{deviation='/x'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module nn1 {namespace urn:nn1;prefix nn1; anyxml x;" "deviation /x {deviate replace {type string;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Invalid deviation of anyxml node - it is not possible to replace \"type\" property.", "/nn1:{deviation='/x'}"); + CHECK_LOG_CTX("Invalid deviation of anyxml node - it is not possible to replace \"type\" property.", "Path \"/nn1:{deviation='/x'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module nn2 {namespace urn:nn2;prefix nn2; leaf-list x {type string;}" "deviation /x {deviate replace {type empty;}}}", LYS_IN_YANG, &mod)); - CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "/nn2:{deviation='/x'}", - "Leaf-list of type \"empty\" is allowed only in YANG 1.1 modules.", "/nn2:{deviation='/x'}"); + CHECK_LOG_CTX("Compilation of a deviated and/or refined node failed.", "Path \"/nn2:{deviation='/x'}\"."); + CHECK_LOG_CTX("Leaf-list of type \"empty\" is allowed only in YANG 1.1 modules.", "Path \"/nn2:{deviation='/x'}\"."); assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module oo1 {namespace urn:oo1;prefix oo1; leaf x {type uint16; default 300;}" "deviation /x {deviate replace {type uint8;}}}", LYS_IN_YANG, &mod)); @@ -3563,6 +3704,7 @@ test_deviation(void **state) assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module pp1 {namespace urn:pp1;prefix pp1; import pp {prefix pp;}" "deviation /pp:c/pp:x {deviate not-supported;}}", LYS_IN_YANG, &mod)); CHECK_LOG_CTX("Target of leafref \"l\" cannot be referenced because it is disabled.", "Schema location \"/pp:l\"."); + CHECK_LOG_CTX("Not found node \"x\" in path.", "Schema location \"/pp:l\"."); } static void @@ -3755,6 +3897,55 @@ test_when(void **state) " }" "}", LYS_IN_YANG, NULL)); + + ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, + "module d1 {" + " namespace urn:d1;" + " prefix d1;" + " container ifm {" + " container interfaces {" + " list interface {" + " key \"name\";" + " leaf name {" + " type string;" + " }" + " container ethernet {" + " container main-interface {" + " container l2-attribute {" + " when \"not(/d1:ifm/d1:interfaces/d1:interface/d1:trunk/d1:members/d1:member[d1:name=current()/../../../d1:name])\";" + " presence \"\";" + " }" + " }" + " }" + " container trunk {" + " container members {" + " list member {" + " key \"name\";" + " leaf name {" + " type string;" + " }" + " }" + " }" + " }" + " }" + " }" + " }" + "}"); + assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, + "module d2 {" + " namespace \"urn:d2\";" + " prefix d2;" + " import d1 {" + " prefix d1;" + " }" + " augment \"/d1:ifm/d1:interfaces/d1:interface/d1:ethernet/d1:main-interface\" {" + " when \"not(d1:l2-attribute)\";" + " container extra-attribute {" + " presence \"\";" + " }" + " }" + "}", + LYS_IN_YANG, NULL)); } static void @@ -3796,6 +3987,68 @@ test_must(void **state) LYS_IN_YANG, NULL)); /* no warnings */ CHECK_LOG_CTX(NULL, NULL); + + /* must referencing disabled leafref in another module */ + ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, + "module b-imp {" + " yang-version 1.1;" + " namespace \"urn:b-imp\";" + " prefix \"bi\";" + "" + " feature feat;" + "" + " grouping band-capabilities {" + " leaf band-number {" + " type uint16;" + " }" + "" + " container sub-band-info {" + " when \"../band-number = '46'\";" + " if-feature \"bi:feat\";" + " leaf number-of-laa-scarriers {" + " type uint8;" + " }" + " }" + " }" + "" + " container module-capability {" + " list band-capabilities {" + " key band-number;" + " config false;" + " uses band-capabilities;" + " }" + " container rw-sub-band-info {" + " if-feature \"bi:feat\";" + " leaf rw-number-of-laa-scarriers {" + " type leafref {" + " path \"/module-capability/band-capabilities/sub-band-info/number-of-laa-scarriers\";" + " require-instance false;" + " }" + " }" + " }" + " }" + "}"); + + ly_ctx_set_options(UTEST_LYCTX, LY_CTX_REF_IMPLEMENTED); + assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, + "module b {" + " yang-version 1.1;" + " namespace \"urn:b\";" + " prefix \"b\";" + "" + " import b-imp {" + " prefix \"bi\";" + " }" + "" + " container laa-config {" + " must \"number-of-laa-scarriers <= /bi:module-capability/bi:rw-sub-band-info/bi:rw-number-of-laa-scarriers\";" + " }" + "}", + LYS_IN_YANG, NULL)); + ly_ctx_unset_options(UTEST_LYCTX, LY_CTX_REF_IMPLEMENTED); + + CHECK_LOG_CTX("Schema node \"number-of-laa-scarriers\" not found; in expr \"number-of-laa-scarriers\" " + "with context node \"/b:laa-config\".", NULL); } int @@ -3816,6 +4069,7 @@ main(void) UTEST(test_type_empty, setup), UTEST(test_type_union, setup), UTEST(test_type_dflt, setup), + UTEST(test_type_exts, setup), UTEST(test_status, setup), UTEST(test_node_container, setup), UTEST(test_node_leaflist, setup), diff --git a/tests/utests/schema/test_yang.c b/tests/utests/schema/test_yang.c index 78b1798..6d1c2ae 100644 --- a/tests/utests/schema/test_yang.c +++ b/tests/utests/schema/test_yang.c @@ -155,6 +155,7 @@ test_helpers(void **state) assert_int_equal(LY_EVALID, buf_store_char(YCTX, Y_IDENTIF_ARG, &p, &len, &buf, &size, 1, &prefix)); in.current = ":"; assert_int_equal(LY_EVALID, buf_store_char(YCTX, Y_IDENTIF_ARG, &p, &len, &buf, &size, 1, &prefix)); + UTEST_LOG_CTX_CLEAN; /* valid colon for prefixed identifiers */ len = size = 0; p = NULL; @@ -183,6 +184,7 @@ test_helpers(void **state) assert_int_equal(LY_SUCCESS, lysp_check_identifierchar((struct lysp_ctx *)YCTX, ':', 0, &prefix)); assert_int_equal(1, prefix); assert_int_equal(LY_EVALID, lysp_check_identifierchar((struct lysp_ctx *)YCTX, ':', 0, &prefix)); + CHECK_LOG_CTX("Invalid identifier first character ':' (0x003a).", "Line number 1."); assert_int_equal(1, prefix); assert_int_equal(LY_SUCCESS, lysp_check_identifierchar((struct lysp_ctx *)YCTX, 'b', 0, &prefix)); assert_int_equal(2, prefix); @@ -887,12 +889,18 @@ test_module(void **state) ly_ctx_set_module_imp_clb(PARSER_CUR_PMOD(YCTX)->mod->ctx, test_imp_clb, "module xxx { namespace urn:xxx; prefix x;}"); in.current = "module" SCHEMA_BEGINNING "include xxx;}"; assert_int_equal(lys_parse_mem(PARSER_CUR_PMOD(YCTX)->mod->ctx, in.current, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"name\" failed.", NULL, "Including \"xxx\" submodule into \"name\" failed.", NULL); + CHECK_LOG_CTX("Parsing module \"name\" failed.", NULL); + CHECK_LOG_CTX("Including \"xxx\" submodule into \"name\" failed.", NULL); + CHECK_LOG_CTX("Data model \"xxx\" not found in local searchdirs.", NULL); + CHECK_LOG_CTX("Parsing submodule failed.", NULL); + CHECK_LOG_CTX("Input data contains module in situation when a submodule is expected.", NULL); ly_ctx_set_module_imp_clb(PARSER_CUR_PMOD(YCTX)->mod->ctx, test_imp_clb, "submodule xxx {belongs-to wrong-name {prefix w;}}"); in.current = "module" SCHEMA_BEGINNING "include xxx;}"; assert_int_equal(lys_parse_mem(PARSER_CUR_PMOD(YCTX)->mod->ctx, in.current, LYS_IN_YANG, NULL), LY_EVALID); - CHECK_LOG_CTX("Parsing module \"name\" failed.", NULL, "Including \"xxx\" submodule into \"name\" failed.", NULL); + CHECK_LOG_CTX("Parsing module \"name\" failed.", NULL); + CHECK_LOG_CTX("Including \"xxx\" submodule into \"name\" failed.", NULL); + UTEST_LOG_CTX_CLEAN; ly_ctx_set_module_imp_clb(PARSER_CUR_PMOD(YCTX)->mod->ctx, test_imp_clb, "submodule xxx {belongs-to name {prefix x;}}"); TEST_GENERIC("include xxx;}", mod->includes, diff --git a/tests/utests/schema/test_yin.c b/tests/utests/schema/test_yin.c index 0ce3abc..a531b64 100644 --- a/tests/utests/schema/test_yin.c +++ b/tests/utests/schema/test_yin.c @@ -395,11 +395,13 @@ test_validate_value(void **state) YCTX->xmlctx->value = "pre:b"; YCTX->xmlctx->value_len = 5; assert_int_equal(yin_validate_value(YCTX, Y_IDENTIF_ARG), LY_EVALID); + CHECK_LOG_CTX("Invalid identifier character ':' (0x003a).", "Line number 1."); assert_int_equal(yin_validate_value(YCTX, Y_PREF_IDENTIF_ARG), LY_SUCCESS); YCTX->xmlctx->value = "pre:pre:b"; YCTX->xmlctx->value_len = 9; assert_int_equal(yin_validate_value(YCTX, Y_PREF_IDENTIF_ARG), LY_EVALID); + CHECK_LOG_CTX("Invalid identifier character ':' (0x003a).", "Line number 1."); } static void @@ -3097,7 +3099,7 @@ test_module_elem(void **state) assert_int_equal(yin_parse_mod(YCTX, lysp_mod), LY_SUCCESS); assert_string_equal(lysp_mod->mod->name, "mod"); - assert_string_equal(lysp_mod->revs, "2019-02-02"); + assert_string_equal(lysp_mod->revs[0].date, "2019-02-02"); assert_string_equal(lysp_mod->mod->ns, "ns"); assert_string_equal(lysp_mod->mod->prefix, "pref"); assert_null(lysp_mod->mod->filepath); @@ -3230,8 +3232,10 @@ test_submodule_elem(void **state) assert_int_equal(lyxml_ctx_new(UTEST_LYCTX, UTEST_IN, &YCTX->xmlctx), LY_SUCCESS); assert_int_equal(yin_parse_submod(YCTX, lysp_submod), LY_SUCCESS); + CHECK_LOG_CTX("YANG version 1.1 expects all includes in main module, includes in submodules (mod) are not necessary.", + NULL); assert_string_equal(lysp_submod->name, "mod"); - assert_string_equal(lysp_submod->revs, "2019-02-02"); + assert_string_equal(lysp_submod->revs[0].date, "2019-02-02"); assert_string_equal(lysp_submod->prefix, "pref"); assert_null(lysp_submod->filepath); assert_string_equal(lysp_submod->org, "org"); diff --git a/tests/utests/types/binary.c b/tests/utests/types/binary.c index 05b6b97..4f3ea66 100644 --- a/tests/utests/types/binary.c +++ b/tests/utests/types/binary.c @@ -52,14 +52,15 @@ test_plugin_store(void **state) struct lys_module *mod; struct lyd_value value = {0}; struct lyplg_type *type = lyplg_type_plugin_find("", NULL, ly_data_type2str[LY_TYPE_BINARY]); - struct lysc_type *lysc_type; + 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;}"); + 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); @@ -176,6 +177,35 @@ test_plugin_store(void **state) 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 */ @@ -194,6 +224,14 @@ test_plugin_store(void **state) 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); } static void diff --git a/tests/utests/types/bits.c b/tests/utests/types/bits.c index 3d42ebc..eb40965 100644 --- a/tests/utests/types/bits.c +++ b/tests/utests/types/bits.c @@ -179,7 +179,7 @@ test_schema_yang(void **state) "leaf port {type my_type {" " bit ten {position 11;} bit two;}}"); UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EVALID); - CHECK_LOG_CTX("Invalid bits - position of the item \"ten\" has changed from 10 to 11 in the derived type.", "/TERR_0:port"); + CHECK_LOG_CTX("Invalid bits - position of the item \"ten\" has changed from 10 to 11 in the derived type.", "Path \"/TERR_0:port\"."); /* add new bit */ schema = MODULE_CREATE_YANG("TERR_1", "typedef my_type{type bits {" @@ -187,15 +187,15 @@ test_schema_yang(void **state) "leaf port {type my_type {" " bit ten {position 10;} bit two; bit test;}}"); UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EVALID); - CHECK_LOG_CTX("Invalid bits - derived type adds new item \"test\".", "/TERR_1:port"); + CHECK_LOG_CTX("Invalid bits - derived type adds new item \"test\".", "Path \"/TERR_1:port\"."); /* different max value => autoadd index */ schema = MODULE_CREATE_YANG("TERR_2", "leaf port {type bits {" " bit first {position -1;} bit second;" "}}"); UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EVALID); - CHECK_LOG_CTX("Parsing module \"TERR_2\" failed.", NULL, - "Invalid value \"-1\" of \"position\".", "Line number 5."); + CHECK_LOG_CTX("Parsing module \"TERR_2\" failed.", NULL); + CHECK_LOG_CTX("Invalid value \"-1\" of \"position\".", "Line number 5."); /* different max value => autoadd index */ schema = MODULE_CREATE_YANG("TERR_3", "leaf port {type bits {" @@ -203,48 +203,48 @@ test_schema_yang(void **state) "}}"); UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EVALID); CHECK_LOG_CTX("Invalid bits - it is not possible to auto-assign bit position for \"second\" since the highest value is already 4294967295.", - "/TERR_3:port"); + "Path \"/TERR_3:port\"."); schema = MODULE_CREATE_YANG("TERR_4", "leaf port {type bits {" " bit first {position 10;} bit \"\";" "}}"); UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EVALID); - CHECK_LOG_CTX("Parsing module \"TERR_4\" failed.", NULL, - "Statement argument is required.", "Line number 5."); + CHECK_LOG_CTX("Parsing module \"TERR_4\" failed.", NULL); + CHECK_LOG_CTX("Statement argument is required.", "Line number 5."); /* wrong character */ schema = MODULE_CREATE_YANG("TERR_5", "leaf port {type bits {" " bit first {position 10;} bit abcd^;" "}}"); UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EVALID); - CHECK_LOG_CTX("Parsing module \"TERR_5\" failed.", NULL, - "Invalid identifier character '^' (0x005e).", "Line number 5."); + CHECK_LOG_CTX("Parsing module \"TERR_5\" failed.", NULL); + CHECK_LOG_CTX("Invalid identifier character '^' (0x005e).", "Line number 5."); schema = MODULE_CREATE_YANG("TERR_6", "leaf port {type bits {" " bit hi; bit hi;" "}}"); UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EVALID); - CHECK_LOG_CTX("Parsing module \"TERR_6\" failed.", NULL, - "Duplicate identifier \"hi\" of bit statement.", "Line number 5."); + CHECK_LOG_CTX("Parsing module \"TERR_6\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"hi\" of bit statement.", "Line number 5."); /* wrong character */ schema = MODULE_CREATE_YANG("TERR_7", "leaf port {type bits {" " bit first {position 10;} bit \"ab&cd\";" "}}"); UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EVALID); - CHECK_LOG_CTX("Parsing module \"TERR_7\" failed.", NULL, - "Invalid identifier character '&' (0x0026).", "Line number 5."); + CHECK_LOG_CTX("Parsing module \"TERR_7\" failed.", NULL); + CHECK_LOG_CTX("Invalid identifier character '&' (0x0026).", "Line number 5."); schema = MODULE_CREATE_YANG("TERR_8", "leaf port {type bits {" " bit first {position 10;} bit \"4abcd\";" "}}"); UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EVALID); - CHECK_LOG_CTX("Parsing module \"TERR_8\" failed.", NULL, - "Invalid identifier first character '4' (0x0034).", "Line number 5."); + CHECK_LOG_CTX("Parsing module \"TERR_8\" failed.", NULL); + CHECK_LOG_CTX("Invalid identifier first character '4' (0x0034).", "Line number 5."); schema = MODULE_CREATE_YANG("TERR_9", "leaf port {type bits;}"); UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EVALID); - CHECK_LOG_CTX("Missing bit substatement for bits type.", "/TERR_9:port"); + CHECK_LOG_CTX("Missing bit substatement for bits type.", "Path \"/TERR_9:port\"."); /* new features of YANG 1.1 in YANG 1.0 */ schema = "module TERR_10 {" @@ -256,8 +256,8 @@ test_schema_yang(void **state) " }}" "}"; UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EVALID); - CHECK_LOG_CTX("Parsing module \"TERR_10\" failed.", NULL, - "Invalid keyword \"if-feature\" as a child of \"bit\" - the statement is allowed only in YANG 1.1 modules.", + CHECK_LOG_CTX("Parsing module \"TERR_10\" failed.", NULL); + CHECK_LOG_CTX("Invalid keyword \"if-feature\" as a child of \"bit\" - the statement is allowed only in YANG 1.1 modules.", "Line number 1."); schema = "module TERR_11 {" @@ -267,7 +267,7 @@ test_schema_yang(void **state) " leaf l {type mytype {bit one;}}" "}"; UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EVALID); - CHECK_LOG_CTX("Bits type can be subtyped only in YANG 1.1 modules.", "/TERR_11:l"); + CHECK_LOG_CTX("Bits type can be subtyped only in YANG 1.1 modules.", "Path \"/TERR_11:l\"."); /* feature is not present */ schema = MODULE_CREATE_YANG("IF_0", "feature f;" @@ -415,7 +415,7 @@ test_schema_yin(void **state) " <bit name=\"ten\"> <position value=\"11\"/> </bit> <bit name=\"two\"/>" "</type></leaf>"); UTEST_INVALID_MODULE(schema, LYS_IN_YIN, NULL, LY_EVALID); - CHECK_LOG_CTX("Invalid bits - position of the item \"ten\" has changed from 10 to 11 in the derived type.", "/TERR_0:port"); + CHECK_LOG_CTX("Invalid bits - position of the item \"ten\" has changed from 10 to 11 in the derived type.", "Path \"/TERR_0:port\"."); /* add new bit */ schema = MODULE_CREATE_YIN("TERR_1", @@ -431,7 +431,7 @@ test_schema_yin(void **state) " <bit name=\"test\"/>" "</type></leaf>"); UTEST_INVALID_MODULE(schema, LYS_IN_YIN, NULL, LY_EVALID); - CHECK_LOG_CTX("Invalid bits - derived type adds new item \"test\".", "/TERR_1:port"); + CHECK_LOG_CTX("Invalid bits - derived type adds new item \"test\".", "Path \"/TERR_1:port\"."); /* different max value => autoadd index */ schema = MODULE_CREATE_YIN("TERR_2", @@ -440,8 +440,8 @@ test_schema_yin(void **state) " <bit name=\"second\">" "</type></leaf>"); UTEST_INVALID_MODULE(schema, LYS_IN_YIN, NULL, LY_EVALID); - CHECK_LOG_CTX("Parsing module \"TERR_2\" failed.", NULL, - "Invalid value \"-1\" of \"value\" attribute in \"position\" element.", "Line number 8."); + CHECK_LOG_CTX("Parsing module \"TERR_2\" failed.", NULL); + CHECK_LOG_CTX("Invalid value \"-1\" of \"value\" attribute in \"position\" element.", "Line number 8."); /* different max value => autoadd index */ schema = MODULE_CREATE_YIN("TERR_3", @@ -451,7 +451,7 @@ test_schema_yin(void **state) "</type></leaf>"); UTEST_INVALID_MODULE(schema, LYS_IN_YIN, NULL, LY_EVALID); CHECK_LOG_CTX("Invalid bits - it is not possible to auto-assign bit position for \"second\" since the highest value is already 4294967295.", - "/TERR_3:port"); + "Path \"/TERR_3:port\"."); schema = MODULE_CREATE_YIN("TERR_4", "<leaf name=\"port\"> <type name=\"bits\">" @@ -459,9 +459,8 @@ test_schema_yin(void **state) " <bit name=\"second\"/>" "</type></leaf>"); UTEST_INVALID_MODULE(schema, LYS_IN_YIN, NULL, LY_EVALID); - CHECK_LOG_CTX("Parsing module \"TERR_4\" failed.", NULL, - "Invalid identifier first character ' ' (0x0020).", - "Line number 8."); + CHECK_LOG_CTX("Parsing module \"TERR_4\" failed.", NULL); + CHECK_LOG_CTX("Invalid identifier first character ' ' (0x0020).", "Line number 8."); schema = MODULE_CREATE_YIN("TERR_5", "<leaf name=\"port\"> <type name=\"bits\">" @@ -469,9 +468,8 @@ test_schema_yin(void **state) " <bit name=\"second\"/>" "</type></leaf>"); UTEST_INVALID_MODULE(schema, LYS_IN_YIN, NULL, LY_EVALID); - CHECK_LOG_CTX("Parsing module \"TERR_5\" failed.", NULL, - "Invalid identifier character ' ' (0x0020).", - "Line number 8."); + CHECK_LOG_CTX("Parsing module \"TERR_5\" failed.", NULL); + CHECK_LOG_CTX("Invalid identifier character ' ' (0x0020).", "Line number 8."); schema = MODULE_CREATE_YIN("TERR_6", "<leaf name=\"port\"> <type name=\"bits\">" @@ -479,9 +477,8 @@ test_schema_yin(void **state) " <bit name=\"hi\"/>" "</type></leaf>"); UTEST_INVALID_MODULE(schema, LYS_IN_YIN, NULL, LY_EVALID); - CHECK_LOG_CTX("Parsing module \"TERR_6\" failed.", NULL, - "Duplicate identifier \"hi\" of bit statement.", - "Line number 8."); + CHECK_LOG_CTX("Parsing module \"TERR_6\" failed.", NULL); + CHECK_LOG_CTX("Duplicate identifier \"hi\" of bit statement.", "Line number 8."); schema = MODULE_CREATE_YIN("TERR_7", "<leaf name=\"port\"> <type name=\"bits\">" @@ -489,9 +486,8 @@ test_schema_yin(void **state) " <bit name=\"second\"/>" "</type></leaf>"); UTEST_INVALID_MODULE(schema, LYS_IN_YIN, NULL, LY_EVALID); - CHECK_LOG_CTX("Parsing module \"TERR_7\" failed.", NULL, - "Invalid identifier first character '4' (0x0034).", - "Line number 8."); + CHECK_LOG_CTX("Parsing module \"TERR_7\" failed.", NULL); + CHECK_LOG_CTX("Invalid identifier first character '4' (0x0034).", "Line number 8."); /* TEST EMPTY NAME*/ schema = MODULE_CREATE_YIN("TERR_8", @@ -500,9 +496,8 @@ test_schema_yin(void **state) " <bit name=\"second\"/>" "</type></leaf>"); UTEST_INVALID_MODULE(schema, LYS_IN_YIN, NULL, LY_EVALID); - CHECK_LOG_CTX("Parsing module \"TERR_8\" failed.", NULL, - "Empty identifier is not allowed.", - "Line number 8."); + CHECK_LOG_CTX("Parsing module \"TERR_8\" failed.", NULL); + CHECK_LOG_CTX("Empty identifier is not allowed.", "Line number 8."); } static void @@ -954,30 +949,6 @@ test_plugin_compare(void **state) assert_int_equal(LY_ENOT, type->compare(&diff_type_val, &(values[1]))); type->free(UTEST_LYCTX, &(diff_type_val)); - /* - * derivated type add some limitations - */ - diff_type_text = val_init[2]; - diff_type = ((struct lysc_node_leaf *)mod->compiled->data->next->next)->type; - ly_ret = diff_type->plugin->store(UTEST_LYCTX, diff_type, diff_type_text, strlen(diff_type_text), - 0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &diff_type_val, NULL, &err); - assert_int_equal(LY_SUCCESS, ly_ret); - assert_int_equal(LY_ENOT, type->compare(&diff_type_val, &(values[2]))); - assert_int_equal(LY_ENOT, type->compare(&diff_type_val, &(values[1]))); - type->free(UTEST_LYCTX, &(diff_type_val)); - - /* - * different type (STRING) - */ - diff_type_text = val_init[2]; - diff_type = ((struct lysc_node_leaf *)mod->compiled->data->next->next->next)->type; - ly_ret = diff_type->plugin->store(UTEST_LYCTX, diff_type, diff_type_text, strlen(diff_type_text), - 0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &diff_type_val, NULL, &err); - assert_int_equal(LY_SUCCESS, ly_ret); - assert_int_equal(LY_ENOT, type->compare(&diff_type_val, &(values[2]))); - assert_int_equal(LY_ENOT, type->compare(&diff_type_val, &(values[0]))); - type->free(UTEST_LYCTX, &(diff_type_val)); - /* delete values */ for (unsigned int it = 0; it < sizeof(val_init) / sizeof(val_init[0]); it++) { type->free(UTEST_LYCTX, &(values[it])); diff --git a/tests/utests/types/identityref.c b/tests/utests/types/identityref.c index cdfe057..107164d 100644 --- a/tests/utests/types/identityref.c +++ b/tests/utests/types/identityref.c @@ -27,15 +27,6 @@ NODES \ "}\n" -#define TEST_SUCCESS_XML(MOD_NAME, NAMESPACES, NODE_NAME, DATA, TYPE, ...) \ - { \ - 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_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, NAMESPACES, NODE_NAME, DATA) \ {\ struct lyd_node *tree; \ @@ -64,21 +55,44 @@ static void test_data_xml(void **state) { const char *schema, *schema2; + struct lyd_node *tree; + const char *data; /* xml test */ - schema = MODULE_CREATE_YANG("ident-base", "identity ident-base;" - "identity ident-imp {base ident-base;}"); + 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_CREATE_YANG("defs", "import ident-base {prefix ib;}" - "identity ident1 {base ib:ident-base;}" - "leaf l1 {type identityref {base ib:ident-base;}}"); + 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); - TEST_SUCCESS_XML("defs", "", "l1", "ident1", IDENT, "defs:ident1", "ident1"); - - TEST_SUCCESS_XML("defs", "xmlns:i=\"urn:tests:ident-base\"", "l1", "i:ident-imp", IDENT, "ident-base:ident-imp", - "ident-imp"); + /* 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"); diff --git a/tests/utests/types/instanceid.c b/tests/utests/types/instanceid.c index 06c8622..3126f61 100644 --- a/tests/utests/types/instanceid.c +++ b/tests/utests/types/instanceid.c @@ -79,12 +79,12 @@ static void test_data_xml(void **state) { const char *schema, *schema2; - const enum ly_path_pred_type val1[] = {LY_PATH_PREDTYPE_NONE, LY_PATH_PREDTYPE_NONE}; - const enum ly_path_pred_type val2[] = {LY_PATH_PREDTYPE_LIST, LY_PATH_PREDTYPE_NONE}; + 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, LY_PATH_PREDTYPE_NONE}; - const enum ly_path_pred_type val5[] = {LY_PATH_PREDTYPE_LIST, LY_PATH_PREDTYPE_NONE}; - const enum ly_path_pred_type val6[] = {LY_PATH_PREDTYPE_LIST, LY_PATH_PREDTYPE_NONE}; + 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;}}"); @@ -136,22 +136,23 @@ test_data_xml(void **state) 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.", + CHECK_LOG_CTX("Invalid instance-identifier \"/xdf:list[2]/xdf:value\" value - semantic error: " + "Positional predicate defined for configuration list \"list\" in path.", "Schema location \"/defs:l1\", line number 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.", + CHECK_LOG_CTX("Invalid instance-identifier \"/t:cont/t:1l\" value - syntax error: Invalid character 't'[9] of expression '/t:cont/t:1l'.", "Schema location \"/defs:l1\", line number 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.", + CHECK_LOG_CTX("Invalid instance-identifier \"/t:cont:t:1l\" value - syntax error: Invalid character ':'[8] of expression '/t:cont:t:1l'.", "Schema location \"/defs:l1\", line number 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.", + CHECK_LOG_CTX("Invalid instance-identifier \"/xdf:cont/xdf:invalid/xdf:path\" value - semantic error: Not found node \"invalid\" in path.", "Schema location \"/defs:l1\", line number 1."); /* non-existing instances, instance-identifier is here in JSON format because it is already in internal @@ -190,72 +191,72 @@ test_data_xml(void **state) /* 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.", + CHECK_LOG_CTX("Invalid instance-identifier \"/t:llist[1\" value - syntax error: Unexpected XPath expression end.", "Schema location \"/defs:l1\", line number 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.", + CHECK_LOG_CTX("Invalid instance-identifier \"/m:cont[1]\" value - semantic error: Positional predicate defined for container \"cont\" in path.", "Schema location \"/defs:l1\", line number 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.", + CHECK_LOG_CTX("Invalid instance-identifier \"[1]\" value - syntax error: Unexpected XPath token \"[\" (\"[1]\"), expected \"Operator(Path)\".", "Schema location \"/defs:l1\", line number 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.", + CHECK_LOG_CTX("Invalid instance-identifier \"/m:cont/m:l2[l2='1']\" value - syntax error: Prefix missing for \"l2\" in path.", "Schema location \"/defs:l1\", line number 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.", + CHECK_LOG_CTX("Invalid instance-identifier \"/m:cont/m:l2[m:l2='1']\" value - semantic error: List predicate defined for leaf \"l2\" in path.", "Schema location \"/defs:l1\", line number 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.", + CHECK_LOG_CTX("Invalid instance-identifier \"/t:llist[4]\" value - semantic error: Positional predicate defined for configuration leaf-list \"llist\" in path.", "Schema location \"/defs:l1\", line number 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.", + CHECK_LOG_CTX("Invalid instance-identifier \"/t:llist[6]\" value - semantic error: No module connected with the prefix \"t\" found (prefix format XML prefixes).", "Schema location \"/defs:l2\", line number 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.", + CHECK_LOG_CTX("Invalid instance-identifier \"/xdf:list[xdf:value='x']\" value - semantic error: Key expected instead of leaf \"value\" in path.", "Schema location \"/defs:l2\", line number 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.", + CHECK_LOG_CTX("Invalid instance-identifier \"/xdf:list[.='x']\" value - semantic error: Leaf-list predicate defined for list \"list\" in path.", "Schema location \"/defs:l2\", line number 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.", + CHECK_LOG_CTX("Invalid instance-identifier \"/t:llist[.='x']\" value - semantic error: Invalid type uint32 value \"x\".", "Schema location \"/defs:l1\", line number 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.", + CHECK_LOG_CTX("Invalid instance-identifier \"/t:llist[1][2]\" value - syntax error: Unparsed characters \"[2]\" left at the end of path.", "Schema location \"/defs:l2\", line number 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.", + CHECK_LOG_CTX("Invalid instance-identifier \"/t:llist[.='a'][.='b']\" value - syntax error: Unparsed characters \"[.='b']\" left at the end of path.", "Schema location \"/defs:l2\", line number 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.", + 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.", "Schema location \"/defs:l2\", line number 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.", + 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.", "Schema location \"/defs:l2\", line number 1."); } diff --git a/tests/utests/types/int8.c b/tests/utests/types/int8.c index 7d0b9ad..198d1f7 100644 --- a/tests/utests/types/int8.c +++ b/tests/utests/types/int8.c @@ -240,22 +240,22 @@ test_schema_yang(void **state) /* TEST ERROR -60 .. 0 | 0 .. 127 */ schema = MODULE_CREATE_YANG("ERR0", "leaf port {type int8 {range \"-60 .. 0 | 0 .. 127\";}}"); UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EEXIST); - CHECK_LOG_CTX("Invalid range restriction - values are not in ascending order (0).", "/ERR0:port"); + CHECK_LOG_CTX("Invalid range restriction - values are not in ascending order (0).", "Path \"/ERR0:port\"."); /* TEST ERROR 0 .. 128 */ schema = MODULE_CREATE_YANG("ERR1", "leaf port {type int8 {range \"0 .. 128\";}}"); UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EDENIED); - CHECK_LOG_CTX("Invalid range restriction - value \"128\" does not fit the type limitations.", "/ERR1:port"); + CHECK_LOG_CTX("Invalid range restriction - value \"128\" does not fit the type limitations.", "Path \"/ERR1:port\"."); /* TEST ERROR -129 .. 126 */ schema = MODULE_CREATE_YANG("ERR2", "leaf port {type int8 {range \"-129 .. 0\";}}"); UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EDENIED); - CHECK_LOG_CTX("Invalid range restriction - value \"-129\" does not fit the type limitations.", "/ERR2:port"); + CHECK_LOG_CTX("Invalid range restriction - value \"-129\" does not fit the type limitations.", "Path \"/ERR2:port\"."); /* TEST ERROR 0 */ schema = MODULE_CREATE_YANG("ERR3", "leaf port {type int8 {range \"-129\";}}"); UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EDENIED); - CHECK_LOG_CTX("Invalid range restriction - value \"-129\" does not fit the type limitations.", "/ERR3:port"); + CHECK_LOG_CTX("Invalid range restriction - value \"-129\" does not fit the type limitations.", "Path \"/ERR3:port\"."); /* * TEST MODULE SUBTYPE @@ -374,7 +374,7 @@ test_schema_yang(void **state) "leaf my_leaf {type my_int_type {range \"min .. max\";}}"); UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EVALID); CHECK_LOG_CTX("Invalid range restriction - the derived restriction (min .. max) is not equally or more limiting.", - "/TS_ERR0:my_leaf"); + "Path \"/TS_ERR0:my_leaf\"."); /* TEST SUBTYPE ERROR -80 .. 80 */ schema = MODULE_CREATE_YANG("TS_ERR1", @@ -382,7 +382,7 @@ test_schema_yang(void **state) " leaf my_leaf {type my_int_type {range \"-80 .. 80\";}}"); UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EVALID); CHECK_LOG_CTX("Invalid range restriction - the derived restriction (-80 .. 80) is not equally or more limiting.", - "/TS_ERR1:my_leaf"); + "Path \"/TS_ERR1:my_leaf\"."); /* TEST SUBTYPE ERROR 0 .. max */ schema = MODULE_CREATE_YANG("TS_ERR2", @@ -390,7 +390,7 @@ test_schema_yang(void **state) "leaf my_leaf {type my_int_type {range \"0 .. max\";}}"); UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EVALID); CHECK_LOG_CTX("Invalid range restriction - the derived restriction (0 .. max) is not equally or more limiting.", - "/TS_ERR2:my_leaf"); + "Path \"/TS_ERR2:my_leaf\"."); /* TEST SUBTYPE ERROR -2 .. 2 */ schema = MODULE_CREATE_YANG("TS_ERR3", @@ -398,7 +398,7 @@ test_schema_yang(void **state) "leaf my_leaf {type my_int_type {range \"-2 .. 2\";}}"); UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EVALID); CHECK_LOG_CTX("Invalid range restriction - the derived restriction (-2 .. 2) is not equally or more limiting.", - "/TS_ERR3:my_leaf"); + "Path \"/TS_ERR3:my_leaf\"."); /* TEST SUBTYPE ERROR -2 .. 2 */ schema = MODULE_CREATE_YANG("TS_ERR4", @@ -406,7 +406,7 @@ test_schema_yang(void **state) "leaf my_leaf {type my_int_type {range \"-100 .. -90 | 100 .. 128\";}}"); UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EDENIED); CHECK_LOG_CTX("Invalid range restriction - value \"128\" does not fit the type limitations.", - "/TS_ERR4:my_leaf"); + "Path \"/TS_ERR4:my_leaf\"."); /* * TEST DEFAULT VALUE @@ -745,7 +745,7 @@ test_schema_yin(void **state) " <type name=\"int8\"> <range value = \"min .. 0 | 0 .. 12\"/> </type>" "</leaf>"); UTEST_INVALID_MODULE(schema, LYS_IN_YIN, NULL, LY_EEXIST); - CHECK_LOG_CTX("Invalid range restriction - values are not in ascending order (0).", "/TE0:port"); + CHECK_LOG_CTX("Invalid range restriction - values are not in ascending order (0).", "Path \"/TE0:port\"."); /* TEST ERROR 0 .. 128 */ schema = MODULE_CREATE_YIN("TE1", @@ -753,7 +753,7 @@ test_schema_yin(void **state) " <type name=\"int8\"> <range value = \"0 .. 128\"/> </type>" "</leaf>"); UTEST_INVALID_MODULE(schema, LYS_IN_YIN, NULL, LY_EDENIED); - CHECK_LOG_CTX("Invalid range restriction - value \"128\" does not fit the type limitations.", "/TE1:port"); + CHECK_LOG_CTX("Invalid range restriction - value \"128\" does not fit the type limitations.", "Path \"/TE1:port\"."); /* TEST ERROR -129 .. 126 */ schema = MODULE_CREATE_YIN("TE2", @@ -761,7 +761,7 @@ test_schema_yin(void **state) " <type name=\"int8\"> <range value =\"-129 .. 126\"/> </type>" "</leaf>"); UTEST_INVALID_MODULE(schema, LYS_IN_YIN, NULL, LY_EDENIED); - CHECK_LOG_CTX("Invalid range restriction - value \"-129\" does not fit the type limitations.", "/TE2:port"); + CHECK_LOG_CTX("Invalid range restriction - value \"-129\" does not fit the type limitations.", "Path \"/TE2:port\"."); /* TEST YIN */ schema = MODULE_CREATE_YIN("TS0", @@ -817,7 +817,7 @@ test_schema_yin(void **state) "</leaf>"); UTEST_INVALID_MODULE(schema, LYS_IN_YIN, NULL, LY_EVALID); CHECK_LOG_CTX("Invalid range restriction - the derived restriction (min .. max) is not equally or more limiting.", - "/TS_ERR1:port"); + "Path \"/TS_ERR1:port\"."); /* TEST ERROR */ schema = MODULE_CREATE_YIN("TS_ERR2", @@ -829,7 +829,7 @@ test_schema_yin(void **state) "</leaf>"); UTEST_INVALID_MODULE(schema, LYS_IN_YIN, NULL, LY_EVALID); CHECK_LOG_CTX("Invalid range restriction - the derived restriction (5 .. 11) is not equally or more limiting.", - "/TS_ERR2:port"); + "Path \"/TS_ERR2:port\"."); /* TEST DEFAULT VALUE */ schema = MODULE_CREATE_YIN("DF0", @@ -1243,8 +1243,14 @@ test_data_json(void **state) TEST_SUCCESS_JSON("T0", "127", INT8, "127", 127); /* leading zeros */ TEST_ERROR_JSON("T0", "015"); + CHECK_LOG_CTX("Invalid character sequence \"15}\", expected a JSON object-end or next item.", + "Line number 1."); TEST_ERROR_JSON("T0", "-015"); + CHECK_LOG_CTX("Invalid character sequence \"15}\", expected a JSON object-end or next item.", + "Line number 1."); TEST_ERROR_JSON("defs", "+50"); + CHECK_LOG_CTX("Invalid character sequence \"+50}\", expected a JSON value.", + "Line number 1."); TEST_ERROR_JSON("T0", "-129"); CHECK_LOG_CTX("Value \"-129\" is out of type int8 min/max bounds.", "Schema location \"/T0:port\", line number 1."); @@ -1510,6 +1516,7 @@ test_plugin_store(void **state) ly_ret = type->store(UTEST_LYCTX, &lysc_type_test, val_text, strlen(val_text), 0, LY_VALUE_XML, NULL, LYD_VALHINT_HEXNUM, NULL, &value, NULL, &err); assert_int_equal(LY_EINT, ly_ret); + UTEST_LOG_CTX_CLEAN; /* * ERROR TESTS @@ -1541,6 +1548,8 @@ test_plugin_store(void **state) 0, LY_VALUE_XML, NULL, LYD_VALHINT_DECNUM, NULL, &value, NULL, &err); assert_int_equal(LY_EVALID, ly_ret); ly_err_free(err); + + UTEST_LOG_CTX_CLEAN; } static void diff --git a/tests/utests/types/leafref.c b/tests/utests/types/leafref.c index c8d0cb6..21e91cd 100644 --- a/tests/utests/types/leafref.c +++ b/tests/utests/types/leafref.c @@ -209,6 +209,70 @@ test_plugin_lyb(void **state) TEST_SUCCESS_LYB("lyb", "lst", "key_str", "lref", "key_str"); } +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", "Schema location \"/xp_test:r1\"."); + + 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", "Schema location \"/xp_test:r2\"."); +} + int main(void) { @@ -216,6 +280,8 @@ main(void) UTEST(test_data_xml), UTEST(test_data_json), UTEST(test_plugin_lyb), + UTEST(test_data_xpath_json), + UTEST(test_xpath_invalid_schema) }; return cmocka_run_group_tests(tests, NULL, NULL); diff --git a/tests/utests/types/string.c b/tests/utests/types/string.c index d232e9d..ce5ae8d 100644 --- a/tests/utests/types/string.c +++ b/tests/utests/types/string.c @@ -200,15 +200,15 @@ test_schema_yang(void **state) /* ERROR TESTS NEGATIVE VALUE */ schema = MODULE_CREATE_YANG("ERR0", "leaf port {type string {length \"-1 .. 20\";}}"); UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EDENIED); - CHECK_LOG_CTX("Invalid length restriction - value \"-1\" does not fit the type limitations.", "/ERR0:port"); + CHECK_LOG_CTX("Invalid length restriction - value \"-1\" does not fit the type limitations.", "Path \"/ERR0:port\"."); schema = MODULE_CREATE_YANG("ERR1", "leaf port {type string {length \"100 .. 18446744073709551616\";}}"); UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EVALID); - CHECK_LOG_CTX("Invalid length restriction - invalid value \"18446744073709551616\".", "/ERR1:port"); + CHECK_LOG_CTX("Invalid length restriction - invalid value \"18446744073709551616\".", "Path \"/ERR1:port\"."); schema = MODULE_CREATE_YANG("ERR2", "leaf port {type string {length \"10 .. 20 | 20 .. 30\";}}"); UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EEXIST); - CHECK_LOG_CTX("Invalid length restriction - values are not in ascending order (20).", "/ERR2:port"); + CHECK_LOG_CTX("Invalid length restriction - values are not in ascending order (20).", "Path \"/ERR2:port\"."); schema = MODULE_CREATE_YANG("ERR3", "typedef my_type {" @@ -216,7 +216,7 @@ test_schema_yang(void **state) "}" "leaf port {type my_type {length \"-1 .. 15\";}}"); UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EDENIED); - CHECK_LOG_CTX("Invalid length restriction - value \"-1\" does not fit the type limitations.", "/ERR3:port"); + CHECK_LOG_CTX("Invalid length restriction - value \"-1\" does not fit the type limitations.", "Path \"/ERR3:port\"."); /* * PATTERN @@ -286,7 +286,7 @@ test_schema_yang(void **state) "}}"); UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EVALID); CHECK_LOG_CTX("Regular expression \"[a-zA-Z_[a-zA-Z0-9\\-_.*\" is not valid (\"\": missing terminating ] for character class).", - "/TPATTERN_ERR_0:port"); + "Path \"/TPATTERN_ERR_0:port\"."); schema = MODULE_CREATE_YANG("TDEFAULT_0", "typedef my_type {" @@ -323,14 +323,14 @@ test_schema_yang(void **state) "}}"); UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EVALID); CHECK_LOG_CTX("Regular expression \"\\[a]b\" is not valid (\"]b\": character group doesn't begin with '[').", - "/TPATTERN_BC_ERR_1:port"); + "Path \"/TPATTERN_BC_ERR_1:port\"."); schema = MODULE_CREATE_YANG("TPATTERN_BC_ERR_2", "leaf port {type string {" "pattern \"\\\\[a]b\";" /* pattern "\\[a]b"; */ "}}"); UTEST_INVALID_MODULE(schema, LYS_IN_YANG, NULL, LY_EVALID); CHECK_LOG_CTX("Regular expression \"\\[a]b\" is not valid (\"]b\": character group doesn't begin with '[').", - "/TPATTERN_BC_ERR_2:port"); + "Path \"/TPATTERN_BC_ERR_2:port\"."); /* PATTERN AND LENGTH */ schema = MODULE_CREATE_YANG("TPL_0", @@ -467,26 +467,26 @@ test_schema_yin(void **state) schema = MODULE_CREATE_YIN("ERR0", "<leaf name=\"port\"> <type name=\"string\">" "<length value =\"-1 .. 20\"/> </type></leaf>"); UTEST_INVALID_MODULE(schema, LYS_IN_YIN, NULL, LY_EDENIED); - CHECK_LOG_CTX("Invalid length restriction - value \"-1\" does not fit the type limitations.", "/ERR0:port"); + CHECK_LOG_CTX("Invalid length restriction - value \"-1\" does not fit the type limitations.", "Path \"/ERR0:port\"."); schema = MODULE_CREATE_YIN("ERR1", "<leaf name=\"port\"> <type name=\"string\">" "<length value=\"100 .. 18446744073709551616\"/>" "</type> </leaf>"); UTEST_INVALID_MODULE(schema, LYS_IN_YIN, NULL, LY_EVALID); - CHECK_LOG_CTX("Invalid length restriction - invalid value \"18446744073709551616\".", "/ERR1:port"); + CHECK_LOG_CTX("Invalid length restriction - invalid value \"18446744073709551616\".", "Path \"/ERR1:port\"."); schema = MODULE_CREATE_YIN("ERR2", "<leaf name=\"port\">" "<type name=\"string\"> <length value=\"10 .. 20 | 20 .. 30\"/>" "</type> </leaf>"); UTEST_INVALID_MODULE(schema, LYS_IN_YIN, NULL, LY_EEXIST); - CHECK_LOG_CTX("Invalid length restriction - values are not in ascending order (20).", "/ERR2:port"); + CHECK_LOG_CTX("Invalid length restriction - values are not in ascending order (20).", "Path \"/ERR2:port\"."); schema = MODULE_CREATE_YIN("ERR3", "<typedef name=\"my_type\"> <type name=\"string\"/> </typedef>" "<leaf name=\"port\"> <type name=\"my_type\"> <length value=\"-1 .. 15\"/>" "</type> </leaf>"); UTEST_INVALID_MODULE(schema, LYS_IN_YIN, NULL, LY_EDENIED); - CHECK_LOG_CTX("Invalid length restriction - value \"-1\" does not fit the type limitations.", "/ERR3:port"); + CHECK_LOG_CTX("Invalid length restriction - value \"-1\" does not fit the type limitations.", "Path \"/ERR3:port\"."); /* * PATTERN @@ -557,7 +557,7 @@ test_schema_yin(void **state) "</type> </leaf>"); UTEST_INVALID_MODULE(schema, LYS_IN_YIN, NULL, LY_EVALID); CHECK_LOG_CTX("Regular expression \"[a-zA-Z_][a-zA-Z0-9\\-_.*\" is not valid (\"\": missing terminating ] for character class).", - "/TPATTERN_ERR_0:port"); + "Path \"/TPATTERN_ERR_0:port\"."); /* * DEFAUT VALUE @@ -618,16 +618,8 @@ test_schema_yin(void **state) "</typedef>" "<leaf name=\"port\"> <type name=\"my_type\"/> </leaf>"); UTEST_INVALID_MODULE(schema, LYS_IN_YIN, NULL, LY_EVALID); - - schema = MODULE_CREATE_YIN("TDEFAULT_2", - "<typedef name=\"my_type\">" - " <type name=\"string\">" - " <length value=\"2\"/>" - " </type>" - " <default value=\"a1i-j<\"/>" - "</typedef>" - "<leaf name=\"port\"> <type name=\"my_type\"/> </leaf>"); - UTEST_INVALID_MODULE(schema, LYS_IN_YIN, NULL, LY_EVALID); + CHECK_LOG_CTX("Invalid default - value does not fit the type (Unsatisfied length - string \"a1i-j<\" length is not allowed.).", + "Schema location \"/TDEFAULT_2:port\"."); schema = MODULE_CREATE_YIN("TDEFAULT_3", "<typedef name=\"my_type\">" @@ -636,6 +628,8 @@ test_schema_yin(void **state) "</type> </typedef>" "<leaf name=\"port\"><type name=\"my_type\"> <pattern value=\"bcd.*\"/> </type></leaf>"); UTEST_INVALID_MODULE(schema, LYS_IN_YIN, NULL, LY_EVALID); + CHECK_LOG_CTX("Invalid default - value does not fit the type (Unsatisfied pattern - \"a1i-j<\" does not conform to \"bcd.*\".).", + "Schema location \"/TDEFAULT_3:port\"."); } @@ -874,7 +868,7 @@ test_data_json(void **state) CHECK_LOG_CTX("Invalid character reference \"\\f\" (0x0000000c).", "Line number 1."); TEST_ERROR_JSON("T0", "\""); - CHECK_LOG_CTX("Unexpected character \"\"\" after JSON string.", "Line number 1."); + CHECK_LOG_CTX("Invalid character sequence \"\"}\", expected a JSON object-end or next item.", "Line number 1."); TEST_ERROR_JSON("T0", "aabb \\x"); CHECK_LOG_CTX("Invalid character escape sequence \\x.", "Line number 1."); @@ -1258,26 +1252,6 @@ test_plugin_compare(void **state) assert_int_equal(LY_ENOT, type->compare(&diff_type_val, &(values[1]))); type->free(UTEST_LYCTX, &(diff_type_val)); - /* original type */ - diff_type_text = "hi"; - diff_type = ((struct lysc_node_leaf *) mod->compiled->data->next->next)->type; - ly_ret = diff_type->plugin->store(UTEST_LYCTX, diff_type, diff_type_text, strlen(diff_type_text), - 0, LY_VALUE_XML, NULL, LYD_VALHINT_STRING, NULL, &diff_type_val, NULL, &err); - assert_int_equal(LY_SUCCESS, ly_ret); - assert_int_equal(LY_ENOT, type->compare(&diff_type_val, &(values[0]))); - assert_int_equal(LY_ENOT, type->compare(&diff_type_val, &(values[1]))); - type->free(UTEST_LYCTX, &(diff_type_val)); - - /* different type (UINT8) */ - diff_type_text = "20"; - diff_type = ((struct lysc_node_leaf *) mod->compiled->data->next->next->next)->type; - ly_ret = diff_type->plugin->store(UTEST_LYCTX, diff_type, diff_type_text, strlen(diff_type_text), - 0, LY_VALUE_XML, NULL, LYD_VALHINT_DECNUM, NULL, &diff_type_val, NULL, &err); - assert_int_equal(LY_SUCCESS, ly_ret); - assert_int_equal(LY_ENOT, type->compare(&diff_type_val, &(values[0]))); - assert_int_equal(LY_ENOT, type->compare(&diff_type_val, &(values[1]))); - type->free(UTEST_LYCTX, &(diff_type_val)); - /* delete values */ for (int unsigned it = 0; it < sizeof(val_init) / sizeof(val_init[0]); it++) { type->free(UTEST_LYCTX, &(values[it])); diff --git a/tests/utests/types/union.c b/tests/utests/types/union.c index 9a0705a..d23cbf1 100644 --- a/tests/utests/types/union.c +++ b/tests/utests/types/union.c @@ -104,11 +104,34 @@ test_data_xml(void **state) /* invalid value */ TEST_ERROR_XML2("", "defs", "", "un1", "123456789012345678901", LY_EVALID); - CHECK_LOG_CTX("Invalid union value \"123456789012345678901\" - no matching subtype found.", + 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", "Schema location \"/defs:un1\", line number 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; @@ -124,12 +147,60 @@ test_plugin_lyb(void **state) TEST_SUCCESS_LYB("lyb", "un1", ""); } +static void +test_validation(void **state) +{ + const char *schema, *data; + struct lyd_node *tree; + char *out; + + 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); +} + int main(void) { const struct CMUnitTest tests[] = { UTEST(test_data_xml), + UTEST(test_data_json), UTEST(test_plugin_lyb), + UTEST(test_validation), }; return cmocka_run_group_tests(tests, NULL, NULL); diff --git a/tests/utests/types/yang_types.c b/tests/utests/types/yang_types.c index 6ce7671..0f78455 100644 --- a/tests/utests/types/yang_types.c +++ b/tests/utests/types/yang_types.c @@ -3,7 +3,7 @@ * @author Michal Vaško <mvasko@cesnet.cz> * @brief test for ietf-yang-types values * - * Copyright (c) 2021 CESNET, z.s.p.o. + * 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. @@ -52,11 +52,11 @@ lyd_free_all(tree); \ } -#define TEST_ERROR_XML(MOD_NAME, NODE_NAME, DATA) \ +#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, LY_EVALID, tree); \ + CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, RET, tree); \ assert_null(tree); \ } @@ -84,14 +84,15 @@ test_data_xml(void **state) /* xml test */ schema = MODULE_CREATE_YANG("a", "leaf l {type yang:date-and-time;}" - "leaf l2 {type yang:xpath1.0;}"); + "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 */ -#if defined (HAVE_TM_GMTOFF) && defined (HAVE_TIME_H_TIMEZONE) 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"); @@ -105,51 +106,44 @@ test_data_xml(void **state) /* fractional hours */ TEST_SUCCESS_XML("a", "l", "2005-05-25T23:15:15.88888+04:30", STRING, "2005-05-25T16:45:15.88888-02:00"); -#else - /* Tests run with a TZ offset of +02:00, but this platform cannot represent that in time_t, - * so libyang always returns unspecified TZ. */ - TEST_SUCCESS_XML("a", "l", "2005-05-25T23:15:15.88888Z", STRING, "2005-05-25T23:15:15.88888-00:00"); - TEST_SUCCESS_XML("a", "l", "2005-05-31T23:15:15-08:59", STRING, "2005-06-01T08:14:15-00:00"); - TEST_SUCCESS_XML("a", "l", "2005-05-31T23:15:15-23:00", STRING, "2005-06-01T22:15:15-00: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-01T02:59:59-00:00"); - TEST_SUCCESS_XML("a", "l", "1969-12-31T23:59:59-02:00", STRING, "1970-01-01T01:59:59-00:00"); - - /* canonize */ - TEST_SUCCESS_XML("a", "l", "2005-02-29T23:15:15-02:00", STRING, "2005-03-02T01:15:15-00:00"); - - /* fractional hours */ - TEST_SUCCESS_XML("a", "l", "2005-05-25T23:15:15.88888+04:30", STRING, "2005-05-25T18:45:15.88888-00:00"); -#endif /* 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"); + 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})\".", "Schema location \"/a:l\", line number 1."); + TEST_ERROR_XML("a", "l", "2023-16-15T20:13:01+01:00", LY_EINVAL); + CHECK_LOG_CTX("Invalid date-and-time month \"15\".", "Schema location \"/a:l\", line number 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\".", "Schema location \"/a:l\", line number 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", "l2", "/aa:l2[. = '4']", STRING, "/a:l2[.='4']"); + 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", "l2", + "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", "l2", + 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", "l2", "/l2[. = '4']", STRING, "/l2[.='4']"); - - TEST_ERROR_XML("a", "l2", "/a:l2[. = '4']"); - CHECK_LOG_CTX("Failed to resolve prefix \"a\".", "Schema location \"/a:l2\", line number 1."); - TEST_ERROR_XML("a\" xmlns:yl=\"urn:ietf:params:xml:ns:yang:ietf-yang-library", "l2", - "/yl:yang-library/yl:datastore/yl::name"); - CHECK_LOG_CTX("Storing value failed.", "Schema location \"/a:l2\", line number 1.", - "Invalid character 'y'[31] of expression '/yl:yang-library/yl:datastore/yl::name'.", - "Schema location \"/a:l2\", line number 1."); + 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\".", "Schema location \"/a:l3\", line number 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.", "Schema location \"/a:l3\", line number 1."); + CHECK_LOG_CTX("Invalid character 'y'[31] of expression '/yl:yang-library/yl:datastore/yl::name'.", + "Schema location \"/a:l3\", line number 1."); } static void @@ -191,6 +185,31 @@ test_print(void **state) } 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; @@ -216,6 +235,7 @@ main(void) const struct CMUnitTest tests[] = { UTEST(test_data_xml), UTEST(test_print), + UTEST(test_duplicate), UTEST(test_lyb), }; diff --git a/tests/utests/utests.h b/tests/utests/utests.h index 877d048..0e0649d 100644 --- a/tests/utests/utests.h +++ b/tests/utests/utests.h @@ -1010,7 +1010,9 @@ struct utest_context { LY_ARRAY_COUNT_TYPE arr_size = sizeof(VALUE) / sizeof(VALUE[0]); \ assert_int_equal(arr_size, LY_ARRAY_COUNT((NODE).target)); \ for (LY_ARRAY_COUNT_TYPE it = 0; it < arr_size; it++) { \ - assert_int_equal(VALUE[it], (NODE).target[it].pred_type); \ + if ((NODE).target[it].predicates) { \ + assert_int_equal(VALUE[it], (NODE).target[it].predicates[0].type); \ + } \ } \ } @@ -1224,97 +1226,32 @@ struct utest_context { _UC->in = NULL /** - * @brief Internal macro to compare error info record with the expected error message and path. - * If NULL is provided as MSG, no error info record (NULL) is expected. + * @brief Check expected last error message. * - * @param[in] ERR Error information record from libyang context. * @param[in] MSG Expected error message. - * @param[in] PATH Expected error path. - */ -#define _CHECK_LOG_CTX(ERR, MSG, PATH) \ - if (!MSG) { \ - assert_null(ERR); \ - } else { \ - assert_non_null(ERR); \ - CHECK_STRING((ERR)->msg, MSG); \ - CHECK_STRING((ERR)->path, PATH); \ - } - -/**` - * @brief Internal macro to check the last libyang's context error. - */ -#define _CHECK_LOG_CTX1(MSG, PATH) \ - _CHECK_LOG_CTX(ly_err_last(_UC->ctx), MSG, PATH) - -/** - * @brief Internal macro to check the last two libyang's context error. - */ -#define _CHECK_LOG_CTX2(MSG1, PATH1, MSG2, PATH2) \ - _CHECK_LOG_CTX(ly_err_last(_UC->ctx), MSG1, PATH1); \ - _CHECK_LOG_CTX(ly_err_last(_UC->ctx)->prev, MSG2, PATH2) - -/** - * @brief Internal macro to check the last three libyang's context error. - */ -#define _CHECK_LOG_CTX3(MSG1, PATH1, MSG2, PATH2, MSG3, PATH3) \ - _CHECK_LOG_CTX2(MSG1, PATH1, MSG2, PATH2); \ - _CHECK_LOG_CTX(ly_err_last(_UC->ctx)->prev->prev, MSG3, PATH3) - -/** - * @brief Internal macro to check the last three libyang's context error. - */ -#define _CHECK_LOG_CTX4(MSG1, PATH1, MSG2, PATH2, MSG3, PATH3, MSG4, PATH4) \ - _CHECK_LOG_CTX3(MSG1, PATH1, MSG2, PATH2, MSG3, PATH3); \ - _CHECK_LOG_CTX(ly_err_last(_UC->ctx)->prev->prev->prev, MSG4, PATH4) - -/** - * @brief Internal macro to check the last three libyang's context error. - */ -#define _CHECK_LOG_CTX5(MSG1, PATH1, MSG2, PATH2, MSG3, PATH3, MSG4, PATH4, MSG5, PATH5) \ - _CHECK_LOG_CTX4(MSG1, PATH1, MSG2, PATH2, MSG3, PATH3, MSG4, PATH4); \ - _CHECK_LOG_CTX(ly_err_last(_UC->ctx)->prev->prev->prev->prev, MSG5, PATH5) - -/** - * @brief Internal macro to check the last three libyang's context error. - */ -#define _CHECK_LOG_CTX6(MSG1, PATH1, MSG2, PATH2, MSG3, PATH3, MSG4, PATH4, MSG5, PATH5, MSG6, PATH6) \ - _CHECK_LOG_CTX5(MSG1, PATH1, MSG2, PATH2, MSG3, PATH3, MSG4, PATH4, MSG5, PATH5); \ - _CHECK_LOG_CTX(ly_err_last(_UC->ctx)->prev->prev->prev->prev->prev, MSG6, PATH6) - -/** - * @brief Internal macro to check the last three libyang's context error. - */ -#define _CHECK_LOG_CTX7(MSG1, PATH1, MSG2, PATH2, MSG3, PATH3, MSG4, PATH4, MSG5, PATH5, MSG6, PATH6, MSG7, PATH7) \ - _CHECK_LOG_CTX6(MSG1, PATH1, MSG2, PATH2, MSG3, PATH3, MSG4, PATH4, MSG5, PATH5, MSG6, PATH6); \ - _CHECK_LOG_CTX(ly_err_last(_UC->ctx)->prev->prev->prev->prev->prev->prev, MSG7, PATH7) - -/** - * @brief Internal macro to check the last three libyang's context error. */ -#define _CHECK_LOG_CTX8(MSG1, PATH1, MSG2, PATH2, MSG3, PATH3, MSG4, PATH4, MSG5, PATH5, MSG6, PATH6, MSG7, PATH7, MSG8, PATH8) \ - _CHECK_LOG_CTX7(MSG1, PATH1, MSG2, PATH2, MSG3, PATH3, MSG4, PATH4, MSG5, PATH5, MSG6, PATH6, MSG7, PATH7); \ - _CHECK_LOG_CTX(ly_err_last(_UC->ctx)->prev->prev->prev->prev->prev->prev->prev, MSG8, PATH8) +#define CHECK_LOG_LASTMSG(MSG) \ + CHECK_STRING(ly_last_errmsg(), MSG) /** - * @brief Internal helper macro to select _CHECK_LOG_CTX* macro according to the provided parameters. - */ -#define _GET_CHECK_LOG_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, NAME, ...) NAME - -/** - * @brief Check expected error(s) in libyang context. - * - * Macro has variadic parameters expected to be provided in pairs of error message and error path starting - * from the latest error. Current limit is checking at most 3 last errors. After checking, macro cleans up - * all the errors from the libyang context. + * @brief Check expected last error in libyang context, which is then cleared. Can be called repeatedly to check + * several errors. If NULL is provided as MSG, no error info record (NULL) is expected. * * @param[in] MSG Expected error message. * @param[in] PATH Expected error path. */ -#define CHECK_LOG_CTX(...) \ - _GET_CHECK_LOG_MACRO(__VA_ARGS__, _CHECK_LOG_CTX8, _INVAL, _CHECK_LOG_CTX7, _INVAL, \ - _CHECK_LOG_CTX6, _INVAL, _CHECK_LOG_CTX5, _INVAL, _CHECK_LOG_CTX4, _INVAL, \ - _CHECK_LOG_CTX3, _INVAL, _CHECK_LOG_CTX2, _INVAL, _CHECK_LOG_CTX1, DUMMY)(__VA_ARGS__); \ - ly_err_clean(_UC->ctx, NULL) +#define CHECK_LOG_CTX(MSG, PATH) \ + { \ + struct ly_err_item *_e = ly_err_last(_UC->ctx); \ + if (!MSG) { \ + assert_null(_e); \ + } else { \ + assert_non_null(_e); \ + CHECK_STRING(_e->msg, MSG); \ + CHECK_STRING(_e->path, PATH); \ + } \ + ly_err_clean(_UC->ctx, _e); \ + } /** * @brief Check expected error in libyang context including error-app-tag. @@ -1324,14 +1261,23 @@ struct utest_context { * @param[in] APPTAG Expected error-app-tag. */ #define CHECK_LOG_CTX_APPTAG(MSG, PATH, APPTAG) \ - if (!MSG) { \ - assert_null(ly_err_last(_UC->ctx)); \ - } else { \ - assert_non_null(ly_err_last(_UC->ctx)); \ - CHECK_STRING(ly_err_last(_UC->ctx)->msg, MSG); \ - CHECK_STRING(ly_err_last(_UC->ctx)->path, PATH); \ - CHECK_STRING(ly_err_last(_UC->ctx)->apptag, APPTAG); \ - } \ + { \ + struct ly_err_item *_e = ly_err_last(_UC->ctx); \ + if (!MSG) { \ + assert_null(_e); \ + } else { \ + assert_non_null(_e); \ + CHECK_STRING(_e->msg, MSG); \ + CHECK_STRING(_e->path, PATH); \ + CHECK_STRING(_e->apptag, APPTAG); \ + } \ + ly_err_clean(_UC->ctx, _e); \ + } + +/** + * @brief Clear all errors stored in the libyang context. + */ +#define UTEST_LOG_CTX_CLEAN \ ly_err_clean(_UC->ctx, NULL) /** @@ -1435,7 +1381,8 @@ utest_teardown(void **state) { *state = NULL; - /* libyang context */ + /* libyang context, no leftover messages */ + assert_null(ly_err_last(current_utest_context->ctx)); ly_ctx_destroy(current_utest_context->ctx); if (current_utest_context->orig_tz) { diff --git a/tests/yanglint/CMakeLists.txt b/tests/yanglint/CMakeLists.txt new file mode 100644 index 0000000..c1e081a --- /dev/null +++ b/tests/yanglint/CMakeLists.txt @@ -0,0 +1,36 @@ +if(WIN32) + set(YANGLINT_INTERACTIVE OFF) +else() + set(YANGLINT_INTERACTIVE ON) +endif() + +function(add_yanglint_test) + cmake_parse_arguments(ADDTEST "" "NAME;VIA;SCRIPT" "" ${ARGN}) + set(TEST_NAME yanglint_${ADDTEST_NAME}) + + if(${ADDTEST_VIA} STREQUAL "tclsh") + set(WRAPPER ${PATH_TCLSH}) + else() + message(FATAL_ERROR "build: unexpected wrapper '${ADDTEST_VIA}'") + endif() + + add_test(NAME ${TEST_NAME} COMMAND ${WRAPPER} ${CMAKE_CURRENT_SOURCE_DIR}/${ADDTEST_SCRIPT}) + set_property(TEST ${TEST_NAME} APPEND PROPERTY ENVIRONMENT "TESTS_DIR=${CMAKE_CURRENT_SOURCE_DIR}") + set_property(TEST ${TEST_NAME} APPEND PROPERTY ENVIRONMENT "YANG_MODULES_DIR=${CMAKE_CURRENT_SOURCE_DIR}/modules") + set_property(TEST ${TEST_NAME} APPEND PROPERTY ENVIRONMENT "YANGLINT=${PROJECT_BINARY_DIR}") +endfunction(add_yanglint_test) + +if(ENABLE_TESTS) + # tests of interactive mode using tclsh + find_program(PATH_TCLSH NAMES tclsh) + if(NOT PATH_TCLSH) + message(WARNING "'tclsh' not found! The yanglint(1) interactive tests will not be available.") + else() + if(YANGLINT_INTERACTIVE) + add_yanglint_test(NAME interactive VIA tclsh SCRIPT interactive/all.tcl) + add_yanglint_test(NAME non-interactive VIA tclsh SCRIPT non-interactive/all.tcl) + else() + add_yanglint_test(NAME non-interactive VIA tclsh SCRIPT non-interactive/all.tcl) + endif() + endif() +endif() diff --git a/tests/yanglint/README.md b/tests/yanglint/README.md new file mode 100644 index 0000000..6c51d89 --- /dev/null +++ b/tests/yanglint/README.md @@ -0,0 +1,107 @@ +# yanglint testing + +Testing yanglint is divided into two ways. +It is either tested in interactive mode using the tcl command 'expect' or non-interactively, classically from the command line. +For both modes, unit testing was used using the tcl package tcltest. + +## How to + +The sample commands in this chapter using `tclsh` are called in the `interactive` or `non-interactive` directories. + +### How to run all yanglint tests? + +In the build directory designated for cmake, enter: + +``` +ctest -R yanglint +``` + +### How to run all yanglint tests that are in interactive mode? + +In the interactive directory, run: + +``` +tclsh all.tcl +``` + +### How to run all yanglint tests that are in non-interactive mode? + +In the non-interactive directory, run: + +``` +tclsh all.tcl +``` + +### How to run all unit-tests from .test file? + +``` +tclsh clear.test +``` + +or alternatively: + +``` +tclsh all.tcl -file clear.test +``` + +### How to run one unit-test? + +``` +tclsh clear.test -match clear_ietf_yang_library +``` + +or alternatively: + +``` +tclsh all.tcl -file clear.test -match clear_ietf_yang_library +``` + +### How to run unit-tests for a certain yanglint command? + +Test names are assumed to consist of the command name: + +``` +tclsh all.tcl -match clear* +``` + +### How do I get more detailed information about 'expect' for a certain test? + +In the interactive directory, run: + +``` +tclsh clear.test -match clear_ietf_yang_library -load "exp_internal 1" +``` + +### How do I get more detailed dialog between 'expect' and yanglint for a certain test? + +In the interactive directory, run: + +``` +tclsh clear.test -match clear_ietf_yang_library -load "log_user 1" +``` + +### How do I suppress error message from tcltest? + +Probably only possible to do via `-verbose ""` + +### How can I also debug? + +You can write commands `interact` and `interpreter` from 'Expect' package into some test. +However, the most useful are the `exp_internal` and `log_user`, which can also be written directly into the test. +See also the rlwrap tool. +You can also use other debugging methods used in tcl programming. + +### Are the tests between interactive mode and non-interactive mode similar? + +Sort of... +- regex \n must be changed to \r\n in the tests for interactive yanglint + +### I would like to add a new "ly_" function. + +Add it to the ly.tcl file. +If you need to call other subfunctions in it, add them to namespace ly::private. + +### I would like to use function other than those prefixed with "ly_". + +Look in the common.tcl file in the "uti" namespace, +which contains general tcl functions that can be used in both interactive and non-interactive tests. diff --git a/tests/yanglint/common.tcl b/tests/yanglint/common.tcl new file mode 100644 index 0000000..d186282 --- /dev/null +++ b/tests/yanglint/common.tcl @@ -0,0 +1,114 @@ +# @brief Common functions and variables for yanglint-interactive and yanglint-non-interactive. +# +# The script requires variables: +# ::env(TESTS_DIR) - Main test directory. Must be set if the script is run via ctest. +# +# The script sets the variables: +# ::env(TESTS_DIR) - Main test directory. It is set by default if not defined. +# ::env(YANG_MODULES_DIR) - Directory of YANG modules. +# TUT_PATH - Assumed absolute path to the directory in which the TUT is located. +# TUT_NAME - TUT name (without path). +# ::tcltest::testConstraint ctest - A tcltest variable that is set to true if the script is run via ctest. Causes tests +# to be a skipped. + +package require tcltest +namespace import ::tcltest::test ::tcltest::cleanupTests + +# Set directory paths for testing yanglint. +if { ![info exists ::env(TESTS_DIR)] } { + # the script is not run via 'ctest' so paths must be set + set ::env(TESTS_DIR) "../" + set ::env(YANG_MODULES_DIR) "../modules" + set TUT_PATH "../../../build" + ::tcltest::testConstraint ctest false +} else { + # cmake (ctest) already sets ::env variables + set TUT_PATH $::env(YANGLINT) + ::tcltest::testConstraint ctest true +} + +set TUT_NAME "yanglint" + +# The script continues by defining functions specific to the yanglint tool. + +namespace eval uti { + namespace export * +} + +# Iterate through the items in the list 'lst' and return a new list where +# the items will have the form: <prefix><item><suffix>. +# Parameter 'index' determines at which index it will start wrapping. +# Parameter 'step' specifies how far the iterator must move to wrap the next item. +proc uti::wrap_list_items {lst {prefix ""} {suffix ""} {index 0} {step 1}} { + # counter to track when to insert wrapper + set cnt $step + set len [llength $lst] + + if {$index > 0} { + # copy list from interval <0;$index) + set ret [lrange $lst 0 [expr {$index - 1}]] + } else { + set ret {} + } + + for {set i $index} {$i < $len} {incr i} { + incr cnt + set item [lindex $lst $i] + if {$cnt >= $step} { + # insert wrapper for item + set cnt 0 + lappend ret [string cat $prefix $item $suffix] + } else { + # just copy item + lappend ret $item + } + } + + return $ret +} + +# Wrap list items with xml tags. +# The element format is: <tag>value</tag> +# Parameter 'values' is list of values. +# Parameter 'tag' is the name of the searched tag. +proc uti::wrap_to_xml {values tag {index 0} {step 1}} { + return [wrap_list_items $values "<$tag>" "</$tag>" $index $step] +} + +# Wrap list items with json attributes. +# The pair format is: "attribute": "value" +# Parameter 'values' is list of values. +# Parameter 'attribute' is the name of the searched attribute. +proc uti::wrap_to_json {values attribute {index 0} {step 1}} { + return [wrap_list_items $values "\"$attribute\": \"" "\"" $index $step] +} + +# Convert list to a regex (which is just a string) so that 'delim' is between items, +# 'begin' is at the beginning of the expression and 'end' is at the end. +proc uti::list_to_regex {lst {delim ".*"} {begin ".*"} {end ".*"}} { + return [string cat $begin [join $lst $delim] $end] +} + +# Merge two lists into one such that the nth items are merged into one separated by a delimiter. +# Returns a list that is the same length as 'lst1' and 'lst2' +proc uti::blend_lists {lst1 lst2 {delim ".*"}} { + return [lmap a $lst1 b $lst2 {string cat $a $delim $b}] +} + +# Create regex to find xml elements. +# The element format is: <tag>value</tag> +# Parameter 'values' is list of values. +# Parameter 'tag' is the name of the searched tag. +# The resulting expression looks like: ".*<tag>value1</tag>.*<tag>value2</tag>.*..." +proc uti::regex_xml_elements {values tag} { + return [list_to_regex [wrap_to_xml $values $tag]] +} + +# Create regex to find json pairs. +# The pair format is: "attribute": "value" +# Parameter 'values' is list of values. +# Parameter 'attribute' is the name of the searched attribute. +# The resulting expression looks like: ".*\"attribute\": \"value1\".*\"attribute\": \"value2\".*..." +proc uti::regex_json_pairs {values attribute} { + return [list_to_regex [wrap_to_json $values $attribute]] +} diff --git a/tests/yanglint/data/modaction.xml b/tests/yanglint/data/modaction.xml new file mode 100644 index 0000000..37faa2d --- /dev/null +++ b/tests/yanglint/data/modaction.xml @@ -0,0 +1,8 @@ +<con xmlns="urn:yanglint:modaction"> + <ls> + <lfkey>kv</lfkey> + <act> + <lfi>some_input</lfi> + </act> + </ls> +</con> diff --git a/tests/yanglint/data/modaction_ds.xml b/tests/yanglint/data/modaction_ds.xml new file mode 100644 index 0000000..a5a1727 --- /dev/null +++ b/tests/yanglint/data/modaction_ds.xml @@ -0,0 +1,5 @@ +<con xmlns="urn:yanglint:modaction"> + <ls> + <lfkey>kv</lfkey> + </ls> +</con> diff --git a/tests/yanglint/data/modaction_nc.xml b/tests/yanglint/data/modaction_nc.xml new file mode 100644 index 0000000..a74b6bf --- /dev/null +++ b/tests/yanglint/data/modaction_nc.xml @@ -0,0 +1,13 @@ +<rpc message-id="101" + xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> + <action xmlns="urn:ietf:params:xml:ns:yang:1"> + <con xmlns="urn:yanglint:modaction"> + <ls> + <lfkey>kv</lfkey> + <act> + <lfi>some_input</lfi> + </act> + </ls> + </con> + </action> +</rpc> diff --git a/tests/yanglint/data/modaction_reply.xml b/tests/yanglint/data/modaction_reply.xml new file mode 100644 index 0000000..7d6532d --- /dev/null +++ b/tests/yanglint/data/modaction_reply.xml @@ -0,0 +1,8 @@ +<con xmlns="urn:yanglint:modaction"> + <ls> + <lfkey>kv</lfkey> + <act> + <lfo>-56</lfo> + </act> + </ls> +</con> diff --git a/tests/yanglint/data/modaction_reply_nc.xml b/tests/yanglint/data/modaction_reply_nc.xml new file mode 100644 index 0000000..f7c3b8f --- /dev/null +++ b/tests/yanglint/data/modaction_reply_nc.xml @@ -0,0 +1,4 @@ +<rpc-reply message-id="101" + xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> + <lfo xmlns="urn:yanglint:modaction">-56</lfo> +</rpc-reply> diff --git a/tests/yanglint/data/modconfig.xml b/tests/yanglint/data/modconfig.xml new file mode 100644 index 0000000..f8a03a9 --- /dev/null +++ b/tests/yanglint/data/modconfig.xml @@ -0,0 +1,4 @@ +<mcc xmlns="urn:yanglint:modconfig"> + <lft>rw</lft> + <lff>ro</lff> +</mcc> diff --git a/tests/yanglint/data/modconfig2.xml b/tests/yanglint/data/modconfig2.xml new file mode 100644 index 0000000..c96e344 --- /dev/null +++ b/tests/yanglint/data/modconfig2.xml @@ -0,0 +1,3 @@ +<mcc xmlns="urn:yanglint:modconfig"> + <lft>rw</lft> +</mcc> diff --git a/tests/yanglint/data/modconfig_ctx.xml b/tests/yanglint/data/modconfig_ctx.xml new file mode 100644 index 0000000..124989c --- /dev/null +++ b/tests/yanglint/data/modconfig_ctx.xml @@ -0,0 +1,13 @@ +<yang-library xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library"> + <module-set> + <name>main-set</name> + <module> + <name>modconfig</name> + <namespace>urn:yanglint:modconfig</namespace> + </module> + </module-set> + <content-id>1</content-id> +</yang-library> +<modules-state xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library"> + <module-set-id>1</module-set-id> +</modules-state> diff --git a/tests/yanglint/data/moddatanodes.xml b/tests/yanglint/data/moddatanodes.xml new file mode 100644 index 0000000..8ae6e97 --- /dev/null +++ b/tests/yanglint/data/moddatanodes.xml @@ -0,0 +1,17 @@ +<dnc xmlns="urn:yanglint:moddatanodes"> + <lf>x</lf> + <lfl>1</lfl> + <lfl>2</lfl> + <con> + <lt> + <kalf>ka1</kalf> + <kblf>kb1</kblf> + <vlf>v1</vlf> + </lt> + <lt> + <kalf>ka2</kalf> + <kblf>kb2</kblf> + <vlf>v2</vlf> + </lt> + </con> +</dnc> diff --git a/tests/yanglint/data/moddefault.xml b/tests/yanglint/data/moddefault.xml new file mode 100644 index 0000000..00f3a9d --- /dev/null +++ b/tests/yanglint/data/moddefault.xml @@ -0,0 +1,4 @@ +<mdc xmlns="urn:yanglint:moddefault"> + <lf>0</lf> + <di>5</di> +</mdc> diff --git a/tests/yanglint/data/modimp_type_ctx.xml b/tests/yanglint/data/modimp_type_ctx.xml new file mode 100644 index 0000000..e6d158a --- /dev/null +++ b/tests/yanglint/data/modimp_type_ctx.xml @@ -0,0 +1,13 @@ +<yang-library xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library"> + <module-set> + <name>main-set</name> + <module> + <name>modimp-type</name> + <namespace>urn:yanglint:modimp-type</namespace> + </module> + </module-set> + <content-id>1</content-id> +</yang-library> +<modules-state xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library"> + <module-set-id>1</module-set-id> +</modules-state> diff --git a/tests/yanglint/data/modleaf.djson b/tests/yanglint/data/modleaf.djson new file mode 100644 index 0000000..25af218 --- /dev/null +++ b/tests/yanglint/data/modleaf.djson @@ -0,0 +1,3 @@ +{ + "modleaf:lfl": 7 +} diff --git a/tests/yanglint/data/modleaf.dxml b/tests/yanglint/data/modleaf.dxml new file mode 100644 index 0000000..408936a --- /dev/null +++ b/tests/yanglint/data/modleaf.dxml @@ -0,0 +1 @@ +<lfl xmlns="urn:yanglint:modleaf">7</lfl> diff --git a/tests/yanglint/data/modleaf.xml b/tests/yanglint/data/modleaf.xml new file mode 100644 index 0000000..408936a --- /dev/null +++ b/tests/yanglint/data/modleaf.xml @@ -0,0 +1 @@ +<lfl xmlns="urn:yanglint:modleaf">7</lfl> diff --git a/tests/yanglint/data/modleafref.xml b/tests/yanglint/data/modleafref.xml new file mode 100644 index 0000000..c9fb147 --- /dev/null +++ b/tests/yanglint/data/modleafref.xml @@ -0,0 +1,2 @@ +<lfl xmlns="urn:yanglint:modleaf">7</lfl> +<lfr xmlns="urn:yanglint:modleafref">7</lfr> diff --git a/tests/yanglint/data/modleafref2.xml b/tests/yanglint/data/modleafref2.xml new file mode 100644 index 0000000..3946daf --- /dev/null +++ b/tests/yanglint/data/modleafref2.xml @@ -0,0 +1,2 @@ +<lfl xmlns="urn:yanglint:modleaf">7</lfl> +<lfr xmlns="urn:yanglint:modleafref">10</lfr> diff --git a/tests/yanglint/data/modmandatory.xml b/tests/yanglint/data/modmandatory.xml new file mode 100644 index 0000000..108cb2a --- /dev/null +++ b/tests/yanglint/data/modmandatory.xml @@ -0,0 +1,3 @@ +<mmc xmlns="urn:yanglint:modmandatory"> + <lft>9</lft> +</mmc> diff --git a/tests/yanglint/data/modmandatory_invalid.xml b/tests/yanglint/data/modmandatory_invalid.xml new file mode 100644 index 0000000..de71895 --- /dev/null +++ b/tests/yanglint/data/modmandatory_invalid.xml @@ -0,0 +1,3 @@ +<mmc xmlns="urn:yanglint:modmandatory"> + <lff>9</lff> +</mmc> diff --git a/tests/yanglint/data/modmerge.xml b/tests/yanglint/data/modmerge.xml new file mode 100644 index 0000000..b52eff5 --- /dev/null +++ b/tests/yanglint/data/modmerge.xml @@ -0,0 +1,4 @@ +<mmc xmlns="urn:yanglint:modmerge"> + <en>one</en> + <lm>4</lm> +</mmc> diff --git a/tests/yanglint/data/modmerge2.xml b/tests/yanglint/data/modmerge2.xml new file mode 100644 index 0000000..e7f17c4 --- /dev/null +++ b/tests/yanglint/data/modmerge2.xml @@ -0,0 +1,3 @@ +<mmc xmlns="urn:yanglint:modmerge"> + <en>zero</en> +</mmc> diff --git a/tests/yanglint/data/modmerge3.xml b/tests/yanglint/data/modmerge3.xml new file mode 100644 index 0000000..6ef857e --- /dev/null +++ b/tests/yanglint/data/modmerge3.xml @@ -0,0 +1,3 @@ +<mmc xmlns="urn:yanglint:modmerge"> + <lf>str</lf> +</mmc> diff --git a/tests/yanglint/data/modnotif.xml b/tests/yanglint/data/modnotif.xml new file mode 100644 index 0000000..81cab21 --- /dev/null +++ b/tests/yanglint/data/modnotif.xml @@ -0,0 +1,5 @@ +<con xmlns="urn:yanglint:modnotif"> + <nfn> + <lf>nested</lf> + </nfn> +</con> diff --git a/tests/yanglint/data/modnotif2.xml b/tests/yanglint/data/modnotif2.xml new file mode 100644 index 0000000..fc75b57 --- /dev/null +++ b/tests/yanglint/data/modnotif2.xml @@ -0,0 +1,3 @@ +<nfg xmlns="urn:yanglint:modnotif"> + <lf>top</lf> +</nfg> diff --git a/tests/yanglint/data/modnotif2_nc.xml b/tests/yanglint/data/modnotif2_nc.xml new file mode 100644 index 0000000..c87cfa0 --- /dev/null +++ b/tests/yanglint/data/modnotif2_nc.xml @@ -0,0 +1,6 @@ +<notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"> + <eventTime>2010-12-06T08:00:01Z</eventTime> + <nfg xmlns="urn:yanglint:modnotif"> + <lf>top</lf> + </nfg> +</notification> diff --git a/tests/yanglint/data/modnotif_ds.xml b/tests/yanglint/data/modnotif_ds.xml new file mode 100644 index 0000000..efd835b --- /dev/null +++ b/tests/yanglint/data/modnotif_ds.xml @@ -0,0 +1 @@ +<con xmlns="urn:yanglint:modnotif"></con> diff --git a/tests/yanglint/data/modnotif_nc.xml b/tests/yanglint/data/modnotif_nc.xml new file mode 100644 index 0000000..39a3440 --- /dev/null +++ b/tests/yanglint/data/modnotif_nc.xml @@ -0,0 +1,8 @@ +<notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"> + <eventTime>2010-12-06T08:00:01Z</eventTime> + <con xmlns="urn:yanglint:modnotif"> + <nfn> + <lf>nested</lf> + </nfn> + </con> +</notification> diff --git a/tests/yanglint/data/modoper_leafref_action.xml b/tests/yanglint/data/modoper_leafref_action.xml new file mode 100644 index 0000000..7ccf29f --- /dev/null +++ b/tests/yanglint/data/modoper_leafref_action.xml @@ -0,0 +1,8 @@ +<cond xmlns="urn:yanglint:modoper-leafref"> + <list> + <klf>key_val</klf> + <act> + <lfi>rw</lfi> + </act> + </list> +</cond> diff --git a/tests/yanglint/data/modoper_leafref_action_reply.xml b/tests/yanglint/data/modoper_leafref_action_reply.xml new file mode 100644 index 0000000..39ec672 --- /dev/null +++ b/tests/yanglint/data/modoper_leafref_action_reply.xml @@ -0,0 +1,8 @@ +<cond xmlns="urn:yanglint:modoper-leafref"> + <list> + <klf>key_val</klf> + <act> + <lfo>rw</lfo> + </act> + </list> +</cond> diff --git a/tests/yanglint/data/modoper_leafref_ds.xml b/tests/yanglint/data/modoper_leafref_ds.xml new file mode 100644 index 0000000..f934b9b --- /dev/null +++ b/tests/yanglint/data/modoper_leafref_ds.xml @@ -0,0 +1,9 @@ +<mcc xmlns="urn:yanglint:modconfig"> + <lft>rw</lft> + <lff>ro</lff> +</mcc> +<cond xmlns="urn:yanglint:modoper-leafref"> + <list> + <klf>key_val</klf> + </list> +</cond> diff --git a/tests/yanglint/data/modoper_leafref_notif.xml b/tests/yanglint/data/modoper_leafref_notif.xml new file mode 100644 index 0000000..2c56b67 --- /dev/null +++ b/tests/yanglint/data/modoper_leafref_notif.xml @@ -0,0 +1,3 @@ +<notifg xmlns="urn:yanglint:modoper-leafref"> + <lfr>rw</lfr> +</notifg> diff --git a/tests/yanglint/data/modoper_leafref_notif2.xml b/tests/yanglint/data/modoper_leafref_notif2.xml new file mode 100644 index 0000000..466697c --- /dev/null +++ b/tests/yanglint/data/modoper_leafref_notif2.xml @@ -0,0 +1,8 @@ +<cond xmlns="urn:yanglint:modoper-leafref"> + <list> + <klf>key_val</klf> + <notif> + <lfn>rw</lfn> + </notif> + </list> +</cond> diff --git a/tests/yanglint/data/modoper_leafref_notif_err.xml b/tests/yanglint/data/modoper_leafref_notif_err.xml new file mode 100644 index 0000000..1622ded --- /dev/null +++ b/tests/yanglint/data/modoper_leafref_notif_err.xml @@ -0,0 +1,7 @@ +<mcc xmlns="urn:yanglint:modconfig"> + <lft>rw</lft> + <lff>ro</lff> +</mcc> +<notifg xmlns="urn:yanglint:modoper-leafref"> + <lf>rw</lf> +</notifg> diff --git a/tests/yanglint/data/modoper_leafref_rpc.xml b/tests/yanglint/data/modoper_leafref_rpc.xml new file mode 100644 index 0000000..b294544 --- /dev/null +++ b/tests/yanglint/data/modoper_leafref_rpc.xml @@ -0,0 +1,3 @@ +<rpcg xmlns="urn:yanglint:modoper-leafref"> + <lfi>rw</lfi> +</rpcg> diff --git a/tests/yanglint/data/modoper_leafref_rpc_reply.xml b/tests/yanglint/data/modoper_leafref_rpc_reply.xml new file mode 100644 index 0000000..e8f7af3 --- /dev/null +++ b/tests/yanglint/data/modoper_leafref_rpc_reply.xml @@ -0,0 +1,5 @@ +<rpcg xmlns="urn:yanglint:modoper-leafref"> + <cono> + <lfo>rw</lfo> + </cono> +</rpcg> diff --git a/tests/yanglint/data/modrpc.xml b/tests/yanglint/data/modrpc.xml new file mode 100644 index 0000000..a4f924d --- /dev/null +++ b/tests/yanglint/data/modrpc.xml @@ -0,0 +1,3 @@ +<rpc xmlns="urn:yanglint:modrpc"> + <lfi>some_input</lfi> +</rpc> diff --git a/tests/yanglint/data/modrpc_nc.xml b/tests/yanglint/data/modrpc_nc.xml new file mode 100644 index 0000000..78d3149 --- /dev/null +++ b/tests/yanglint/data/modrpc_nc.xml @@ -0,0 +1,6 @@ +<rpc message-id="101" + xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> + <rpc xmlns="urn:yanglint:modrpc"> + <lfi>some_input</lfi> + </rpc> +</rpc> diff --git a/tests/yanglint/data/modrpc_reply.xml b/tests/yanglint/data/modrpc_reply.xml new file mode 100644 index 0000000..632971c --- /dev/null +++ b/tests/yanglint/data/modrpc_reply.xml @@ -0,0 +1,5 @@ +<rpc xmlns="urn:yanglint:modrpc"> + <con> + <lfo>-56</lfo> + </con> +</rpc> diff --git a/tests/yanglint/data/modrpc_reply_nc.xml b/tests/yanglint/data/modrpc_reply_nc.xml new file mode 100644 index 0000000..da2a01c --- /dev/null +++ b/tests/yanglint/data/modrpc_reply_nc.xml @@ -0,0 +1,6 @@ +<rpc-reply message-id="101" + xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> + <con xmlns="urn:yanglint:modrpc"> + <lfo>-56</lfo> + </con> +</rpc-reply> diff --git a/tests/yanglint/data/modsm.xml b/tests/yanglint/data/modsm.xml new file mode 100644 index 0000000..bb0793c --- /dev/null +++ b/tests/yanglint/data/modsm.xml @@ -0,0 +1,3 @@ +<root xmlns="urn:yanglint:modsm"> + <lfl xmlns="urn:yanglint:modleaf">7</lfl> +</root> diff --git a/tests/yanglint/data/modsm2.xml b/tests/yanglint/data/modsm2.xml new file mode 100644 index 0000000..ff6f103 --- /dev/null +++ b/tests/yanglint/data/modsm2.xml @@ -0,0 +1,4 @@ +<root xmlns="urn:yanglint:modsm"> + <lfl xmlns="urn:yanglint:modleaf">7</lfl> + <alf xmlns="urn:yanglint:modsm-augment">str</alf> +</root> diff --git a/tests/yanglint/data/modsm_ctx_ext.xml b/tests/yanglint/data/modsm_ctx_ext.xml new file mode 100644 index 0000000..e80141a --- /dev/null +++ b/tests/yanglint/data/modsm_ctx_ext.xml @@ -0,0 +1,20 @@ +<yang-library xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library"> + <module-set> + <name>test-set</name> + <module> + <name>modleaf</name> + <namespace>urn:yanglint:modleaf</namespace> + </module> + </module-set> + <content-id>1</content-id> +</yang-library> +<modules-state xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library"> + <module-set-id>1</module-set-id> +</modules-state> +<schema-mounts xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount"> + <mount-point> + <module>modsm</module> + <label>root</label> + <inline></inline> + </mount-point> +</schema-mounts> diff --git a/tests/yanglint/data/modsm_ctx_main.xml b/tests/yanglint/data/modsm_ctx_main.xml new file mode 100644 index 0000000..5405d4d --- /dev/null +++ b/tests/yanglint/data/modsm_ctx_main.xml @@ -0,0 +1,17 @@ +<yang-library xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library"> + <module-set> + <name>main-set</name> + <module> + <name>modsm</name> + <namespace>urn:yanglint:modsm</namespace> + </module> + <module> + <name>modsm-augment</name> + <namespace>urn:yanglint:modsm-augment</namespace> + </module> + </module-set> + <content-id>1</content-id> +</yang-library> +<modules-state xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library"> + <module-set-id>1</module-set-id> +</modules-state> diff --git a/tests/yanglint/interactive/add.test b/tests/yanglint/interactive/add.test new file mode 100644 index 0000000..d1cacc1 --- /dev/null +++ b/tests/yanglint/interactive/add.test @@ -0,0 +1,59 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/interactive/ly.tcl" : "ly.tcl"}] + +set mdir $::env(YANG_MODULES_DIR) + +test add_basic {} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "add $mdir/modleafref.yang" + ly_cmd "list" "I modleafref\r.*I modleaf" +}} + +test add_disable_searchdir_once {add --disable-searchdir} { +-setup $ly_setup -cleanup $ly_cleanup -constraints {!ctest} -body { + ly_cmd "add $mdir/modimp-cwd.yang" + ly_cmd "clear" + ly_cmd_err "add -D $mdir/modimp-cwd.yang" "not found in local searchdirs" +}} + +test add_disable_searchdir_twice {add -D -D} { +-setup $ly_setup -cleanup $ly_cleanup -constraints {!ctest} -body { + ly_cmd "add $mdir/ietf-ip.yang" + ly_cmd "clear" + ly_cmd_err "add -D -D $mdir/ietf-ip.yang" "Loading \"ietf-interfaces\" module failed." +}} + +test add_with_feature {Add module with feature} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "add --feature modfeature:ftr2 $mdir/modfeature.yang" + ly_cmd "feature -a" "modfeature:\r\n\tftr1 \\(off\\)\r\n\tftr2 \\(on\\)" +}} + +test add_make_implemented_once {add --make-implemented} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_ignore "add $mdir/modmust.yang" + ly_cmd "list" "I modmust\r.*i modleaf" + ly_cmd "clear" + ly_ignore "add -i $mdir/modmust.yang" + ly_cmd "list" "I modmust\r.*I modleaf" +}} + +test add_make_implemented_twice {add -i -i} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "add $mdir/modimp-type.yang" + ly_cmd "list" "I modimp-type\r.*i modtypedef" + ly_cmd "clear" + ly_cmd "add -i -i $mdir/modimp-type.yang" + ly_cmd "list" "I modimp-type\r.*I modtypedef" +}} + +test add_extended_leafref_enabled {Valid module with --extended-leafref option} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "add -X $mdir/modextleafref.yang" +}} + +test add_extended_leafref_disabled {Expected error if --extended-leafref is not set} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd_err "add $mdir/modextleafref.yang" "Unexpected XPath token \"FunctionName\"" +}} + +cleanupTests diff --git a/tests/yanglint/interactive/all.tcl b/tests/yanglint/interactive/all.tcl new file mode 100644 index 0000000..b22a5ab --- /dev/null +++ b/tests/yanglint/interactive/all.tcl @@ -0,0 +1,15 @@ +package require tcltest + +# Hook to determine if any of the tests failed. +# Sets a global variable exitCode to 1 if any test fails otherwise it is set to 0. +proc tcltest::cleanupTestsHook {} { + variable numTests + set ::exitCode [expr {$numTests(Failed) > 0}] +} + +if {[info exists ::env(TESTS_DIR)]} { + tcltest::configure -testdir "$env(TESTS_DIR)/interactive" +} + +tcltest::runAllTests +exit $exitCode diff --git a/tests/yanglint/interactive/clear.test b/tests/yanglint/interactive/clear.test new file mode 100644 index 0000000..cac0810 --- /dev/null +++ b/tests/yanglint/interactive/clear.test @@ -0,0 +1,53 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/interactive/ly.tcl" : "ly.tcl"}] + +set mdir $::env(YANG_MODULES_DIR) +set ddir $::env(TESTS_DIR)/data + +test clear_searchpath {searchpath is also deleted} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "searchpath ./" + ly_cmd "clear" + ly_cmd "searchpath" "List of the searchpaths:" -ex +}} + +test clear_make_implemented_once {clear --make-implemented} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "clear -i" + ly_cmd "add $mdir/modmust.yang" + ly_cmd "list" "I modmust\r.*I modleaf" +}} + +test clear_make_implemented_twice {clear -i -i} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "clear -i -i" + ly_cmd "add $mdir/modmust.yang" + ly_cmd "list" "I modmust\r.*I modleaf" +}} + +test clear_ietf_yang_library {clear --yang-library} { +-setup $ly_setup -cleanup $ly_cleanup -body { + # add models + ly_cmd "clear -y" + ly_cmd "list" "I ietf-yang-library" +}} + +test clear_ylf_list {apply --yang-library-file and check result by --list} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "clear -Y $ddir/modimp_type_ctx.xml" + ly_cmd "list" "I modimp-type.*i modtypedef" +}} + +test clear_ylf_make_implemented {apply --yang-library-file and --make-implemented} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "clear -Y $ddir/modimp_type_ctx.xml -i -i" + ly_cmd "list" "I modimp-type.*I modtypedef" +}} + +test clear_ylf_augment_ctx {Setup context by yang-library-file and augment module} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "clear -Y $ddir/modconfig_ctx.xml" + ly_cmd "add $mdir/modconfig-augment.yang" + ly_cmd "print -f tree modconfig" "mca:alf" +}} + +cleanupTests diff --git a/tests/yanglint/interactive/completion.test b/tests/yanglint/interactive/completion.test new file mode 100644 index 0000000..86ded1f --- /dev/null +++ b/tests/yanglint/interactive/completion.test @@ -0,0 +1,69 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/interactive/ly.tcl" : "ly.tcl"}] + +set mdir "$::env(YANG_MODULES_DIR)" + +variable ly_cleanup { + ly_ignore + ly_exit +} + +test completion_hints_ietf_ip {Completion and hints for ietf-ip.yang} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "add $mdir/ietf-ip.yang" + + # completion and hint + ly_completion "print -f info -P " "print -f info -P /ietf-" + + set hints {"/ietf-yang-schema-mount:schema-mounts" "/ietf-interfaces:interfaces" "/ietf-interfaces:interfaces-state"} + ly_hint "" "print -f info -P /ietf-" $hints + + # double completion + ly_completion "i" "print -f info -P /ietf-interfaces:interfaces" + ly_completion "/" "print -f info -P /ietf-interfaces:interfaces/interface" + + # a lot of hints + set hints {"/ietf-interfaces:interfaces/interface" + "/ietf-interfaces:interfaces/interface/name" "/ietf-interfaces:interfaces/interface/description" + "/ietf-interfaces:interfaces/interface/type" "/ietf-interfaces:interfaces/interface/enabled" + "/ietf-interfaces:interfaces/interface/link-up-down-trap-enable" + "/ietf-interfaces:interfaces/interface/ietf-ip:ipv4" "/ietf-interfaces:interfaces/interface/ietf-ip:ipv6" + } + ly_hint "" "print -f info -P /ietf-interfaces:interfaces/interface" $hints + + # double tab + ly_completion "/i" "print -f info -P /ietf-interfaces:interfaces/interface/ietf-ip:ipv" + ly_completion "4" "print -f info -P /ietf-interfaces:interfaces/interface/ietf-ip:ipv4" + set hints { "/ietf-interfaces:interfaces/interface/ietf-ip:ipv4" "/ietf-interfaces:interfaces/interface/ietf-ip:ipv4/enabled" + "/ietf-interfaces:interfaces/interface/ietf-ip:ipv4/forwarding" "/ietf-interfaces:interfaces/interface/ietf-ip:ipv4/mtu" + "/ietf-interfaces:interfaces/interface/ietf-ip:ipv4/address" "/ietf-interfaces:interfaces/interface/ietf-ip:ipv4/neighbor" + } + ly_hint "\t" "print -f info -P /ietf-interfaces:interfaces/interface/ietf-ip:ipv" $hints + + # no more completion + ly_completion "/e" "print -f info -P /ietf-interfaces:interfaces/interface/ietf-ip:ipv4/enabled " +}} + +# Note that somehow a command is automatically sent again (\t\t replaced by \r) after the hints. +# But that doesn't affect the test because the tests only focus on the word in the hint. + +test hint_data_file {Show file hints for command data} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_hint "data $mdir\t\t" "data $mdir" "modleaf.yang.*" +}} + +test hint_data_format {Show print hints for command data --format} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_hint "data -f \t\t" "data -f " "xml.*" +}} + +test hint_data_file_after_opt {Show file hints after option with argument} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_hint "data -f xml $mdir\t\t" "data -f xml $mdir" "modleaf.yang.*" +}} + +test hint_data_file_after_opt2 {Show file hints after option without argument} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_hint "data -m $mdir\t\t" "data -m $mdir" "modleaf.yang.*" +}} + +cleanupTests diff --git a/tests/yanglint/interactive/data_default.test b/tests/yanglint/interactive/data_default.test new file mode 100644 index 0000000..1953acc --- /dev/null +++ b/tests/yanglint/interactive/data_default.test @@ -0,0 +1,41 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/interactive/ly.tcl" : "ly.tcl"}] + +set mods "ietf-netconf-with-defaults moddefault" +set data "$::env(TESTS_DIR)/data/moddefault.xml" + +test data_default_not_set {Print data without --default parameter} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load $mods" + ly_cmd "data -f xml $data" "</lf>.*</di>\r\n</mdc>" + ly_cmd "data -f json $data" "lf\".*di\"\[^\"]*" +}} + +test data_default_all {data --default all} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load $mods" + ly_cmd "data -d all -f xml $data" "</lf>.*</di>.*</ds>\r\n</mdc>" + ly_cmd "data -d all -f json $data" "lf\".*di\".*ds\"\[^\"]*" +}} + +test data_default_all_tagged {data --default all-tagged} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load $mods" + ly_cmd "data -d all-tagged -f xml $data" "</lf>.*<di.*default.*</di>.*<ds.*default.*</ds>\r\n</mdc>" + ly_cmd "data -d all-tagged -f json $data" "lf\".*di\".*ds\".*@ds\".*default\"\[^\"]*" +}} + +test data_default_trim {data --default trim} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load $mods" + ly_cmd "data -d trim -f xml $data" "</lf>\r\n</mdc>" + ly_cmd "data -d trim -f json $data" "lf\"\[^\"]*" +}} + +test data_default_implicit_tagged {data --default implicit-tagged} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load $mods" + ly_cmd "data -d implicit-tagged -f xml $data" "</lf>.*<di>5</di>.*<ds.*default.*</ds>\r\n</mdc>" + ly_cmd "data -d implicit-tagged -f json $data" "lf\".*di\"\[^@]*ds\".*default\"\[^\"]*" +}} + +cleanupTests diff --git a/tests/yanglint/interactive/data_format.test b/tests/yanglint/interactive/data_format.test new file mode 100644 index 0000000..dc4b7e0 --- /dev/null +++ b/tests/yanglint/interactive/data_format.test @@ -0,0 +1,23 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/interactive/ly.tcl" : "ly.tcl"}] + +set ddir "$::env(TESTS_DIR)/data" + +test data_format_xml {Print data in xml format} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modleaf" + ly_cmd "data -f xml $ddir/modleaf.xml" "<lfl xmlns=\"urn:yanglint:modleaf\">7</lfl>" +}} + +test data_format_json {Print data in json format} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modleaf" + ly_cmd "data -f json $ddir/modleaf.xml" "{\r\n \"modleaf:lfl\": 7\r\n}" +}} + +test data_format_lyb_err {Print data in lyb format} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modleaf" + ly_cmd_err "data -f lyb $ddir/modleaf.xml" "The LYB format requires the -o" +}} + +cleanupTests diff --git a/tests/yanglint/interactive/data_in_format.test b/tests/yanglint/interactive/data_in_format.test new file mode 100644 index 0000000..cc5f37e --- /dev/null +++ b/tests/yanglint/interactive/data_in_format.test @@ -0,0 +1,21 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/interactive/ly.tcl" : "ly.tcl"}] + +set ddir "$::env(TESTS_DIR)/data" + +test data_in_format_xml {--in-format xml} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modleaf" + ly_cmd "data -F xml $ddir/modleaf.dxml" + ly_cmd_err "data -F json $ddir/modleaf.dxml" "Failed to parse" + ly_cmd_err "data -F lyb $ddir/modleaf.dxml" "Failed to parse" +}} + +test data_in_format_json {--in-format json} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modleaf" + ly_cmd "data -F json $ddir/modleaf.djson" + ly_cmd_err "data -F xml $ddir/modleaf.djson" "Failed to parse" + ly_cmd_err "data -F lyb $ddir/modleaf.djson" "Failed to parse" +}} + +cleanupTests diff --git a/tests/yanglint/interactive/data_merge.test b/tests/yanglint/interactive/data_merge.test new file mode 100644 index 0000000..38754c7 --- /dev/null +++ b/tests/yanglint/interactive/data_merge.test @@ -0,0 +1,33 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/interactive/ly.tcl" : "ly.tcl"}] + +set ddir "$::env(TESTS_DIR)/data" + +test data_merge_basic {Data is merged and the node is added} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modmerge" + ly_cmd "data -m -f xml $ddir/modmerge.xml $ddir/modmerge3.xml" "<en>.*<lm>.*<lf>" +}} + +test data_merge_validation_failed {Data is merged but validation failed.} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modmerge" + ly_cmd "data $ddir/modmerge.xml" + ly_cmd "data $ddir/modmerge2.xml" + ly_cmd "data -m $ddir/modmerge2.xml $ddir/modmerge.xml" + ly_cmd_err "data -m $ddir/modmerge.xml $ddir/modmerge2.xml" "Merged data are not valid" +}} + +test data_merge_dataconfig {The merge option has effect only for 'data' and 'config' TYPEs} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modrpc modnotif modconfig modleaf" + set wrn1 "option has effect only for" + ly_cmd_wrn "data -m -t rpc $ddir/modrpc.xml $ddir/modrpc.xml" $wrn1 + ly_cmd_wrn "data -m -t notif $ddir/modnotif2.xml $ddir/modnotif2.xml" $wrn1 + ly_cmd_wrn "data -m -t get $ddir/modleaf.xml $ddir/modconfig.xml" $wrn1 + ly_cmd_wrn "data -m -t getconfig $ddir/modleaf.xml $ddir/modconfig2.xml" $wrn1 + ly_cmd_wrn "data -m -t edit $ddir/modleaf.xml $ddir/modconfig2.xml" $wrn1 + ly_cmd "data -m -t config $ddir/modleaf.xml $ddir/modconfig2.xml" + ly_cmd "data -m -t data $ddir/modleaf.xml $ddir/modconfig.xml" +}} + +cleanupTests diff --git a/tests/yanglint/interactive/data_not_strict.test b/tests/yanglint/interactive/data_not_strict.test new file mode 100644 index 0000000..201a5a9 --- /dev/null +++ b/tests/yanglint/interactive/data_not_strict.test @@ -0,0 +1,25 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/interactive/ly.tcl" : "ly.tcl"}] + +set ddir $::env(TESTS_DIR)/data + +test data_no_strict_basic {} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modleaf" + ly_cmd_err "data $ddir/modmandatory.xml" "No module with namespace \"urn:yanglint:modmandatory\" in the context." + ly_cmd "data -n $ddir/modmandatory.xml" +}} + +test data_no_strict_invalid_data {validation with --no-strict but data are invalid} { +-setup $ly_setup -cleanup $ly_cleanup -body { + set errmsg "Mandatory node \"lft\" instance does not exist." + ly_cmd "load modmandatory" + ly_cmd_err "data -n $ddir/modmandatory_invalid.xml" $errmsg +}} + +test data_no_strict_ignore_invalid_data {--no-strict ignore invalid data if no schema is provided} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modleaf" + ly_cmd "data -f xml -n $ddir/modmandatory_invalid.xml $ddir/modleaf.xml" "modleaf.*</lfl>$" +}} + +cleanupTests diff --git a/tests/yanglint/interactive/data_operational.test b/tests/yanglint/interactive/data_operational.test new file mode 100644 index 0000000..c0c7b1c --- /dev/null +++ b/tests/yanglint/interactive/data_operational.test @@ -0,0 +1,86 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/interactive/ly.tcl" : "ly.tcl"}] + +set ddir "$::env(TESTS_DIR)/data" +set err1 "Operational datastore takes effect only with RPCs/Actions/Replies/Notification input data types" + +test data_operational_twice {it is not allowed to specify more than one --operational parameter} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modoper-leafref" + ly_cmd "data -t notif -O $ddir/modconfig.xml -O $ddir/modleaf.xml" "cannot be set multiple times" +}} + +test data_operational_no_type {--operational should be with parameter --type} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modoper-leafref" + ly_cmd_wrn "data -O $ddir/modconfig.xml $ddir/modoper_leafref_notif.xml" $err1 +}} + +test data_operational_missing {--operational is omitted and the datastore contents is in the data file} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modoper-leafref" + ly_cmd_err "data $ddir/modoper_leafref_notif_err.xml" "Failed to parse input data file" +}} + +test data_operational_wrong_type {data are not defined as an operation} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd_wrn "data -t data -O $ddir/modconfig.xml $ddir/modleaf.xml" $err1 +}} + +test data_operational_datastore_with_unknown_data {unknown data are ignored} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modrpc" + ly_cmd "data -t rpc -O $ddir/modmandatory_invalid.xml $ddir/modrpc.xml" +}} + +test data_operational_empty_datastore {datastore is considered empty because it contains unknown data} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modrpc modnotif" + ly_cmd "data -t rpc -O $ddir/modmandatory_invalid.xml $ddir/modrpc.xml" + set msg "parent \"/modnotif:con\" not found in the operational data" + ly_cmd_err "data -t notif -O $ddir/modmandatory_invalid.xml $ddir/modnotif.xml" $msg +}} + +test data_operational_notif_leafref {--operational data is referenced from notification-leafref} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modoper-leafref" + ly_cmd "data -t notif -O $ddir/modconfig.xml $ddir/modoper_leafref_notif.xml" +}} + +test data_operational_nested_notif_leafref {--operational data is referenced from nested-notification-leafref} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modoper-leafref" + ly_cmd "data -t notif -O $ddir/modoper_leafref_ds.xml $ddir/modoper_leafref_notif2.xml" +}} + +test data_operational_nested_notif_parent_missing {--operational data are invalid due to missing parent node} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modoper-leafref" + set msg "klf='key_val']\" not found in the operational data" + ly_cmd_err "data -t notif -O $ddir/modconfig.xml $ddir/modoper_leafref_notif2.xml" $msg +}} + +test data_operational_action_leafref {--operational data is referenced from action-leafref} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modoper-leafref" + ly_cmd "data -t rpc -O $ddir/modoper_leafref_ds.xml $ddir/modoper_leafref_action.xml" +}} + +test data_operational_action_reply_leafref {--operational data is referenced from action-leafref output} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modoper-leafref" + ly_cmd "data -t reply -O $ddir/modoper_leafref_ds.xml $ddir/modoper_leafref_action_reply.xml" +}} + +test data_operational_rpc_leafref {--operational data is referenced from rpc-leafref} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modoper-leafref" + ly_cmd "data -t rpc -O $ddir/modconfig.xml $ddir/modoper_leafref_rpc.xml" +}} + +test data_operational_rpc_reply_leafref {--operational data is referenced from rpc-leafref output} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modoper-leafref" + ly_cmd "data -t reply -O $ddir/modconfig.xml $ddir/modoper_leafref_rpc_reply.xml" +}} + +cleanupTests diff --git a/tests/yanglint/interactive/data_present.test b/tests/yanglint/interactive/data_present.test new file mode 100644 index 0000000..4bba596 --- /dev/null +++ b/tests/yanglint/interactive/data_present.test @@ -0,0 +1,25 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/interactive/ly.tcl" : "ly.tcl"}] + +set ddir "$::env(TESTS_DIR)/data" + +test data_present_via_mandatory {validation of mandatory-stmt will pass only with the --present} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modleaf modmandatory" + ly_cmd_err "data $ddir/modleaf.xml" "Mandatory node \"lft\" instance does not exist." + ly_cmd "data -e $ddir/modleaf.xml" +}} + +test data_present_merge {validation with --present and --merge} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modleaf modmandatory moddefault" + ly_cmd_err "data -m $ddir/modleaf.xml $ddir/moddefault.xml" "Mandatory node \"lft\" instance does not exist." + ly_cmd "data -e -m $ddir/modleaf.xml $ddir/moddefault.xml" +}} + +test data_present_merge_invalid {using --present and --merge but data are invalid} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modleaf modmandatory" + ly_cmd_err "data -e -m $ddir/modleaf.xml $ddir/modmandatory_invalid.xml" "Mandatory node \"lft\" instance does not exist." +}} + +cleanupTests diff --git a/tests/yanglint/interactive/data_type.test b/tests/yanglint/interactive/data_type.test new file mode 100644 index 0000000..a442813 --- /dev/null +++ b/tests/yanglint/interactive/data_type.test @@ -0,0 +1,140 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/interactive/ly.tcl" : "ly.tcl"}] + +set ddir "$::env(TESTS_DIR)/data" + +test data_type_data {data --type data} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modconfig" + ly_cmd "data -t data $ddir/modconfig.xml" +}} + +test data_type_config {data --type config} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modconfig" + ly_cmd_err "data -t config $ddir/modconfig.xml" "Unexpected data state node \"lff\"" + ly_cmd "data -t config $ddir/modconfig2.xml" +}} + +test data_type_get {data --type get} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modleafref" + ly_cmd_err "data -t data $ddir/modleafref2.xml" "Invalid leafref value" + ly_cmd "data -t get $ddir/modleafref2.xml" +}} + +test data_type_getconfig_no_state {No state node for data --type getconfig} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modconfig" + ly_cmd_err "data -t getconfig $ddir/modconfig.xml" "Unexpected data state node \"lff\"" + ly_cmd "data -t getconfig $ddir/modconfig2.xml" +}} + +test data_type_getconfig_parse_only {No validation performed for data --type getconfig} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modleafref" + ly_cmd_err "data -t data $ddir/modleafref2.xml" "Invalid leafref value" + ly_cmd "data -t getconfig $ddir/modleafref2.xml" +}} + +test data_type_edit_no_state {No state node for data --type edit} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modconfig" + ly_cmd_err "data -t edit $ddir/modconfig.xml" "Unexpected data state node \"lff\"" + ly_cmd "data -t edit $ddir/modconfig2.xml" +}} + +test data_type_edit_parse_only {No validation performed for data --type edit} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modleafref" + ly_cmd_err "data -t data $ddir/modleafref2.xml" "Invalid leafref value" + ly_cmd "data -t edit $ddir/modleafref2.xml" +}} + +test data_type_rpc {Validation of rpc-statement by data --type rpc} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modrpc modleaf" + ly_cmd_err "data -t rpc $ddir/modleaf.xml" "Missing the operation node." + ly_cmd "data -t rpc $ddir/modrpc.xml" +}} + +test data_type_rpc_nc {Validation of rpc-statement by data --type nc-rpc} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modrpc modleaf ietf-netconf" + ly_cmd_err "data -t nc-rpc $ddir/modleaf.xml" "Missing NETCONF <rpc> envelope" + ly_cmd "data -t nc-rpc $ddir/modrpc_nc.xml" +}} + +test data_type_rpc_reply {Validation of rpc-reply by data --type reply} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modrpc modleaf" + ly_cmd_err "data -t rpc $ddir/modleaf.xml" "Missing the operation node." + ly_cmd_wrn "data -t reply -R $ddir/modrpc.xml $ddir/modrpc_reply.xml" "needed only for NETCONF" + ly_cmd "data -t reply $ddir/modrpc_reply.xml" +}} + +test data_type_rpc_reply_nc {Validation of rpc-reply by data --type nc-reply} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modrpc modleaf" + ly_cmd_err "data -t nc-reply -R $ddir/modrpc_nc.xml $ddir/modleaf.xml" "Missing NETCONF <rpc-reply> envelope" + ly_cmd_err "data -t nc-reply $ddir/modrpc_reply_nc.xml" "Missing source RPC" + ly_cmd "data -t nc-reply -R $ddir/modrpc_nc.xml $ddir/modrpc_reply_nc.xml" +}} + +test data_type_rpc_action {Validation of action-statement by data --type rpc} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modaction modleaf" + ly_cmd_err "data -t rpc $ddir/modleaf.xml" "Missing the operation node." + ly_cmd "data -t rpc -O $ddir/modaction_ds.xml $ddir/modaction.xml" +}} + +test data_type_rpc_action_nc {Validation of action-statement by data --type nc-rpc} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modaction modleaf" + ly_cmd_err "data -t nc-rpc $ddir/modleaf.xml" "Missing NETCONF <rpc> envelope" + ly_cmd "data -t nc-rpc -O $ddir/modaction_ds.xml $ddir/modaction_nc.xml" +}} + +test data_type_rpc_action_reply {Validation of action-reply by data --type reply} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modaction modleaf" + ly_cmd_err "data -t rpc $ddir/modleaf.xml" "Missing the operation node." + ly_cmd "data -t reply -O $ddir/modaction_ds.xml $ddir/modaction_reply.xml" +}} + +test data_type_rpc_action_reply_nc {Validation of action-reply by data --type nc-reply} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modaction modleaf" + ly_cmd_err "data -t nc-reply -R $ddir/modaction_nc.xml $ddir/modleaf.xml" "Missing NETCONF <rpc-reply> envelope" + ly_cmd_err "data -t nc-reply $ddir/modaction_reply_nc.xml" "Missing source RPC" + ly_cmd_err "data -t nc-reply -R $ddir/modaction_nc.xml $ddir/modaction_reply_nc.xml" "operational parameter needed" + ly_cmd "data -t nc-reply -O $ddir/modaction_ds.xml -R $ddir/modaction_nc.xml $ddir/modaction_reply_nc.xml" +}} + +test data_type_notif {Validation of notification-statement by data --type notif} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modnotif modleaf" + ly_cmd_err "data -t notif $ddir/modleaf.xml" "Missing the operation node." + ly_cmd "data -t notif $ddir/modnotif2.xml" +}} + +test data_type_notif_nc {Validation of notification-statement by data --type nc-notif} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modnotif modleaf ietf-netconf" + ly_cmd_err "data -t nc-notif $ddir/modleaf.xml" "Missing NETCONF <notification> envelope" + ly_cmd "data -t nc-notif $ddir/modnotif2_nc.xml" +}} + +test data_type_notif_nested {Validation of nested-notification-statement by data --type notif} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modnotif modleaf" + ly_cmd "data -t notif -O $ddir/modnotif_ds.xml $ddir/modnotif.xml" +}} + +test data_type_notif_nested_nc {Validation of nested-notification-statement by data --type nc-notif} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modnotif modleaf ietf-netconf" + ly_cmd_err "data -t nc-notif $ddir/modleaf.xml" "Missing NETCONF <notification> envelope" + ly_cmd "data -t nc-notif -O $ddir/modnotif_ds.xml $ddir/modnotif_nc.xml" +}} + +cleanupTests diff --git a/tests/yanglint/interactive/data_xpath.test b/tests/yanglint/interactive/data_xpath.test new file mode 100644 index 0000000..398cb9f --- /dev/null +++ b/tests/yanglint/interactive/data_xpath.test @@ -0,0 +1,57 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/interactive/ly.tcl" : "ly.tcl"}] + +set data "$::env(TESTS_DIR)/data/moddatanodes.xml" + +test data_xpath_empty {--xpath to missing node} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load moddatanodes" + ly_cmd "data -x /moddatanodes:dnc/mis $data" "Empty" +}} + +test data_xpath_leaf {--xpath to leaf node} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load moddatanodes" + ly_cmd "data -x /moddatanodes:dnc/lf $data" "leaf \"lf\" \\(value: \"x\"\\)" +}} + +test data_xpath_leaflist {--xpath to leaf-list node} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load moddatanodes" + set r1 "leaf-list \"lfl\" \\(value: \"1\"\\)" + set r2 "leaf-list \"lfl\" \\(value: \"2\"\\)" + ly_cmd "data -x /moddatanodes:dnc/lfl $data" "$r1\r\n $r2" +}} + +test data_xpath_list {--xpath to list} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load moddatanodes" + set r1 "list \"lt\" \\(\"kalf\": \"ka1\"; \"kblf\": \"kb1\";\\)" + set r2 "list \"lt\" \\(\"kalf\": \"ka2\"; \"kblf\": \"kb2\";\\)" + ly_cmd "data -x /moddatanodes:dnc/con/lt $data" "$r1\r\n $r2" +}} + +test data_xpath_container {--xpath to container} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load moddatanodes" + ly_cmd "data -x /moddatanodes:dnc/con $data" "container \"con\"" +}} + +test data_xpath_wrong_path {--xpath to a non-existent node} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load moddatanodes" + ly_cmd_err "data -x /moddatanodes:dnc/wrng $data" "xpath failed" +}} + +test data_xpath_err_format {--xpath cannot be combined with --format} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load moddatanodes" + ly_cmd_err "data -f xml -x /moddatanodes:dnc/lf $data" "option cannot be combined" +}} + +test data_xpath_err_default {--xpath cannot be combined with --default} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load moddatanodes ietf-netconf-with-defaults" + ly_cmd_err "data -d all -x /moddatanodes:dnc/lf $data" "option cannot be combined" +}} + +cleanupTests diff --git a/tests/yanglint/interactive/debug.test b/tests/yanglint/interactive/debug.test new file mode 100644 index 0000000..8a64c92 --- /dev/null +++ b/tests/yanglint/interactive/debug.test @@ -0,0 +1,33 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/interactive/ly.tcl" : "ly.tcl"}] + +set mdir $::env(YANG_MODULES_DIR) + +test debug_dict {Check debug message DICT} { +-setup $ly_setup -cleanup $ly_cleanup -constraints {[yanglint_debug]} -body { + ly_cmd "verb debug" + ly_cmd "debug dict" + ly_cmd "load modleaf" "DICT" +}} + +test debug_xpath {Check debug message XPATH} { +-setup $ly_setup -cleanup $ly_cleanup -constraints {[yanglint_debug]} -body { + ly_cmd "verb debug" + ly_cmd "debug xpath" + ly_cmd "load modmust" "XPATH" +}} + +test debug_dep_sets {Check debug message DEPSETS} { +-setup $ly_setup -cleanup $ly_cleanup -constraints {[yanglint_debug]} -body { + ly_cmd "verb debug" + ly_cmd "debug dep-sets" + ly_cmd "load modleaf" "DEPSETS" +}} + +test debug_depsets_xpath {Check debug message DEPSETS and XPATH} { +-setup $ly_setup -cleanup $ly_cleanup -constraints {[yanglint_debug]} -body { + ly_cmd "verb debug" + ly_cmd "debug dep-sets xpath" + ly_cmd "load modmust" "DEPSETS.*XPATH" +}} + +cleanupTests diff --git a/tests/yanglint/interactive/extdata.test b/tests/yanglint/interactive/extdata.test new file mode 100644 index 0000000..e253d1a --- /dev/null +++ b/tests/yanglint/interactive/extdata.test @@ -0,0 +1,63 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/interactive/ly.tcl" : "ly.tcl"}] + +set mdir "$::env(YANG_MODULES_DIR)" +set ddir "$::env(TESTS_DIR)/data" + +test extdata_set_clear {Set and clear extdata file} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "extdata" "No file set" + ly_cmd "extdata $ddir/modsm_ctx_ext.xml" + ly_cmd "extdata" "$ddir/modsm_ctx_ext.xml" + ly_cmd "extdata -c" + ly_cmd "extdata" "No file set" +}} + +test extdata_clear_cmd {Clear extdata file by 'clear' command} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "extdata $ddir/modsm_ctx_ext.xml" + ly_cmd "clear" + ly_cmd "extdata" "No file set" +}} + +test extdata_one_only {Only one file for extdata} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd_err "extdata $ddir/modsm_ctx_ext.xml $ddir/modsm_ctx_ext.xml" "Only one file must be entered" +}} + +test extdata_schema_mount_tree {Print tree output of a model with Schema Mount} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "clear -y" + ly_cmd "searchpath $mdir" + ly_cmd "load modsm" + ly_cmd "extdata $ddir/modsm_ctx_ext.xml" + ly_cmd "print -f tree modsm" "--mp root.*--rw lfl/" +}} + +test ext_data_schema_mount_tree_yanglibfile {Print tree output of a model with Schema Mount and --yang-library-file} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "clear -Y $ddir/modsm_ctx_main.xml" + ly_cmd "searchpath $mdir" + ly_cmd "load modsm" + ly_cmd "extdata $ddir/modsm_ctx_ext.xml" + ly_cmd "print -f tree modsm" "--mp root.*--rw lfl/.*--rw msa:alf?" +}} + +test ext_data_schema_mount_xml {Validating and printing mounted data} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "clear -y" + ly_cmd "searchpath $mdir" + ly_cmd "load modsm" + ly_cmd "extdata $ddir/modsm_ctx_ext.xml" + ly_cmd "data -f xml -t config $ddir/modsm.xml" "</lfl>" +}} + +test ext_data_schema_mount_xml_yanglibfile {Validating and printing mounted data with --yang-library-file} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "clear -Y $ddir/modsm_ctx_main.xml" + ly_cmd "searchpath $mdir" + ly_cmd "load modsm" + ly_cmd "extdata $ddir/modsm_ctx_ext.xml" + ly_cmd "data -f xml -t config $ddir/modsm2.xml" "</lfl>.*</alf>" +}} + +cleanupTests diff --git a/tests/yanglint/interactive/feature.test b/tests/yanglint/interactive/feature.test new file mode 100644 index 0000000..84bfa8e --- /dev/null +++ b/tests/yanglint/interactive/feature.test @@ -0,0 +1,37 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/interactive/ly.tcl" : "ly.tcl"}] + +test feature_all_default {Default output of feature --all} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "feature -a" "yang:\r\n\t(none)\r\n\r\nietf-yang-schema-mount:\r\n\t(none)\r\n" -ex +}} + +test feature_all_add_module {Add module with only one feature and call feature --all} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load --feature modfeature:ftr1 modfeature" + ly_cmd "feature -a" "modfeature:\r\n\tftr1 \\(on\\)\r\n\tftr2 \\(off\\)" +}} + +test feature_all_on {Add module with all enabled features and call feature --all} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load --feature modfeature:* modfeature" + ly_cmd "feature -a" "modfeature:\r\n\tftr1 \\(on\\)\r\n\tftr2 \\(on\\)" +}} + +test feature_one_module {Show features for one module} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load ietf-ip" + ly_cmd "feature -f ietf-ip" " -F ietf-ip:ipv4-non-contiguous-netmasks,ipv6-privacy-autoconf" -ex +}} + +test feature_more_modules {Show a mix of modules with and without features} { +-setup $ly_setup -cleanup $ly_cleanup -body { + + set features " -F modfeature:ftr1,ftr2\ +-F modleaf:\ +-F ietf-ip:ipv4-non-contiguous-netmasks,ipv6-privacy-autoconf" + + ly_cmd "load ietf-ip modleaf modfeature" + ly_cmd "feature -f modfeature modleaf ietf-ip" $features -ex +}} + +cleanupTests diff --git a/tests/yanglint/interactive/list.test b/tests/yanglint/interactive/list.test new file mode 100644 index 0000000..ab59a32 --- /dev/null +++ b/tests/yanglint/interactive/list.test @@ -0,0 +1,34 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/interactive/ly.tcl" : "ly.tcl"}] +namespace import uti::regex_xml_elements uti::regex_json_pairs + +set modules {ietf-yang-library ietf-inet-types} + +test list_basic {basic test} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "list" "ietf-yang-types" +}} + +test list_format_xml {list --format xml} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "clear -y" + ly_cmd "list -f xml" [regex_xml_elements $modules "name"] +}} + +test list_format_json {list --format json} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "clear -y" + ly_cmd "list -f json" [regex_json_pairs $modules "name"] +}} + +test list_ietf_yang_library {Error due to missing ietf-yang-library} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd_err "list -f xml" "Module \"ietf-yang-library\" is not implemented." +}} + +test list_bad_format {Error due to bad format} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "clear -y" + ly_cmd_err "list -f csv" "Unknown output format csv" +}} + +cleanupTests diff --git a/tests/yanglint/interactive/load.test b/tests/yanglint/interactive/load.test new file mode 100644 index 0000000..a95d044 --- /dev/null +++ b/tests/yanglint/interactive/load.test @@ -0,0 +1,45 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/interactive/ly.tcl" : "ly.tcl"}] + +test load_basic {} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modleafref" + ly_cmd "list" "I modleafref\r.*I modleaf" +}} + +test load_with_feature {Load module with feature} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load --feature modfeature:ftr2 modfeature" + ly_cmd "feature -a" "modfeature:\r\n\tftr1 \\(off\\)\r\n\tftr2 \\(on\\)" +}} + +test load_make_implemented_once {load --make-implemented} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_ignore "load modmust" + ly_cmd "list" "I modmust\r.*i modleaf" + ly_cmd "clear" + ly_cmd "searchpath $::env(YANG_MODULES_DIR)" + ly_cmd "load -i modmust" + ly_cmd "list" "I modmust\r.*I modleaf" +}} + +test load_make_implemented_twice {load -i -i} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modimp-type" + ly_cmd "list" "I modimp-type\r.*i modtypedef" + ly_cmd "clear" + ly_cmd "searchpath $::env(YANG_MODULES_DIR)" + ly_cmd "load -i -i modimp-type" + ly_cmd "list" "I modimp-type\r.*I modtypedef" +}} + +test load_extended_leafref_enabled {Valid module with --extended-leafref option} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load -X modextleafref" +}} + +test load_extended_leafref_disabled {Expected error if --extended-leafref is not set} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd_err "load modextleafref" "Unexpected XPath token \"FunctionName\"" +}} + +cleanupTests diff --git a/tests/yanglint/interactive/ly.tcl b/tests/yanglint/interactive/ly.tcl new file mode 100644 index 0000000..4c56be4 --- /dev/null +++ b/tests/yanglint/interactive/ly.tcl @@ -0,0 +1,81 @@ +# @brief The main source of functions and variables for testing yanglint in the interactive mode. + +# For testing yanglint. +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/common.tcl" : "../common.tcl"}] +# For testing any interactive tool. +source "$::env(TESTS_DIR)/../tool_i.tcl" + +# The script continues by defining variables and functions specific to the interactive yanglint tool. + +# set the timeout to 5 seconds +set timeout 5 +# prompt of yanglint +set prompt "> " +# turn off dialog between expect and yanglint +log_user 0 +# setting some large terminal width +stty columns 720 + +# default setup for every unit test +variable ly_setup { + spawn $TUT + ly_skip_warnings + # Searchpath is set, so modules can be loaded via the 'load' command. + ly_cmd "searchpath $::env(YANG_MODULES_DIR)" +} + +# default cleanup for every unit test +variable ly_cleanup { + ly_exit +} + +# Skip no dir and/or no history warnings and prompt. +proc ly_skip_warnings {} { + global prompt + expect -re "(YANGLINT.*)*$prompt" {} +} + +# Send command 'cmd' to the process, expect error header and then check output string by 'pattern'. +# Parameter cmd is a string of arguments. +# Parameter pattern is a regex. It must not contain a prompt. +proc ly_cmd_err {cmd pattern} { + global prompt + + send -- "${cmd}\r" + expect -- "${cmd}\r\n" + + expect { + -re "YANGLINT\\\[E\\\]: .*${pattern}.*\r\n${prompt}$" {} + -re "libyang\\\[\[0-9]+\\\]: .*${pattern}.*\r\n${prompt}$" {} + -re "\r\n${prompt}$" { + error "unexpected output:\n$expect_out(buffer)" + } + } +} + +# Send command 'cmd' to the process, expect warning header and then check output string by 'pattern'. +# Parameter cmd is a string of arguments. +# Parameter pattern is a regex. It must not contain a prompt. +proc ly_cmd_wrn {cmd pattern} { + ly_cmd_header $cmd "YANGLINT\\\[W\\\]:" $pattern +} + +# Send 'exit' and wait for eof. +proc ly_exit {} { + send "exit\r" + expect eof +} + +# Check if yanglint is configured as DEBUG. +# Return 1 on success. +proc yanglint_debug {} { + global TUT + # Call non-interactive yanglint with --help. + set output [exec -- $TUT "-h"] + # Find option --debug. + if { [regexp -- "--debug=GROUPS" $output] } { + return 1 + } else { + return 0 + } +} diff --git a/tests/yanglint/interactive/modcwd.yang b/tests/yanglint/interactive/modcwd.yang new file mode 100644 index 0000000..db33e73 --- /dev/null +++ b/tests/yanglint/interactive/modcwd.yang @@ -0,0 +1,4 @@ +module modcwd { + namespace "urn:yanglint:modcwd"; + prefix mc; +} diff --git a/tests/yanglint/interactive/print.test b/tests/yanglint/interactive/print.test new file mode 100644 index 0000000..8b9d740 --- /dev/null +++ b/tests/yanglint/interactive/print.test @@ -0,0 +1,77 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/interactive/ly.tcl" : "ly.tcl"}] + +set ipv6_path "/ietf-interfaces:interfaces/interface/ietf-ip:ipv6/address" + +test print_yang {} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modleaf" + ly_cmd "print -f yang modleaf" "leaf lfl" +}} + +test print_yang_submodule {Print submodule in yang format} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modinclude" + ly_cmd "print -f yang modsub" "submodule modsub" +}} + +test print_yin {} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modleaf" + ly_cmd "print -f yin modleaf" "<leaf name=\"lfl\">" +}} + +test print_yin_submodule {Print submodule in yin format} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modinclude" + ly_cmd "print -f yin modsub" "<submodule name=\"modsub\"" +}} + +test print_info {} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modleaf" + ly_cmd "print -f info modleaf" "status current" +}} + +test print_info_path {Print subtree in info format} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load ietf-ip" + ly_cmd "print -f info -P $ipv6_path" "^list address .* leaf prefix-length" +}} + +test print_info_path_single_node {Print node in info format} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load ietf-ip" + ly_cmd "print -f info -q -P $ipv6_path" "^list address .* IPv6 addresses on the interface.\";\r\n\}$" +}} + +test print_tree {} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modleaf" + ly_cmd "print -f tree modleaf" "\\+--rw lfl" +}} + +test print_tree_submodule {Print submodule in tree format} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load modinclude" + ly_cmd "print -f tree modsub" "submodule: modsub" +}} + +test print_tree_path {Print subtree in tree format} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load ietf-ip" + ly_cmd "print -f tree -P $ipv6_path" "\\+--rw address.*\\+--rw prefix-length" +}} + +test print_tree_path_single_node {Print node in tree format} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load ietf-ip" + ly_cmd "print -f tree -q -P $ipv6_path" "\\+--rw address\\* \\\[ip\\\]$" +}} + +test print_tree_path_single_node_line_length {Print node in the tree format and limit row size} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "load ietf-ip" + ly_cmd "print -f tree -L 20 -q -P $ipv6_path" "\\+--rw address\\*\r\n *\\\[ip\\\]$" +}} + +cleanupTests diff --git a/tests/yanglint/interactive/searchpath.test b/tests/yanglint/interactive/searchpath.test new file mode 100644 index 0000000..3bd6796 --- /dev/null +++ b/tests/yanglint/interactive/searchpath.test @@ -0,0 +1,24 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/interactive/ly.tcl" : "ly.tcl"}] + +set mdir $::env(YANG_MODULES_DIR) + +variable ly_setup { + spawn $TUT + ly_skip_warnings +} + +test searchpath_basic {} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "searchpath $mdir" + ly_cmd "searchpath" "$mdir" + ly_cmd "load modleaf" +}} + +test searchpath_clear {searchpath --clear} { +-setup $ly_setup -cleanup $ly_cleanup -body { + ly_cmd "searchpath $mdir" + ly_cmd "searchpath --clear" + ly_cmd_err "load modleaf" "Data model \"modleaf\" not found in local searchdirs" +}} + +cleanupTests diff --git a/tests/yanglint/modules/ietf-interfaces.yang b/tests/yanglint/modules/ietf-interfaces.yang new file mode 100644 index 0000000..ad64425 --- /dev/null +++ b/tests/yanglint/modules/ietf-interfaces.yang @@ -0,0 +1,725 @@ +module ietf-interfaces { + + namespace "urn:ietf:params:xml:ns:yang:ietf-interfaces"; + prefix if; + + import ietf-yang-types { + prefix yang; + } + + organization + "IETF NETMOD (NETCONF Data Modeling Language) Working Group"; + + contact + "WG Web: <http://tools.ietf.org/wg/netmod/> + WG List: <mailto:netmod@ietf.org> + + WG Chair: Thomas Nadeau + <mailto:tnadeau@lucidvision.com> + + WG Chair: Juergen Schoenwaelder + <mailto:j.schoenwaelder@jacobs-university.de> + + Editor: Martin Bjorklund + <mailto:mbj@tail-f.com>"; + + description + "This module contains a collection of YANG definitions for + managing network interfaces. + + Copyright (c) 2014 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC 7223; see + the RFC itself for full legal notices."; + + revision 2014-05-08 { + description + "Initial revision."; + reference + "RFC 7223: A YANG Data Model for Interface Management"; + } + + /* + * Typedefs + */ + + typedef interface-ref { + type leafref { + path "/if:interfaces/if:interface/if:name"; + } + description + "This type is used by data models that need to reference + configured interfaces."; + } + + typedef interface-state-ref { + type leafref { + path "/if:interfaces-state/if:interface/if:name"; + } + description + "This type is used by data models that need to reference + the operationally present interfaces."; + } + + /* + * Identities + */ + + identity interface-type { + description + "Base identity from which specific interface types are + derived."; + } + + /* + * Features + */ + + feature arbitrary-names { + description + "This feature indicates that the device allows user-controlled + interfaces to be named arbitrarily."; + } + feature pre-provisioning { + description + "This feature indicates that the device supports + pre-provisioning of interface configuration, i.e., it is + possible to configure an interface whose physical interface + hardware is not present on the device."; + } + + feature if-mib { + description + "This feature indicates that the device implements + the IF-MIB."; + reference + "RFC 2863: The Interfaces Group MIB"; + } + + /* + * Configuration data nodes + */ + + container interfaces { + description + "Interface configuration parameters."; + + list interface { + key "name"; + + description + "The list of configured interfaces on the device. + + The operational state of an interface is available in the + /interfaces-state/interface list. If the configuration of a + system-controlled interface cannot be used by the system + (e.g., the interface hardware present does not match the + interface type), then the configuration is not applied to + the system-controlled interface shown in the + /interfaces-state/interface list. If the configuration + of a user-controlled interface cannot be used by the system, + the configured interface is not instantiated in the + /interfaces-state/interface list."; + + leaf name { + type string; + description + "The name of the interface. + + A device MAY restrict the allowed values for this leaf, + possibly depending on the type of the interface. + For system-controlled interfaces, this leaf is the + device-specific name of the interface. The 'config false' + list /interfaces-state/interface contains the currently + existing interfaces on the device. + + If a client tries to create configuration for a + system-controlled interface that is not present in the + /interfaces-state/interface list, the server MAY reject + the request if the implementation does not support + pre-provisioning of interfaces or if the name refers to + an interface that can never exist in the system. A + NETCONF server MUST reply with an rpc-error with the + error-tag 'invalid-value' in this case. + + If the device supports pre-provisioning of interface + configuration, the 'pre-provisioning' feature is + advertised. + + If the device allows arbitrarily named user-controlled + interfaces, the 'arbitrary-names' feature is advertised. + + When a configured user-controlled interface is created by + the system, it is instantiated with the same name in the + /interface-state/interface list."; + } + + leaf description { + type string; + description + "A textual description of the interface. + + A server implementation MAY map this leaf to the ifAlias + MIB object. Such an implementation needs to use some + mechanism to handle the differences in size and characters + allowed between this leaf and ifAlias. The definition of + such a mechanism is outside the scope of this document. + + Since ifAlias is defined to be stored in non-volatile + storage, the MIB implementation MUST map ifAlias to the + value of 'description' in the persistently stored + datastore. + + Specifically, if the device supports ':startup', when + ifAlias is read the device MUST return the value of + 'description' in the 'startup' datastore, and when it is + written, it MUST be written to the 'running' and 'startup' + datastores. Note that it is up to the implementation to + + decide whether to modify this single leaf in 'startup' or + perform an implicit copy-config from 'running' to + 'startup'. + + If the device does not support ':startup', ifAlias MUST + be mapped to the 'description' leaf in the 'running' + datastore."; + reference + "RFC 2863: The Interfaces Group MIB - ifAlias"; + } + + leaf type { + type identityref { + base interface-type; + } + mandatory true; + description + "The type of the interface. + + When an interface entry is created, a server MAY + initialize the type leaf with a valid value, e.g., if it + is possible to derive the type from the name of the + interface. + + If a client tries to set the type of an interface to a + value that can never be used by the system, e.g., if the + type is not supported or if the type does not match the + name of the interface, the server MUST reject the request. + A NETCONF server MUST reply with an rpc-error with the + error-tag 'invalid-value' in this case."; + reference + "RFC 2863: The Interfaces Group MIB - ifType"; + } + + leaf enabled { + type boolean; + default "true"; + description + "This leaf contains the configured, desired state of the + interface. + + Systems that implement the IF-MIB use the value of this + leaf in the 'running' datastore to set + IF-MIB.ifAdminStatus to 'up' or 'down' after an ifEntry + has been initialized, as described in RFC 2863. + + + + Changes in this leaf in the 'running' datastore are + reflected in ifAdminStatus, but if ifAdminStatus is + changed over SNMP, this leaf is not affected."; + reference + "RFC 2863: The Interfaces Group MIB - ifAdminStatus"; + } + + leaf link-up-down-trap-enable { + if-feature if-mib; + type enumeration { + enum enabled { + value 1; + } + enum disabled { + value 2; + } + } + description + "Controls whether linkUp/linkDown SNMP notifications + should be generated for this interface. + + If this node is not configured, the value 'enabled' is + operationally used by the server for interfaces that do + not operate on top of any other interface (i.e., there are + no 'lower-layer-if' entries), and 'disabled' otherwise."; + reference + "RFC 2863: The Interfaces Group MIB - + ifLinkUpDownTrapEnable"; + } + } + } + + /* + * Operational state data nodes + */ + + container interfaces-state { + config false; + description + "Data nodes for the operational state of interfaces."; + + list interface { + key "name"; + + + + + + description + "The list of interfaces on the device. + + System-controlled interfaces created by the system are + always present in this list, whether they are configured or + not."; + + leaf name { + type string; + description + "The name of the interface. + + A server implementation MAY map this leaf to the ifName + MIB object. Such an implementation needs to use some + mechanism to handle the differences in size and characters + allowed between this leaf and ifName. The definition of + such a mechanism is outside the scope of this document."; + reference + "RFC 2863: The Interfaces Group MIB - ifName"; + } + + leaf type { + type identityref { + base interface-type; + } + mandatory true; + description + "The type of the interface."; + reference + "RFC 2863: The Interfaces Group MIB - ifType"; + } + + leaf admin-status { + if-feature if-mib; + type enumeration { + enum up { + value 1; + description + "Ready to pass packets."; + } + enum down { + value 2; + description + "Not ready to pass packets and not in some test mode."; + } + + + + enum testing { + value 3; + description + "In some test mode."; + } + } + mandatory true; + description + "The desired state of the interface. + + This leaf has the same read semantics as ifAdminStatus."; + reference + "RFC 2863: The Interfaces Group MIB - ifAdminStatus"; + } + + leaf oper-status { + type enumeration { + enum up { + value 1; + description + "Ready to pass packets."; + } + enum down { + value 2; + description + "The interface does not pass any packets."; + } + enum testing { + value 3; + description + "In some test mode. No operational packets can + be passed."; + } + enum unknown { + value 4; + description + "Status cannot be determined for some reason."; + } + enum dormant { + value 5; + description + "Waiting for some external event."; + } + enum not-present { + value 6; + description + "Some component (typically hardware) is missing."; + } + enum lower-layer-down { + value 7; + description + "Down due to state of lower-layer interface(s)."; + } + } + mandatory true; + description + "The current operational state of the interface. + + This leaf has the same semantics as ifOperStatus."; + reference + "RFC 2863: The Interfaces Group MIB - ifOperStatus"; + } + + leaf last-change { + type yang:date-and-time; + description + "The time the interface entered its current operational + state. If the current state was entered prior to the + last re-initialization of the local network management + subsystem, then this node is not present."; + reference + "RFC 2863: The Interfaces Group MIB - ifLastChange"; + } + + leaf if-index { + if-feature if-mib; + type int32 { + range "1..2147483647"; + } + mandatory true; + description + "The ifIndex value for the ifEntry represented by this + interface."; + reference + "RFC 2863: The Interfaces Group MIB - ifIndex"; + } + + leaf phys-address { + type yang:phys-address; + description + "The interface's address at its protocol sub-layer. For + example, for an 802.x interface, this object normally + contains a Media Access Control (MAC) address. The + interface's media-specific modules must define the bit + + + and byte ordering and the format of the value of this + object. For interfaces that do not have such an address + (e.g., a serial line), this node is not present."; + reference + "RFC 2863: The Interfaces Group MIB - ifPhysAddress"; + } + + leaf-list higher-layer-if { + type interface-state-ref; + description + "A list of references to interfaces layered on top of this + interface."; + reference + "RFC 2863: The Interfaces Group MIB - ifStackTable"; + } + + leaf-list lower-layer-if { + type interface-state-ref; + description + "A list of references to interfaces layered underneath this + interface."; + reference + "RFC 2863: The Interfaces Group MIB - ifStackTable"; + } + + leaf speed { + type yang:gauge64; + units "bits/second"; + description + "An estimate of the interface's current bandwidth in bits + per second. For interfaces that do not vary in + bandwidth or for those where no accurate estimation can + be made, this node should contain the nominal bandwidth. + For interfaces that have no concept of bandwidth, this + node is not present."; + reference + "RFC 2863: The Interfaces Group MIB - + ifSpeed, ifHighSpeed"; + } + + + + + + + + + + container statistics { + description + "A collection of interface-related statistics objects."; + + leaf discontinuity-time { + type yang:date-and-time; + mandatory true; + description + "The time on the most recent occasion at which any one or + more of this interface's counters suffered a + discontinuity. If no such discontinuities have occurred + since the last re-initialization of the local management + subsystem, then this node contains the time the local + management subsystem re-initialized itself."; + } + + leaf in-octets { + type yang:counter64; + description + "The total number of octets received on the interface, + including framing characters. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system, and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifHCInOctets"; + } + + leaf in-unicast-pkts { + type yang:counter64; + description + "The number of packets, delivered by this sub-layer to a + higher (sub-)layer, that were not addressed to a + multicast or broadcast address at this sub-layer. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system, and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifHCInUcastPkts"; + } + + + + + leaf in-broadcast-pkts { + type yang:counter64; + description + "The number of packets, delivered by this sub-layer to a + higher (sub-)layer, that were addressed to a broadcast + address at this sub-layer. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system, and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - + ifHCInBroadcastPkts"; + } + + leaf in-multicast-pkts { + type yang:counter64; + description + "The number of packets, delivered by this sub-layer to a + higher (sub-)layer, that were addressed to a multicast + address at this sub-layer. For a MAC-layer protocol, + this includes both Group and Functional addresses. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system, and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - + ifHCInMulticastPkts"; + } + + leaf in-discards { + type yang:counter32; + description + "The number of inbound packets that were chosen to be + discarded even though no errors had been detected to + prevent their being deliverable to a higher-layer + protocol. One possible reason for discarding such a + packet could be to free up buffer space. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system, and at + other times as indicated by the value of + 'discontinuity-time'."; + + + reference + "RFC 2863: The Interfaces Group MIB - ifInDiscards"; + } + + leaf in-errors { + type yang:counter32; + description + "For packet-oriented interfaces, the number of inbound + packets that contained errors preventing them from being + deliverable to a higher-layer protocol. For character- + oriented or fixed-length interfaces, the number of + inbound transmission units that contained errors + preventing them from being deliverable to a higher-layer + protocol. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system, and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifInErrors"; + } + + leaf in-unknown-protos { + type yang:counter32; + description + "For packet-oriented interfaces, the number of packets + received via the interface that were discarded because + of an unknown or unsupported protocol. For + character-oriented or fixed-length interfaces that + support protocol multiplexing, the number of + transmission units received via the interface that were + discarded because of an unknown or unsupported protocol. + For any interface that does not support protocol + multiplexing, this counter is not present. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system, and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifInUnknownProtos"; + } + + + + + + leaf out-octets { + type yang:counter64; + description + "The total number of octets transmitted out of the + interface, including framing characters. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system, and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifHCOutOctets"; + } + + leaf out-unicast-pkts { + type yang:counter64; + description + "The total number of packets that higher-level protocols + requested be transmitted, and that were not addressed + to a multicast or broadcast address at this sub-layer, + including those that were discarded or not sent. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system, and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifHCOutUcastPkts"; + } + + leaf out-broadcast-pkts { + type yang:counter64; + description + "The total number of packets that higher-level protocols + requested be transmitted, and that were addressed to a + broadcast address at this sub-layer, including those + that were discarded or not sent. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system, and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - + ifHCOutBroadcastPkts"; + } + + + leaf out-multicast-pkts { + type yang:counter64; + description + "The total number of packets that higher-level protocols + requested be transmitted, and that were addressed to a + multicast address at this sub-layer, including those + that were discarded or not sent. For a MAC-layer + protocol, this includes both Group and Functional + addresses. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system, and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - + ifHCOutMulticastPkts"; + } + + leaf out-discards { + type yang:counter32; + description + "The number of outbound packets that were chosen to be + discarded even though no errors had been detected to + prevent their being transmitted. One possible reason + for discarding such a packet could be to free up buffer + space. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system, and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifOutDiscards"; + } + + leaf out-errors { + type yang:counter32; + description + "For packet-oriented interfaces, the number of outbound + packets that could not be transmitted because of errors. + For character-oriented or fixed-length interfaces, the + number of outbound transmission units that could not be + transmitted because of errors. + + + + + Discontinuities in the value of this counter can occur + at re-initialization of the management system, and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifOutErrors"; + } + } + } + } +} diff --git a/tests/yanglint/modules/ietf-ip.yang b/tests/yanglint/modules/ietf-ip.yang new file mode 100644 index 0000000..1499120 --- /dev/null +++ b/tests/yanglint/modules/ietf-ip.yang @@ -0,0 +1,758 @@ +module ietf-ip { + + namespace "urn:ietf:params:xml:ns:yang:ietf-ip"; + prefix ip; + + import ietf-interfaces { + prefix if; + } + import ietf-inet-types { + prefix inet; + } + import ietf-yang-types { + prefix yang; + } + + organization + "IETF NETMOD (NETCONF Data Modeling Language) Working Group"; + + contact + "WG Web: <http://tools.ietf.org/wg/netmod/> + WG List: <mailto:netmod@ietf.org> + + WG Chair: Thomas Nadeau + <mailto:tnadeau@lucidvision.com> + + WG Chair: Juergen Schoenwaelder + <mailto:j.schoenwaelder@jacobs-university.de> + + Editor: Martin Bjorklund + <mailto:mbj@tail-f.com>"; + + + + + + + + + + + description + "This module contains a collection of YANG definitions for + configuring IP implementations. + + Copyright (c) 2014 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC 7277; see + the RFC itself for full legal notices."; + + revision 2014-06-16 { + description + "Initial revision."; + reference + "RFC 7277: A YANG Data Model for IP Management"; + } + + /* + + * Features + */ + + feature ipv4-non-contiguous-netmasks { + description + "Indicates support for configuring non-contiguous + subnet masks."; + } + + feature ipv6-privacy-autoconf { + description + "Indicates support for Privacy Extensions for Stateless Address + Autoconfiguration in IPv6."; + reference + "RFC 4941: Privacy Extensions for Stateless Address + Autoconfiguration in IPv6"; + } + + + + + + /* + * Typedefs + */ + + typedef ip-address-origin { + type enumeration { + enum other { + description + "None of the following."; + } + enum static { + description + "Indicates that the address has been statically + configured - for example, using NETCONF or a Command Line + Interface."; + } + enum dhcp { + description + "Indicates an address that has been assigned to this + system by a DHCP server."; + } + enum link-layer { + description + "Indicates an address created by IPv6 stateless + autoconfiguration that embeds a link-layer address in its + interface identifier."; + } + enum random { + description + "Indicates an address chosen by the system at + + random, e.g., an IPv4 address within 169.254/16, an + RFC 4941 temporary address, or an RFC 7217 semantically + opaque address."; + reference + "RFC 4941: Privacy Extensions for Stateless Address + Autoconfiguration in IPv6 + RFC 7217: A Method for Generating Semantically Opaque + Interface Identifiers with IPv6 Stateless + Address Autoconfiguration (SLAAC)"; + } + } + description + "The origin of an address."; + } + + + + typedef neighbor-origin { + type enumeration { + enum other { + description + "None of the following."; + } + enum static { + description + "Indicates that the mapping has been statically + configured - for example, using NETCONF or a Command Line + Interface."; + } + enum dynamic { + description + "Indicates that the mapping has been dynamically resolved + using, e.g., IPv4 ARP or the IPv6 Neighbor Discovery + protocol."; + } + } + description + "The origin of a neighbor entry."; + } + + /* + * Configuration data nodes + */ + + augment "/if:interfaces/if:interface" { + description + "Parameters for configuring IP on interfaces. + + If an interface is not capable of running IP, the server + must not allow the client to configure these parameters."; + + container ipv4 { + presence + "Enables IPv4 unless the 'enabled' leaf + (which defaults to 'true') is set to 'false'"; + description + "Parameters for the IPv4 address family."; + + + + + + + + + leaf enabled { + type boolean; + default true; + description + "Controls whether IPv4 is enabled or disabled on this + interface. When IPv4 is enabled, this interface is + connected to an IPv4 stack, and the interface can send + and receive IPv4 packets."; + } + leaf forwarding { + type boolean; + default false; + description + "Controls IPv4 packet forwarding of datagrams received by, + but not addressed to, this interface. IPv4 routers + forward datagrams. IPv4 hosts do not (except those + source-routed via the host)."; + } + leaf mtu { + type uint16 { + range "68..max"; + } + units octets; + description + "The size, in octets, of the largest IPv4 packet that the + interface will send and receive. + + The server may restrict the allowed values for this leaf, + depending on the interface's type. + + If this leaf is not configured, the operationally used MTU + depends on the interface's type."; + reference + "RFC 791: Internet Protocol"; + } + list address { + key "ip"; + description + "The list of configured IPv4 addresses on the interface."; + + leaf ip { + type inet:ipv4-address-no-zone; + description + "The IPv4 address on the interface."; + } + + + + choice subnet { + mandatory true; + description + "The subnet can be specified as a prefix-length, or, + if the server supports non-contiguous netmasks, as + a netmask."; + leaf prefix-length { + type uint8 { + range "0..32"; + } + description + "The length of the subnet prefix."; + } + leaf netmask { + if-feature ipv4-non-contiguous-netmasks; + type yang:dotted-quad; + description + "The subnet specified as a netmask."; + } + } + } + list neighbor { + key "ip"; + description + "A list of mappings from IPv4 addresses to + link-layer addresses. + + Entries in this list are used as static entries in the + ARP Cache."; + reference + "RFC 826: An Ethernet Address Resolution Protocol"; + + leaf ip { + type inet:ipv4-address-no-zone; + description + "The IPv4 address of the neighbor node."; + } + leaf link-layer-address { + type yang:phys-address; + mandatory true; + description + "The link-layer address of the neighbor node."; + } + } + + } + + + container ipv6 { + presence + "Enables IPv6 unless the 'enabled' leaf + (which defaults to 'true') is set to 'false'"; + description + "Parameters for the IPv6 address family."; + + leaf enabled { + type boolean; + default true; + description + "Controls whether IPv6 is enabled or disabled on this + interface. When IPv6 is enabled, this interface is + connected to an IPv6 stack, and the interface can send + and receive IPv6 packets."; + } + leaf forwarding { + type boolean; + default false; + description + "Controls IPv6 packet forwarding of datagrams received by, + but not addressed to, this interface. IPv6 routers + forward datagrams. IPv6 hosts do not (except those + source-routed via the host)."; + reference + "RFC 4861: Neighbor Discovery for IP version 6 (IPv6) + Section 6.2.1, IsRouter"; + } + leaf mtu { + type uint32 { + range "1280..max"; + } + units octets; + description + "The size, in octets, of the largest IPv6 packet that the + interface will send and receive. + + The server may restrict the allowed values for this leaf, + depending on the interface's type. + + If this leaf is not configured, the operationally used MTU + depends on the interface's type."; + reference + "RFC 2460: Internet Protocol, Version 6 (IPv6) Specification + Section 5"; + } + + + list address { + key "ip"; + description + "The list of configured IPv6 addresses on the interface."; + + leaf ip { + type inet:ipv6-address-no-zone; + description + "The IPv6 address on the interface."; + } + leaf prefix-length { + type uint8 { + range "0..128"; + } + mandatory true; + description + "The length of the subnet prefix."; + } + } + list neighbor { + key "ip"; + description + "A list of mappings from IPv6 addresses to + link-layer addresses. + + Entries in this list are used as static entries in the + Neighbor Cache."; + reference + "RFC 4861: Neighbor Discovery for IP version 6 (IPv6)"; + + leaf ip { + type inet:ipv6-address-no-zone; + description + "The IPv6 address of the neighbor node."; + } + leaf link-layer-address { + type yang:phys-address; + mandatory true; + description + "The link-layer address of the neighbor node."; + } + } + + + + + + + leaf dup-addr-detect-transmits { + type uint32; + default 1; + description + "The number of consecutive Neighbor Solicitation messages + sent while performing Duplicate Address Detection on a + tentative address. A value of zero indicates that + Duplicate Address Detection is not performed on + tentative addresses. A value of one indicates a single + transmission with no follow-up retransmissions."; + reference + "RFC 4862: IPv6 Stateless Address Autoconfiguration"; + } + container autoconf { + description + "Parameters to control the autoconfiguration of IPv6 + addresses, as described in RFC 4862."; + reference + "RFC 4862: IPv6 Stateless Address Autoconfiguration"; + + leaf create-global-addresses { + type boolean; + default true; + description + "If enabled, the host creates global addresses as + described in RFC 4862."; + reference + "RFC 4862: IPv6 Stateless Address Autoconfiguration + Section 5.5"; + } + leaf create-temporary-addresses { + if-feature ipv6-privacy-autoconf; + type boolean; + default false; + description + "If enabled, the host creates temporary addresses as + described in RFC 4941."; + reference + "RFC 4941: Privacy Extensions for Stateless Address + Autoconfiguration in IPv6"; + } + + + + + + + + leaf temporary-valid-lifetime { + if-feature ipv6-privacy-autoconf; + type uint32; + units "seconds"; + default 604800; + description + "The time period during which the temporary address + is valid."; + reference + "RFC 4941: Privacy Extensions for Stateless Address + Autoconfiguration in IPv6 + - TEMP_VALID_LIFETIME"; + } + leaf temporary-preferred-lifetime { + if-feature ipv6-privacy-autoconf; + type uint32; + units "seconds"; + default 86400; + description + "The time period during which the temporary address is + preferred."; + reference + "RFC 4941: Privacy Extensions for Stateless Address + Autoconfiguration in IPv6 + - TEMP_PREFERRED_LIFETIME"; + } + } + } + } + + /* + * Operational state data nodes + */ + + augment "/if:interfaces-state/if:interface" { + description + "Data nodes for the operational state of IP on interfaces."; + + container ipv4 { + presence "Present if IPv4 is enabled on this interface"; + config false; + description + "Interface-specific parameters for the IPv4 address family."; + + + + + + leaf forwarding { + type boolean; + description + "Indicates whether IPv4 packet forwarding is enabled or + disabled on this interface."; + } + leaf mtu { + type uint16 { + range "68..max"; + } + units octets; + description + "The size, in octets, of the largest IPv4 packet that the + interface will send and receive."; + reference + "RFC 791: Internet Protocol"; + } + list address { + key "ip"; + description + "The list of IPv4 addresses on the interface."; + + leaf ip { + type inet:ipv4-address-no-zone; + description + "The IPv4 address on the interface."; + } + choice subnet { + description + "The subnet can be specified as a prefix-length, or, + if the server supports non-contiguous netmasks, as + a netmask."; + leaf prefix-length { + type uint8 { + range "0..32"; + } + description + "The length of the subnet prefix."; + } + leaf netmask { + if-feature ipv4-non-contiguous-netmasks; + type yang:dotted-quad; + description + "The subnet specified as a netmask."; + } + } + + + leaf origin { + type ip-address-origin; + description + "The origin of this address."; + } + } + list neighbor { + key "ip"; + description + "A list of mappings from IPv4 addresses to + link-layer addresses. + + This list represents the ARP Cache."; + reference + "RFC 826: An Ethernet Address Resolution Protocol"; + + leaf ip { + type inet:ipv4-address-no-zone; + description + "The IPv4 address of the neighbor node."; + } + leaf link-layer-address { + type yang:phys-address; + description + "The link-layer address of the neighbor node."; + } + leaf origin { + type neighbor-origin; + description + "The origin of this neighbor entry."; + } + } + + } + + container ipv6 { + presence "Present if IPv6 is enabled on this interface"; + config false; + description + "Parameters for the IPv6 address family."; + + + + + + + + + leaf forwarding { + type boolean; + default false; + description + "Indicates whether IPv6 packet forwarding is enabled or + disabled on this interface."; + reference + "RFC 4861: Neighbor Discovery for IP version 6 (IPv6) + Section 6.2.1, IsRouter"; + } + leaf mtu { + type uint32 { + range "1280..max"; + } + units octets; + description + "The size, in octets, of the largest IPv6 packet that the + interface will send and receive."; + reference + "RFC 2460: Internet Protocol, Version 6 (IPv6) Specification + Section 5"; + } + list address { + key "ip"; + description + "The list of IPv6 addresses on the interface."; + + leaf ip { + type inet:ipv6-address-no-zone; + description + "The IPv6 address on the interface."; + } + leaf prefix-length { + type uint8 { + range "0..128"; + } + mandatory true; + description + "The length of the subnet prefix."; + } + leaf origin { + type ip-address-origin; + description + "The origin of this address."; + } + + + + leaf status { + type enumeration { + enum preferred { + description + "This is a valid address that can appear as the + destination or source address of a packet."; + } + enum deprecated { + description + "This is a valid but deprecated address that should + no longer be used as a source address in new + communications, but packets addressed to such an + address are processed as expected."; + } + enum invalid { + description + "This isn't a valid address, and it shouldn't appear + as the destination or source address of a packet."; + } + enum inaccessible { + description + "The address is not accessible because the interface + to which this address is assigned is not + operational."; + } + enum unknown { + description + "The status cannot be determined for some reason."; + } + enum tentative { + description + "The uniqueness of the address on the link is being + verified. Addresses in this state should not be + used for general communication and should only be + used to determine the uniqueness of the address."; + } + enum duplicate { + description + "The address has been determined to be non-unique on + the link and so must not be used."; + } + + + + + + + + enum optimistic { + description + "The address is available for use, subject to + restrictions, while its uniqueness on a link is + being verified."; + } + } + description + "The status of an address. Most of the states correspond + to states from the IPv6 Stateless Address + Autoconfiguration protocol."; + reference + "RFC 4293: Management Information Base for the + Internet Protocol (IP) + - IpAddressStatusTC + RFC 4862: IPv6 Stateless Address Autoconfiguration"; + } + } + list neighbor { + key "ip"; + description + "A list of mappings from IPv6 addresses to + link-layer addresses. + + This list represents the Neighbor Cache."; + reference + "RFC 4861: Neighbor Discovery for IP version 6 (IPv6)"; + + leaf ip { + type inet:ipv6-address-no-zone; + description + "The IPv6 address of the neighbor node."; + } + leaf link-layer-address { + type yang:phys-address; + description + "The link-layer address of the neighbor node."; + } + leaf origin { + type neighbor-origin; + description + "The origin of this neighbor entry."; + } + leaf is-router { + type empty; + description + "Indicates that the neighbor node acts as a router."; + } + leaf state { + type enumeration { + enum incomplete { + description + "Address resolution is in progress, and the link-layer + address of the neighbor has not yet been + determined."; + } + enum reachable { + description + "Roughly speaking, the neighbor is known to have been + reachable recently (within tens of seconds ago)."; + } + enum stale { + description + "The neighbor is no longer known to be reachable, but + until traffic is sent to the neighbor no attempt + should be made to verify its reachability."; + } + enum delay { + description + "The neighbor is no longer known to be reachable, and + traffic has recently been sent to the neighbor. + Rather than probe the neighbor immediately, however, + delay sending probes for a short while in order to + give upper-layer protocols a chance to provide + reachability confirmation."; + } + enum probe { + description + "The neighbor is no longer known to be reachable, and + unicast Neighbor Solicitation probes are being sent + to verify reachability."; + } + } + description + "The Neighbor Unreachability Detection state of this + entry."; + reference + "RFC 4861: Neighbor Discovery for IP version 6 (IPv6) + Section 7.3.2"; + } + } + } + } +} diff --git a/tests/yanglint/modules/ietf-netconf-acm.yang b/tests/yanglint/modules/ietf-netconf-acm.yang new file mode 100644 index 0000000..d372fa0 --- /dev/null +++ b/tests/yanglint/modules/ietf-netconf-acm.yang @@ -0,0 +1,411 @@ +module ietf-netconf-acm { + namespace "urn:ietf:params:xml:ns:yang:ietf-netconf-acm"; + prefix nacm; + + import ietf-yang-types { + prefix yang; + } + + organization + "IETF NETCONF (Network Configuration) Working Group"; + contact + "WG Web: <http://tools.ietf.org/wg/netconf/> + WG List: <mailto:netconf@ietf.org> + + WG Chair: Mehmet Ersue + <mailto:mehmet.ersue@nsn.com> + + WG Chair: Bert Wijnen + <mailto:bertietf@bwijnen.net> + + Editor: Andy Bierman + <mailto:andy@yumaworks.com> + + Editor: Martin Bjorklund + <mailto:mbj@tail-f.com>"; + description + "NETCONF Access Control Model. + + Copyright (c) 2012 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD + License set forth in Section 4.c of the IETF Trust's + Legal Provisions Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC 6536; see + the RFC itself for full legal notices."; + + revision 2012-02-22 { + description + "Initial version"; + reference + "RFC 6536: Network Configuration Protocol (NETCONF) + Access Control Model"; + } + + extension default-deny-write { + description + "Used to indicate that the data model node + represents a sensitive security system parameter. + + If present, and the NACM module is enabled (i.e., + /nacm/enable-nacm object equals 'true'), the NETCONF server + will only allow the designated 'recovery session' to have + write access to the node. An explicit access control rule is + required for all other users. + + The 'default-deny-write' extension MAY appear within a data + definition statement. It is ignored otherwise."; + } + + extension default-deny-all { + description + "Used to indicate that the data model node + controls a very sensitive security system parameter. + + If present, and the NACM module is enabled (i.e., + /nacm/enable-nacm object equals 'true'), the NETCONF server + will only allow the designated 'recovery session' to have + read, write, or execute access to the node. An explicit + access control rule is required for all other users. + + The 'default-deny-all' extension MAY appear within a data + definition statement, 'rpc' statement, or 'notification' + statement. It is ignored otherwise."; + } + + typedef user-name-type { + type string { + length "1..max"; + } + description + "General Purpose Username string."; + } + + typedef matchall-string-type { + type string { + pattern "\\*"; + } + description + "The string containing a single asterisk '*' is used + to conceptually represent all possible values + for the particular leaf using this data type."; + } + + typedef access-operations-type { + type bits { + bit create { + description + "Any protocol operation that creates a + new data node."; + } + bit read { + description + "Any protocol operation or notification that + returns the value of a data node."; + } + bit update { + description + "Any protocol operation that alters an existing + data node."; + } + bit delete { + description + "Any protocol operation that removes a data node."; + } + bit exec { + description + "Execution access to the specified protocol operation."; + } + } + description + "NETCONF Access Operation."; + } + + typedef group-name-type { + type string { + length "1..max"; + pattern "[^\\*].*"; + } + description + "Name of administrative group to which + users can be assigned."; + } + + typedef action-type { + type enumeration { + enum "permit" { + description + "Requested action is permitted."; + } + enum "deny" { + description + "Requested action is denied."; + } + } + description + "Action taken by the server when a particular + rule matches."; + } + + typedef node-instance-identifier { + type yang:xpath1.0; + description + "Path expression used to represent a special + data node instance identifier string. + + A node-instance-identifier value is an + unrestricted YANG instance-identifier expression. + All the same rules as an instance-identifier apply + except predicates for keys are optional. If a key + predicate is missing, then the node-instance-identifier + represents all possible server instances for that key. + + This XPath expression is evaluated in the following context: + + o The set of namespace declarations are those in scope on + the leaf element where this type is used. + + o The set of variable bindings contains one variable, + 'USER', which contains the name of the user of the current + session. + + o The function library is the core function library, but + note that due to the syntax restrictions of an + instance-identifier, no functions are allowed. + + o The context node is the root node in the data tree."; + } + + container nacm { + nacm:default-deny-all; + description + "Parameters for NETCONF Access Control Model."; + leaf enable-nacm { + type boolean; + default "true"; + description + "Enables or disables all NETCONF access control + enforcement. If 'true', then enforcement + is enabled. If 'false', then enforcement + is disabled."; + } + leaf read-default { + type action-type; + default "permit"; + description + "Controls whether read access is granted if + no appropriate rule is found for a + particular read request."; + } + leaf write-default { + type action-type; + default "deny"; + description + "Controls whether create, update, or delete access + is granted if no appropriate rule is found for a + particular write request."; + } + leaf exec-default { + type action-type; + default "permit"; + description + "Controls whether exec access is granted if no appropriate + rule is found for a particular protocol operation request."; + } + leaf enable-external-groups { + type boolean; + default "true"; + description + "Controls whether the server uses the groups reported by the + NETCONF transport layer when it assigns the user to a set of + NACM groups. If this leaf has the value 'false', any group + names reported by the transport layer are ignored by the + server."; + } + leaf denied-operations { + type yang:zero-based-counter32; + config false; + mandatory true; + description + "Number of times since the server last restarted that a + protocol operation request was denied."; + } + leaf denied-data-writes { + type yang:zero-based-counter32; + config false; + mandatory true; + description + "Number of times since the server last restarted that a + protocol operation request to alter + a configuration datastore was denied."; + } + leaf denied-notifications { + type yang:zero-based-counter32; + config false; + mandatory true; + description + "Number of times since the server last restarted that + a notification was dropped for a subscription because + access to the event type was denied."; + } + container groups { + description + "NETCONF Access Control Groups."; + list group { + key "name"; + description + "One NACM Group Entry. This list will only contain + configured entries, not any entries learned from + any transport protocols."; + leaf name { + type group-name-type; + description + "Group name associated with this entry."; + } + leaf-list user-name { + type user-name-type; + description + "Each entry identifies the username of + a member of the group associated with + this entry."; + } + } + } + list rule-list { + key "name"; + ordered-by user; + description + "An ordered collection of access control rules."; + leaf name { + type string { + length "1..max"; + } + description + "Arbitrary name assigned to the rule-list."; + } + leaf-list group { + type union { + type matchall-string-type; + type group-name-type; + } + description + "List of administrative groups that will be + assigned the associated access rights + defined by the 'rule' list. + + The string '*' indicates that all groups apply to the + entry."; + } + list rule { + key "name"; + ordered-by user; + description + "One access control rule. + + Rules are processed in user-defined order until a match is + found. A rule matches if 'module-name', 'rule-type', and + 'access-operations' match the request. If a rule + matches, the 'action' leaf determines if access is granted + or not."; + leaf name { + type string { + length "1..max"; + } + description + "Arbitrary name assigned to the rule."; + } + leaf module-name { + type union { + type matchall-string-type; + type string; + } + default "*"; + description + "Name of the module associated with this rule. + + This leaf matches if it has the value '*' or if the + object being accessed is defined in the module with the + specified module name."; + } + choice rule-type { + description + "This choice matches if all leafs present in the rule + match the request. If no leafs are present, the + choice matches all requests."; + case protocol-operation { + leaf rpc-name { + type union { + type matchall-string-type; + type string; + } + description + "This leaf matches if it has the value '*' or if + its value equals the requested protocol operation + name."; + } + } + case notification { + leaf notification-name { + type union { + type matchall-string-type; + type string; + } + description + "This leaf matches if it has the value '*' or if its + value equals the requested notification name."; + } + } + case data-node { + leaf path { + type node-instance-identifier; + mandatory true; + description + "Data Node Instance Identifier associated with the + data node controlled by this rule. + + Configuration data or state data instance + identifiers start with a top-level data node. A + complete instance identifier is required for this + type of path value. + + The special value '/' refers to all possible + datastore contents."; + } + } + } + leaf access-operations { + type union { + type matchall-string-type; + type access-operations-type; + } + default "*"; + description + "Access operations associated with this rule. + + This leaf matches if it has the value '*' or if the + bit corresponding to the requested operation is set."; + } + leaf action { + type action-type; + mandatory true; + description + "The access control action associated with the + rule. If a rule is determined to match a + particular request, then this object is used + to determine whether to permit or deny the + request."; + } + leaf comment { + type string; + description + "A textual description of the access rule."; + } + } + } + } +} diff --git a/tests/yanglint/modules/ietf-netconf-with-defaults@2011-06-01.yang b/tests/yanglint/modules/ietf-netconf-with-defaults@2011-06-01.yang new file mode 100644 index 0000000..e19d2b3 --- /dev/null +++ b/tests/yanglint/modules/ietf-netconf-with-defaults@2011-06-01.yang @@ -0,0 +1,140 @@ +module ietf-netconf-with-defaults { + + namespace "urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults"; + + prefix ncwd; + + import ietf-netconf { prefix nc; } + + organization + "IETF NETCONF (Network Configuration Protocol) Working Group"; + + contact + "WG Web: <http://tools.ietf.org/wg/netconf/> + + WG List: <netconf@ietf.org> + + WG Chair: Bert Wijnen + <bertietf@bwijnen.net> + + WG Chair: Mehmet Ersue + <mehmet.ersue@nsn.com> + + Editor: Andy Bierman + <andy.bierman@brocade.com> + + Editor: Balazs Lengyel + <balazs.lengyel@ericsson.com>"; + + description + "This module defines an extension to the NETCONF protocol + that allows the NETCONF client to control how default + values are handled by the server in particular NETCONF + operations. + + Copyright (c) 2011 IETF Trust and the persons identified as + the document authors. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC 6243; see + the RFC itself for full legal notices."; + + revision 2011-06-01 { + description + "Initial version."; + reference + "RFC 6243: With-defaults Capability for NETCONF"; + } + + typedef with-defaults-mode { + description + "Possible modes to report default data."; + reference + "RFC 6243; Section 3."; + type enumeration { + enum report-all { + description + "All default data is reported."; + reference + "RFC 6243; Section 3.1"; + } + enum report-all-tagged { + description + "All default data is reported. + Any nodes considered to be default data + will contain a 'default' XML attribute, + set to 'true' or '1'."; + reference + "RFC 6243; Section 3.4"; + } + enum trim { + description + "Values are not reported if they contain the default."; + reference + "RFC 6243; Section 3.2"; + } + enum explicit { + description + "Report values that contain the definition of + explicitly set data."; + reference + "RFC 6243; Section 3.3"; + } + } + } + + grouping with-defaults-parameters { + description + "Contains the <with-defaults> parameter for control + of defaults in NETCONF retrieval operations."; + + leaf with-defaults { + description + "The explicit defaults processing mode requested."; + reference + "RFC 6243; Section 4.5.1"; + + type with-defaults-mode; + } + } + + // extending the get-config operation + augment /nc:get-config/nc:input { + description + "Adds the <with-defaults> parameter to the + input of the NETCONF <get-config> operation."; + reference + "RFC 6243; Section 4.5.1"; + + uses with-defaults-parameters; + } + + // extending the get operation + augment /nc:get/nc:input { + description + "Adds the <with-defaults> parameter to + the input of the NETCONF <get> operation."; + reference + "RFC 6243; Section 4.5.1"; + + uses with-defaults-parameters; + } + + // extending the copy-config operation + augment /nc:copy-config/nc:input { + description + "Adds the <with-defaults> parameter to + the input of the NETCONF <copy-config> operation."; + reference + "RFC 6243; Section 4.5.1"; + + uses with-defaults-parameters; + } + +} diff --git a/tests/yanglint/modules/ietf-netconf@2011-06-01.yang b/tests/yanglint/modules/ietf-netconf@2011-06-01.yang new file mode 100644 index 0000000..3053db2 --- /dev/null +++ b/tests/yanglint/modules/ietf-netconf@2011-06-01.yang @@ -0,0 +1,934 @@ +module ietf-netconf { + + // the namespace for NETCONF XML definitions is unchanged + // from RFC 4741, which this document replaces + namespace "urn:ietf:params:xml:ns:netconf:base:1.0"; + + prefix nc; + + import ietf-inet-types { + prefix inet; + } + + import ietf-netconf-acm { prefix nacm; } + + organization + "IETF NETCONF (Network Configuration) Working Group"; + + contact + "WG Web: <http://tools.ietf.org/wg/netconf/> + WG List: <netconf@ietf.org> + + WG Chair: Bert Wijnen + <bertietf@bwijnen.net> + + WG Chair: Mehmet Ersue + <mehmet.ersue@nsn.com> + + Editor: Martin Bjorklund + <mbj@tail-f.com> + + Editor: Juergen Schoenwaelder + <j.schoenwaelder@jacobs-university.de> + + Editor: Andy Bierman + <andy.bierman@brocade.com>"; + description + "NETCONF Protocol Data Types and Protocol Operations. + + Copyright (c) 2011 IETF Trust and the persons identified as + the document authors. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC 6241; see + the RFC itself for full legal notices."; + + revision 2011-06-01 { + description + "Initial revision; + 2013-09-29: Updated to include NACM attributes, + as specified in RFC 6536: sec 3.2.5 and 3.2.8"; + reference + "RFC 6241: Network Configuration Protocol"; + } + + extension get-filter-element-attributes { + description + "If this extension is present within an 'anyxml' + statement named 'filter', which must be conceptually + defined within the RPC input section for the <get> + and <get-config> protocol operations, then the + following unqualified XML attribute is supported + within the <filter> element, within a <get> or + <get-config> protocol operation: + + type : optional attribute with allowed + value strings 'subtree' and 'xpath'. + If missing, the default value is 'subtree'. + + If the 'xpath' feature is supported, then the + following unqualified XML attribute is + also supported: + + select: optional attribute containing a + string representing an XPath expression. + The 'type' attribute must be equal to 'xpath' + if this attribute is present."; + } + + // NETCONF capabilities defined as features + feature writable-running { + description + "NETCONF :writable-running capability; + If the server advertises the :writable-running + capability for a session, then this feature must + also be enabled for that session. Otherwise, + this feature must not be enabled."; + reference "RFC 6241, Section 8.2"; + } + + feature candidate { + description + "NETCONF :candidate capability; + If the server advertises the :candidate + capability for a session, then this feature must + also be enabled for that session. Otherwise, + this feature must not be enabled."; + reference "RFC 6241, Section 8.3"; + } + + feature confirmed-commit { + if-feature candidate; + description + "NETCONF :confirmed-commit:1.1 capability; + If the server advertises the :confirmed-commit:1.1 + capability for a session, then this feature must + also be enabled for that session. Otherwise, + this feature must not be enabled."; + + reference "RFC 6241, Section 8.4"; + } + + feature rollback-on-error { + description + "NETCONF :rollback-on-error capability; + If the server advertises the :rollback-on-error + capability for a session, then this feature must + also be enabled for that session. Otherwise, + this feature must not be enabled."; + reference "RFC 6241, Section 8.5"; + } + + feature validate { + description + "NETCONF :validate:1.1 capability; + If the server advertises the :validate:1.1 + capability for a session, then this feature must + also be enabled for that session. Otherwise, + this feature must not be enabled."; + reference "RFC 6241, Section 8.6"; + } + + feature startup { + description + "NETCONF :startup capability; + If the server advertises the :startup + capability for a session, then this feature must + also be enabled for that session. Otherwise, + this feature must not be enabled."; + reference "RFC 6241, Section 8.7"; + } + + feature url { + description + "NETCONF :url capability; + If the server advertises the :url + capability for a session, then this feature must + also be enabled for that session. Otherwise, + this feature must not be enabled."; + reference "RFC 6241, Section 8.8"; + } + + feature xpath { + description + "NETCONF :xpath capability; + If the server advertises the :xpath + capability for a session, then this feature must + also be enabled for that session. Otherwise, + this feature must not be enabled."; + reference "RFC 6241, Section 8.9"; + } + + // NETCONF Simple Types + + typedef session-id-type { + type uint32 { + range "1..max"; + } + description + "NETCONF Session Id"; + } + + typedef session-id-or-zero-type { + type uint32; + description + "NETCONF Session Id or Zero to indicate none"; + } + typedef error-tag-type { + type enumeration { + enum in-use { + description + "The request requires a resource that + already is in use."; + } + enum invalid-value { + description + "The request specifies an unacceptable value for one + or more parameters."; + } + enum too-big { + description + "The request or response (that would be generated) is + too large for the implementation to handle."; + } + enum missing-attribute { + description + "An expected attribute is missing."; + } + enum bad-attribute { + description + "An attribute value is not correct; e.g., wrong type, + out of range, pattern mismatch."; + } + enum unknown-attribute { + description + "An unexpected attribute is present."; + } + enum missing-element { + description + "An expected element is missing."; + } + enum bad-element { + description + "An element value is not correct; e.g., wrong type, + out of range, pattern mismatch."; + } + enum unknown-element { + description + "An unexpected element is present."; + } + enum unknown-namespace { + description + "An unexpected namespace is present."; + } + enum access-denied { + description + "Access to the requested protocol operation or + data model is denied because authorization failed."; + } + enum lock-denied { + description + "Access to the requested lock is denied because the + lock is currently held by another entity."; + } + enum resource-denied { + description + "Request could not be completed because of + insufficient resources."; + } + enum rollback-failed { + description + "Request to roll back some configuration change (via + rollback-on-error or <discard-changes> operations) + was not completed for some reason."; + + } + enum data-exists { + description + "Request could not be completed because the relevant + data model content already exists. For example, + a 'create' operation was attempted on data that + already exists."; + } + enum data-missing { + description + "Request could not be completed because the relevant + data model content does not exist. For example, + a 'delete' operation was attempted on + data that does not exist."; + } + enum operation-not-supported { + description + "Request could not be completed because the requested + operation is not supported by this implementation."; + } + enum operation-failed { + description + "Request could not be completed because the requested + operation failed for some reason not covered by + any other error condition."; + } + enum partial-operation { + description + "This error-tag is obsolete, and SHOULD NOT be sent + by servers conforming to this document."; + } + enum malformed-message { + description + "A message could not be handled because it failed to + be parsed correctly. For example, the message is not + well-formed XML or it uses an invalid character set."; + } + } + description "NETCONF Error Tag"; + reference "RFC 6241, Appendix A"; + } + + typedef error-severity-type { + type enumeration { + enum error { + description "Error severity"; + } + enum warning { + description "Warning severity"; + } + } + description "NETCONF Error Severity"; + reference "RFC 6241, Section 4.3"; + } + + typedef edit-operation-type { + type enumeration { + enum merge { + description + "The configuration data identified by the + element containing this attribute is merged + with the configuration at the corresponding + level in the configuration datastore identified + by the target parameter."; + } + enum replace { + description + "The configuration data identified by the element + containing this attribute replaces any related + configuration in the configuration datastore + identified by the target parameter. If no such + configuration data exists in the configuration + datastore, it is created. Unlike a + <copy-config> operation, which replaces the + entire target configuration, only the configuration + actually present in the config parameter is affected."; + } + enum create { + description + "The configuration data identified by the element + containing this attribute is added to the + configuration if and only if the configuration + data does not already exist in the configuration + datastore. If the configuration data exists, an + <rpc-error> element is returned with an + <error-tag> value of 'data-exists'."; + } + enum delete { + description + "The configuration data identified by the element + containing this attribute is deleted from the + configuration if and only if the configuration + data currently exists in the configuration + datastore. If the configuration data does not + exist, an <rpc-error> element is returned with + an <error-tag> value of 'data-missing'."; + } + enum remove { + description + "The configuration data identified by the element + containing this attribute is deleted from the + configuration if the configuration + data currently exists in the configuration + datastore. If the configuration data does not + exist, the 'remove' operation is silently ignored + by the server."; + } + } + default "merge"; + description "NETCONF 'operation' attribute values"; + reference "RFC 6241, Section 7.2"; + } + + // NETCONF Standard Protocol Operations + + rpc get-config { + description + "Retrieve all or part of a specified configuration."; + + reference "RFC 6241, Section 7.1"; + + input { + container source { + description + "Particular configuration to retrieve."; + + choice config-source { + mandatory true; + description + "The configuration to retrieve."; + leaf candidate { + if-feature candidate; + type empty; + description + "The candidate configuration is the config source."; + } + leaf running { + type empty; + description + "The running configuration is the config source."; + } + leaf startup { + if-feature startup; + type empty; + description + "The startup configuration is the config source. + This is optional-to-implement on the server because + not all servers will support filtering for this + datastore."; + } + } + } + + anyxml filter { + description + "Subtree or XPath filter to use."; + nc:get-filter-element-attributes; + } + } + + output { + anyxml data { + description + "Copy of the source datastore subset that matched + the filter criteria (if any). An empty data container + indicates that the request did not produce any results."; + } + } + } + + rpc edit-config { + description + "The <edit-config> operation loads all or part of a specified + configuration to the specified target configuration."; + + reference "RFC 6241, Section 7.2"; + + input { + container target { + description + "Particular configuration to edit."; + + choice config-target { + mandatory true; + description + "The configuration target."; + + leaf candidate { + if-feature candidate; + type empty; + description + "The candidate configuration is the config target."; + } + leaf running { + if-feature writable-running; + type empty; + description + "The running configuration is the config source."; + } + } + } + + leaf default-operation { + type enumeration { + enum merge { + description + "The default operation is merge."; + } + enum replace { + description + "The default operation is replace."; + } + enum none { + description + "There is no default operation."; + } + } + default "merge"; + description + "The default operation to use."; + } + + leaf test-option { + if-feature validate; + type enumeration { + enum test-then-set { + description + "The server will test and then set if no errors."; + } + enum set { + description + "The server will set without a test first."; + } + + enum test-only { + description + "The server will only test and not set, even + if there are no errors."; + } + } + default "test-then-set"; + description + "The test option to use."; + } + + leaf error-option { + type enumeration { + enum stop-on-error { + description + "The server will stop on errors."; + } + enum continue-on-error { + description + "The server may continue on errors."; + } + enum rollback-on-error { + description + "The server will roll back on errors. + This value can only be used if the 'rollback-on-error' + feature is supported."; + } + } + default "stop-on-error"; + description + "The error option to use."; + } + + choice edit-content { + mandatory true; + description + "The content for the edit operation."; + + anyxml config { + description + "Inline Config content."; + } + leaf url { + if-feature url; + type inet:uri; + description + "URL-based config content."; + } + } + } + } + + rpc copy-config { + description + "Create or replace an entire configuration datastore with the + contents of another complete configuration datastore."; + + reference "RFC 6241, Section 7.3"; + + input { + container target { + description + "Particular configuration to copy to."; + + choice config-target { + mandatory true; + description + "The configuration target of the copy operation."; + + leaf candidate { + if-feature candidate; + type empty; + description + "The candidate configuration is the config target."; + } + leaf running { + if-feature writable-running; + type empty; + description + "The running configuration is the config target. + This is optional-to-implement on the server."; + } + leaf startup { + if-feature startup; + type empty; + description + "The startup configuration is the config target."; + } + leaf url { + if-feature url; + type inet:uri; + description + "The URL-based configuration is the config target."; + } + } + } + + container source { + description + "Particular configuration to copy from."; + + choice config-source { + mandatory true; + description + "The configuration source for the copy operation."; + + leaf candidate { + if-feature candidate; + type empty; + description + "The candidate configuration is the config source."; + } + leaf running { + type empty; + description + "The running configuration is the config source."; + } + leaf startup { + if-feature startup; + type empty; + description + "The startup configuration is the config source."; + } + leaf url { + if-feature url; + type inet:uri; + description + "The URL-based configuration is the config source."; + } + anyxml config { + description + "Inline Config content: <config> element. Represents + an entire configuration datastore, not + a subset of the running datastore."; + } + } + } + } + } + + rpc delete-config { + nacm:default-deny-all; + description + "Delete a configuration datastore."; + + reference "RFC 6241, Section 7.4"; + + input { + container target { + description + "Particular configuration to delete."; + + choice config-target { + mandatory true; + description + "The configuration target to delete."; + + leaf startup { + if-feature startup; + type empty; + description + "The startup configuration is the config target."; + } + leaf url { + if-feature url; + type inet:uri; + description + "The URL-based configuration is the config target."; + } + } + } + } + } + + rpc lock { + description + "The lock operation allows the client to lock the configuration + system of a device."; + + reference "RFC 6241, Section 7.5"; + + input { + container target { + description + "Particular configuration to lock."; + + choice config-target { + mandatory true; + description + "The configuration target to lock."; + + leaf candidate { + if-feature candidate; + type empty; + description + "The candidate configuration is the config target."; + } + leaf running { + type empty; + description + "The running configuration is the config target."; + } + leaf startup { + if-feature startup; + type empty; + description + "The startup configuration is the config target."; + } + } + } + } + } + + rpc unlock { + description + "The unlock operation is used to release a configuration lock, + previously obtained with the 'lock' operation."; + + reference "RFC 6241, Section 7.6"; + + input { + container target { + description + "Particular configuration to unlock."; + + choice config-target { + mandatory true; + description + "The configuration target to unlock."; + + leaf candidate { + if-feature candidate; + type empty; + description + "The candidate configuration is the config target."; + } + leaf running { + type empty; + description + "The running configuration is the config target."; + } + leaf startup { + if-feature startup; + type empty; + description + "The startup configuration is the config target."; + } + } + } + } + } + + rpc get { + description + "Retrieve running configuration and device state information."; + + reference "RFC 6241, Section 7.7"; + + input { + anyxml filter { + description + "This parameter specifies the portion of the system + configuration and state data to retrieve."; + nc:get-filter-element-attributes; + } + } + + output { + anyxml data { + description + "Copy of the running datastore subset and/or state + data that matched the filter criteria (if any). + An empty data container indicates that the request did not + produce any results."; + } + } + } + + rpc close-session { + description + "Request graceful termination of a NETCONF session."; + + reference "RFC 6241, Section 7.8"; + } + + rpc kill-session { + nacm:default-deny-all; + description + "Force the termination of a NETCONF session."; + + reference "RFC 6241, Section 7.9"; + + input { + leaf session-id { + type session-id-type; + mandatory true; + description + "Particular session to kill."; + } + } + } + + rpc commit { + if-feature candidate; + + description + "Commit the candidate configuration as the device's new + current configuration."; + + reference "RFC 6241, Section 8.3.4.1"; + + input { + leaf confirmed { + if-feature confirmed-commit; + type empty; + description + "Requests a confirmed commit."; + reference "RFC 6241, Section 8.3.4.1"; + } + + leaf confirm-timeout { + if-feature confirmed-commit; + type uint32 { + range "1..max"; + } + units "seconds"; + default "600"; // 10 minutes + description + "The timeout interval for a confirmed commit."; + reference "RFC 6241, Section 8.3.4.1"; + } + + leaf persist { + if-feature confirmed-commit; + type string; + description + "This parameter is used to make a confirmed commit + persistent. A persistent confirmed commit is not aborted + if the NETCONF session terminates. The only way to abort + a persistent confirmed commit is to let the timer expire, + or to use the <cancel-commit> operation. + + The value of this parameter is a token that must be given + in the 'persist-id' parameter of <commit> or + <cancel-commit> operations in order to confirm or cancel + the persistent confirmed commit. + + The token should be a random string."; + reference "RFC 6241, Section 8.3.4.1"; + } + + leaf persist-id { + if-feature confirmed-commit; + type string; + description + "This parameter is given in order to commit a persistent + confirmed commit. The value must be equal to the value + given in the 'persist' parameter to the <commit> operation. + If it does not match, the operation fails with an + 'invalid-value' error."; + reference "RFC 6241, Section 8.3.4.1"; + } + + } + } + + rpc discard-changes { + if-feature candidate; + + description + "Revert the candidate configuration to the current + running configuration."; + reference "RFC 6241, Section 8.3.4.2"; + } + + rpc cancel-commit { + if-feature confirmed-commit; + description + "This operation is used to cancel an ongoing confirmed commit. + If the confirmed commit is persistent, the parameter + 'persist-id' must be given, and it must match the value of the + 'persist' parameter."; + reference "RFC 6241, Section 8.4.4.1"; + + input { + leaf persist-id { + type string; + description + "This parameter is given in order to cancel a persistent + confirmed commit. The value must be equal to the value + given in the 'persist' parameter to the <commit> operation. + If it does not match, the operation fails with an + 'invalid-value' error."; + } + } + } + + rpc validate { + if-feature validate; + + description + "Validates the contents of the specified configuration."; + + reference "RFC 6241, Section 8.6.4.1"; + + input { + container source { + description + "Particular configuration to validate."; + + choice config-source { + mandatory true; + description + "The configuration source to validate."; + + leaf candidate { + if-feature candidate; + type empty; + description + "The candidate configuration is the config source."; + } + leaf running { + type empty; + description + "The running configuration is the config source."; + } + leaf startup { + if-feature startup; + type empty; + description + "The startup configuration is the config source."; + } + leaf url { + if-feature url; + type inet:uri; + description + "The URL-based configuration is the config source."; + } + anyxml config { + description + "Inline Config content: <config> element. Represents + an entire configuration datastore, not + a subset of the running datastore."; + } + } + } + } + } + +} diff --git a/tests/yanglint/modules/modaction.yang b/tests/yanglint/modules/modaction.yang new file mode 100644 index 0000000..5a3f92f --- /dev/null +++ b/tests/yanglint/modules/modaction.yang @@ -0,0 +1,26 @@ +module modaction { + yang-version 1.1; + namespace "urn:yanglint:modaction"; + prefix ma; + + container con { + list ls { + key "lfkey"; + leaf lfkey { + type string; + } + action act { + input { + leaf lfi { + type string; + } + } + output { + leaf lfo { + type int16; + } + } + } + } + } +} diff --git a/tests/yanglint/modules/modconfig-augment.yang b/tests/yanglint/modules/modconfig-augment.yang new file mode 100644 index 0000000..d94b366 --- /dev/null +++ b/tests/yanglint/modules/modconfig-augment.yang @@ -0,0 +1,15 @@ +module modconfig-augment { + yang-version 1.1; + namespace "urn:yanglint:modconfig-augment"; + prefix "mca"; + + import modconfig { + prefix mc; + } + + augment "/mc:mcc" { + leaf alf { + type string; + } + } +} diff --git a/tests/yanglint/modules/modconfig.yang b/tests/yanglint/modules/modconfig.yang new file mode 100644 index 0000000..1d12ca6 --- /dev/null +++ b/tests/yanglint/modules/modconfig.yang @@ -0,0 +1,17 @@ +module modconfig { + namespace "urn:yanglint:modconfig"; + prefix mc; + + container mcc { + leaf lft { + type string; + config true; + mandatory true; + } + leaf lff { + type string; + config false; + mandatory true; + } + } +} diff --git a/tests/yanglint/modules/moddatanodes.yang b/tests/yanglint/modules/moddatanodes.yang new file mode 100644 index 0000000..ae4ab20 --- /dev/null +++ b/tests/yanglint/modules/moddatanodes.yang @@ -0,0 +1,31 @@ +module moddatanodes { + yang-version 1.1; + namespace "urn:yanglint:moddatanodes"; + prefix mdn; + + container dnc { + leaf lf { + type string; + } + leaf-list lfl { + type string; + } + leaf mis { + type string; + } + container con { + list lt { + key "kalf kblf"; + leaf kalf { + type string; + } + leaf kblf { + type string; + } + leaf vlf { + type string; + } + } + } + } +} diff --git a/tests/yanglint/modules/moddefault.yang b/tests/yanglint/modules/moddefault.yang new file mode 100644 index 0000000..26570c3 --- /dev/null +++ b/tests/yanglint/modules/moddefault.yang @@ -0,0 +1,19 @@ +module moddefault { + namespace "urn:yanglint:moddefault"; + prefix md; + + container mdc { + leaf lf { + type uint16; + } + leaf di { + type int16; + default "5"; + } + leaf ds { + type string; + default "str"; + } + } + +} diff --git a/tests/yanglint/modules/modextleafref.yang b/tests/yanglint/modules/modextleafref.yang new file mode 100644 index 0000000..d45ec71 --- /dev/null +++ b/tests/yanglint/modules/modextleafref.yang @@ -0,0 +1,24 @@ +module modextleafref { + namespace "urn:yanglint:modextleafref"; + prefix mel; + + list ls { + key k; + leaf k { + type string; + } + leaf lf { + type uint8; + } + } + leaf lfr { + type leafref { + path "../ls/k"; + } + } + leaf lfrderef { + type leafref { + path "deref(../lfr)/../lf"; + } + } +} diff --git a/tests/yanglint/modules/modfeature.yang b/tests/yanglint/modules/modfeature.yang new file mode 100644 index 0000000..f59d4c8 --- /dev/null +++ b/tests/yanglint/modules/modfeature.yang @@ -0,0 +1,7 @@ +module modfeature { + namespace "urn:yanglint:modfeature"; + prefix l; + + feature ftr1; + feature ftr2; +} diff --git a/tests/yanglint/modules/modimp-cwd.yang b/tests/yanglint/modules/modimp-cwd.yang new file mode 100644 index 0000000..3249462 --- /dev/null +++ b/tests/yanglint/modules/modimp-cwd.yang @@ -0,0 +1,8 @@ +module modimp-cwd { + namespace "urn:yanglint:modimp-cwd"; + prefix ic; + + import modcwd { + prefix mc; + } +} diff --git a/tests/yanglint/modules/modimp-path.yang b/tests/yanglint/modules/modimp-path.yang new file mode 100644 index 0000000..d9dbb9b --- /dev/null +++ b/tests/yanglint/modules/modimp-path.yang @@ -0,0 +1,8 @@ +module modimp-path { + namespace "urn:yanglint:modimp-path"; + prefix ip; + + import modpath { + prefix mp; + } +} diff --git a/tests/yanglint/modules/modimp-type.yang b/tests/yanglint/modules/modimp-type.yang new file mode 100644 index 0000000..ec21d31 --- /dev/null +++ b/tests/yanglint/modules/modimp-type.yang @@ -0,0 +1,12 @@ +module modimp-type { + namespace "urn:yanglint:modimp-type"; + prefix mit; + + import modtypedef { + prefix mtd; + } + + leaf lf { + type mtd:mui8; + } +} diff --git a/tests/yanglint/modules/modinclude.yang b/tests/yanglint/modules/modinclude.yang new file mode 100644 index 0000000..849d43f --- /dev/null +++ b/tests/yanglint/modules/modinclude.yang @@ -0,0 +1,9 @@ +module modinclude { + yang-version 1.1; + namespace "urn:yanglint:modinclude"; + prefix mi; + + include "modsub"; + + container mic; +} diff --git a/tests/yanglint/modules/modleaf.yang b/tests/yanglint/modules/modleaf.yang new file mode 100644 index 0000000..48ce786 --- /dev/null +++ b/tests/yanglint/modules/modleaf.yang @@ -0,0 +1,8 @@ +module modleaf { + namespace "urn:yanglint:modleaf"; + prefix l; + + leaf lfl { + type uint16; + } +} diff --git a/tests/yanglint/modules/modleafref.yang b/tests/yanglint/modules/modleafref.yang new file mode 100644 index 0000000..f86fb3f --- /dev/null +++ b/tests/yanglint/modules/modleafref.yang @@ -0,0 +1,14 @@ +module modleafref { + namespace "urn:yanglint:modleafref"; + prefix m; + + import modleaf { + prefix ml; + } + + leaf lfr { + type leafref { + path "/ml:lfl"; + } + } +} diff --git a/tests/yanglint/modules/modmandatory.yang b/tests/yanglint/modules/modmandatory.yang new file mode 100644 index 0000000..4d48540 --- /dev/null +++ b/tests/yanglint/modules/modmandatory.yang @@ -0,0 +1,14 @@ +module modmandatory { + namespace "urn:yanglint:modmandatory"; + prefix mm; + + container mmc { + leaf lft { + type int16; + mandatory true; + } + leaf lff { + type int16; + } + } +} diff --git a/tests/yanglint/modules/modmerge.yang b/tests/yanglint/modules/modmerge.yang new file mode 100644 index 0000000..60fd75c --- /dev/null +++ b/tests/yanglint/modules/modmerge.yang @@ -0,0 +1,21 @@ +module modmerge { + namespace "urn:yanglint:modmerge"; + prefix mm; + + container mmc { + leaf en { + type enumeration { + enum zero; + enum one; + } + } + leaf lm { + type int16; + must "../en != 'zero'"; + } + leaf lf { + type string; + } + } + +} diff --git a/tests/yanglint/modules/modmust.yang b/tests/yanglint/modules/modmust.yang new file mode 100644 index 0000000..99971bd --- /dev/null +++ b/tests/yanglint/modules/modmust.yang @@ -0,0 +1,13 @@ +module modmust { + namespace "urn:yanglint:modmust"; + prefix m; + + import modleaf { + prefix ml; + } + + leaf lfm { + type string; + must "/ml:lfl > 0"; + } +} diff --git a/tests/yanglint/modules/modnotif.yang b/tests/yanglint/modules/modnotif.yang new file mode 100644 index 0000000..a2155a0 --- /dev/null +++ b/tests/yanglint/modules/modnotif.yang @@ -0,0 +1,19 @@ +module modnotif { + yang-version 1.1; + namespace "urn:yanglint:modnotif"; + prefix mn; + + container con { + notification nfn { + leaf lf { + type string; + } + } + } + + notification nfg { + leaf lf { + type string; + } + } +} diff --git a/tests/yanglint/modules/modoper-leafref.yang b/tests/yanglint/modules/modoper-leafref.yang new file mode 100644 index 0000000..36a1124 --- /dev/null +++ b/tests/yanglint/modules/modoper-leafref.yang @@ -0,0 +1,68 @@ +module modoper-leafref { + yang-version 1.1; + namespace "urn:yanglint:modoper-leafref"; + prefix mol; + + import modconfig { + prefix mc; + } + + container cond { + list list { + key "klf"; + leaf klf { + type string; + } + action act { + input { + leaf lfi { + type leafref { + path "/mc:mcc/mc:lft"; + } + } + } + output { + leaf lfo { + type leafref { + path "/mc:mcc/mc:lft"; + } + } + } + } + notification notif { + leaf lfn { + type leafref { + path "/mc:mcc/mc:lft"; + } + } + } + } + } + + rpc rpcg { + input { + leaf lfi { + type leafref { + path "/mc:mcc/mc:lft"; + } + } + } + output { + container cono { + leaf lfo { + type leafref { + path "/mc:mcc/mc:lft"; + } + } + } + } + } + + notification notifg { + leaf lfr { + type leafref { + path "/mc:mcc/mc:lft"; + } + } + } +} diff --git a/tests/yanglint/modules/modpath.yang b/tests/yanglint/modules/modpath.yang new file mode 100644 index 0000000..da099a2 --- /dev/null +++ b/tests/yanglint/modules/modpath.yang @@ -0,0 +1,4 @@ +module modpath { + namespace "urn:yanglint:modpath"; + prefix mp; +} diff --git a/tests/yanglint/modules/modrpc.yang b/tests/yanglint/modules/modrpc.yang new file mode 100644 index 0000000..dc0cced --- /dev/null +++ b/tests/yanglint/modules/modrpc.yang @@ -0,0 +1,19 @@ +module modrpc { + namespace "urn:yanglint:modrpc"; + prefix mr; + + rpc rpc { + input { + leaf lfi { + type string; + } + } + output { + container con { + leaf lfo { + type int16; + } + } + } + } +} diff --git a/tests/yanglint/modules/modsm-augment.yang b/tests/yanglint/modules/modsm-augment.yang new file mode 100644 index 0000000..5d16fbd --- /dev/null +++ b/tests/yanglint/modules/modsm-augment.yang @@ -0,0 +1,15 @@ +module modsm-augment { + yang-version 1.1; + namespace "urn:yanglint:modsm-augment"; + prefix "msa"; + + import modsm { + prefix msm; + } + + augment "/msm:root" { + leaf alf { + type string; + } + } +} diff --git a/tests/yanglint/modules/modsm.yang b/tests/yanglint/modules/modsm.yang new file mode 100644 index 0000000..dfe8830 --- /dev/null +++ b/tests/yanglint/modules/modsm.yang @@ -0,0 +1,13 @@ +module modsm { + yang-version 1.1; + namespace "urn:yanglint:modsm"; + prefix "msm"; + + import ietf-yang-schema-mount { + prefix sm; + } + + container root { + sm:mount-point "root"; + } +} diff --git a/tests/yanglint/modules/modsub.yang b/tests/yanglint/modules/modsub.yang new file mode 100644 index 0000000..79d9286 --- /dev/null +++ b/tests/yanglint/modules/modsub.yang @@ -0,0 +1,8 @@ +submodule modsub { + yang-version 1.1; + belongs-to modinclude { + prefix mi; + } + + container msc; +} diff --git a/tests/yanglint/modules/modtypedef.yang b/tests/yanglint/modules/modtypedef.yang new file mode 100644 index 0000000..ea09c95 --- /dev/null +++ b/tests/yanglint/modules/modtypedef.yang @@ -0,0 +1,8 @@ +module modtypedef { + namespace "urn:yanglint:typedef"; + prefix mt; + + typedef mui8 { + type uint8; + } +} diff --git a/tests/yanglint/non-interactive/all.tcl b/tests/yanglint/non-interactive/all.tcl new file mode 100644 index 0000000..998c03a --- /dev/null +++ b/tests/yanglint/non-interactive/all.tcl @@ -0,0 +1,15 @@ +package require tcltest + +# Hook to determine if any of the tests failed. +# Sets a global variable exitCode to 1 if any test fails otherwise it is set to 0. +proc tcltest::cleanupTestsHook {} { + variable numTests + set ::exitCode [expr {$numTests(Failed) > 0}] +} + +if {[info exists ::env(TESTS_DIR)]} { + tcltest::configure -testdir "$env(TESTS_DIR)/non-interactive" +} + +tcltest::runAllTests +exit $exitCode diff --git a/tests/yanglint/non-interactive/data_default.test b/tests/yanglint/non-interactive/data_default.test new file mode 100644 index 0000000..be19d72 --- /dev/null +++ b/tests/yanglint/non-interactive/data_default.test @@ -0,0 +1,31 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/non-interactive/ly.tcl" : "ly.tcl"}] + +set mods "$::env(YANG_MODULES_DIR)/ietf-netconf-with-defaults@2011-06-01.yang $::env(YANG_MODULES_DIR)/moddefault.yang" +set data "$::env(TESTS_DIR)/data/moddefault.xml" + +test data_default_not_set {Print data without --default parameter} { + ly_cmd "-f xml $mods $data" "</lf>.*</di>\n</mdc>" + ly_cmd "-f json $mods $data" "lf\".*di\"\[^\"]*" +} {} + +test data_default_all {data --default all} { + ly_cmd "-d all -f xml $mods $data" "</lf>.*</di>.*</ds>\n</mdc>" + ly_cmd "-d all -f json $mods $data" "lf\".*di\".*ds\"\[^\"]*" +} {} + +test data_default_all_tagged {data --default all-tagged} { + ly_cmd "-d all-tagged -f xml $mods $data" "</lf>.*<di.*default.*</di>.*<ds.*default.*</ds>\n</mdc>" + ly_cmd "-d all-tagged -f json $mods $data" "lf\".*di\".*ds\".*@ds\".*default\"\[^\"]*" +} {} + +test data_default_trim {data --default trim} { + ly_cmd "-d trim -f xml $mods $data" "</lf>\n</mdc>" + ly_cmd "-d trim -f json $mods $data" "lf\"\[^\"]*" +} {} + +test data_default_implicit_tagged {data --default implicit-tagged} { + ly_cmd "-d implicit-tagged -f xml $mods $data" "</lf>.*<di>5</di>.*<ds.*default.*</ds>\n</mdc>" + ly_cmd "-d implicit-tagged -f json $mods $data" "lf\".*di\"\[^@]*ds\".*default\"\[^\"]*" +} {} + +cleanupTests diff --git a/tests/yanglint/non-interactive/data_in_format.test b/tests/yanglint/non-interactive/data_in_format.test new file mode 100644 index 0000000..f1336dd --- /dev/null +++ b/tests/yanglint/non-interactive/data_in_format.test @@ -0,0 +1,18 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/non-interactive/ly.tcl" : "ly.tcl"}] + +set mdir $::env(YANG_MODULES_DIR) +set ddir $::env(TESTS_DIR)/data + +test data_in_format_xml {--in-format xml} { + ly_cmd "-I xml $mdir/modleaf.yang $ddir/modleaf.dxml" + ly_cmd_err "-I json $mdir/modleaf.yang $ddir/modleaf.dxml" "Failed to parse" + ly_cmd_err "-I lyb $mdir/modleaf.yang $ddir/modleaf.dxml" "Failed to parse" +} {} + +test data_in_format_json {--in-format json} { + ly_cmd "-I json $mdir/modleaf.yang $ddir/modleaf.djson" + ly_cmd_err "-I xml $mdir/modleaf.yang $ddir/modleaf.djson" "Failed to parse" + ly_cmd_err "-I lyb $mdir/modleaf.yang $ddir/modleaf.djson" "Failed to parse" +} {} + +cleanupTests diff --git a/tests/yanglint/non-interactive/data_merge.test b/tests/yanglint/non-interactive/data_merge.test new file mode 100644 index 0000000..4ecfcee --- /dev/null +++ b/tests/yanglint/non-interactive/data_merge.test @@ -0,0 +1,28 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/non-interactive/ly.tcl" : "ly.tcl"}] + +set mdir $::env(YANG_MODULES_DIR) +set ddir $::env(TESTS_DIR)/data + +test data_merge_basic {Data is merged and the node is added} { + ly_cmd "-m -f xml $mdir/modmerge.yang $ddir/modmerge.xml $ddir/modmerge3.xml" "<en>.*<lm>.*<lf>" +} {} + +test data_merge_validation_failed {Data is merged but validation failed.} { + ly_cmd "$mdir/modmerge.yang $ddir/modmerge.xml" + ly_cmd "$mdir/modmerge.yang $ddir/modmerge2.xml" + ly_cmd "-m $mdir/modmerge.yang $ddir/modmerge2.xml $ddir/modmerge.xml" + ly_cmd_err "-m $mdir/modmerge.yang $ddir/modmerge.xml $ddir/modmerge2.xml" "Merged data are not valid" +} {} + +test data_merge_dataconfig {The merge option has effect only for 'data' and 'config' TYPEs} { + set wrn1 "option has effect only for" + ly_cmd_wrn "-m -t rpc $mdir/modrpc.yang $ddir/modrpc.xml $ddir/modrpc.xml" $wrn1 + ly_cmd_wrn "-m -t notif $mdir/modnotif.yang $ddir/modnotif2.xml $ddir/modnotif2.xml" $wrn1 + ly_cmd_wrn "-m -t get $mdir/modconfig.yang $mdir/modleaf.yang $ddir/modleaf.xml $ddir/modconfig.xml" $wrn1 + ly_cmd_wrn "-m -t getconfig $mdir/modconfig.yang $mdir/modleaf.yang $ddir/modleaf.xml $ddir/modconfig2.xml" $wrn1 + ly_cmd_wrn "-m -t edit $mdir/modconfig.yang $mdir/modleaf.yang $ddir/modleaf.xml $ddir/modconfig2.xml" $wrn1 + ly_cmd "-m -t config $mdir/modconfig.yang $mdir/modleaf.yang $ddir/modleaf.xml $ddir/modconfig2.xml" + ly_cmd "-m -t data $mdir/modconfig.yang $mdir/modleaf.yang $ddir/modleaf.xml $ddir/modconfig.xml" +} {} + +cleanupTests diff --git a/tests/yanglint/non-interactive/data_not_strict.test b/tests/yanglint/non-interactive/data_not_strict.test new file mode 100644 index 0000000..b91eed8 --- /dev/null +++ b/tests/yanglint/non-interactive/data_not_strict.test @@ -0,0 +1,20 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/non-interactive/ly.tcl" : "ly.tcl"}] + +set mdir $::env(YANG_MODULES_DIR) +set ddir $::env(TESTS_DIR)/data + +test data_no_strict_basic {} { + ly_cmd_err "$ddir/modmandatory.xml $mdir/modleaf.yang" "No module with namespace \"urn:yanglint:modmandatory\" in the context." + ly_cmd "-n $ddir/modmandatory.xml $mdir/modleaf.yang" +} {} + +test data_no_strict_invalid_data {validation with --no-strict but data are invalid} { + set errmsg "Mandatory node \"lft\" instance does not exist." + ly_cmd_err "-n $ddir/modmandatory_invalid.xml $mdir/modmandatory.yang" $errmsg +} {} + +test data_no_strict_ignore_invalid_data {--no-strict ignore invalid data if no schema is provided} { + ly_cmd "-f xml -n $ddir/modmandatory_invalid.xml $ddir/modleaf.xml $mdir/modleaf.yang" "modleaf.*</lfl>$" +} {} + +cleanupTests diff --git a/tests/yanglint/non-interactive/data_operational.test b/tests/yanglint/non-interactive/data_operational.test new file mode 100644 index 0000000..82e861e --- /dev/null +++ b/tests/yanglint/non-interactive/data_operational.test @@ -0,0 +1,62 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/non-interactive/ly.tcl" : "ly.tcl"}] + +set mdir "$::env(YANG_MODULES_DIR)" +set ddir "$::env(TESTS_DIR)/data" +set err1 "Operational datastore takes effect only with RPCs/Actions/Replies/Notification input data types" + +test data_operational_twice {it is not allowed to specify more than one --operational parameter} { + ly_cmd_err "-t notif -O $ddir/modconfig.xml -O $ddir/modleaf.xml" "cannot be set multiple times" +} {} + +test data_operational_no_type {--operational should be with parameter --type} { + ly_cmd_err "-O $ddir/modconfig.xml $mdir/modoper-leafref.yang $ddir/modoper_leafref_notif.xml" $err1 +} {} + +test data_operational_missing {--operational is omitted and the datastore contents is in the data file} { + ly_cmd_err "$mdir/modoper-leafref.yang $ddir/modoper_leafref_notif_err.xml" "Failed to parse input data file" +} {} + +test data_operational_wrong_type {data are not defined as an operation} { + ly_cmd_wrn "-t data -O $ddir/modconfig.xml $mdir/modleaf.yang $ddir/modleaf.xml" $err1 +} {} + +test data_operational_datastore_with_unknown_data {unknown data are ignored} { + ly_cmd "-t rpc -O $ddir/modmandatory_invalid.xml $mdir/modrpc.yang $ddir/modrpc.xml" +} {} + +test data_operational_empty_datastore {datastore is considered empty because it contains unknown data} { + ly_cmd "-t rpc -O $ddir/modmandatory_invalid.xml $mdir/modrpc.yang $ddir/modrpc.xml" + set msg "parent \"/modnotif:con\" not found in the operational data" + ly_cmd_err "-t notif -O $ddir/modmandatory_invalid.xml $mdir/modnotif.yang $ddir/modnotif.xml" $msg +} {} + +test data_operational_notif_leafref {--operational data is referenced from notification-leafref} { + ly_cmd "-t notif -O $ddir/modconfig.xml $mdir/modoper-leafref.yang $ddir/modoper_leafref_notif.xml" +} {} + +test data_operational_nested_notif_leafref {--operational data is referenced from nested-notification-leafref} { + ly_cmd "-t notif -O $ddir/modoper_leafref_ds.xml $mdir/modoper-leafref.yang $ddir/modoper_leafref_notif2.xml" +} {} + +test data_operational_nested_notif_parent_missing {--operational data are invalid due to missing parent node} { + set msg "klf='key_val']\" not found in the operational data" + ly_cmd_err "-t notif -O $ddir/modconfig.xml $mdir/modoper-leafref.yang $ddir/modoper_leafref_notif2.xml" $msg +} {} + +test data_operational_action_leafref {--operational data is referenced from action-leafref} { + ly_cmd "-t rpc -O $ddir/modoper_leafref_ds.xml $mdir/modoper-leafref.yang $ddir/modoper_leafref_action.xml" +} {} + +test data_operational_action_reply_leafref {--operational data is referenced from action-leafref output} { + ly_cmd "-t reply -O $ddir/modoper_leafref_ds.xml $mdir/modoper-leafref.yang $ddir/modoper_leafref_action_reply.xml" +} {} + +test data_operational_rpc_leafref {--operational data is referenced from rpc-leafref} { + ly_cmd "-t rpc -O $ddir/modconfig.xml $mdir/modoper-leafref.yang $ddir/modoper_leafref_rpc.xml" +} {} + +test data_operational_rpc_reply_leafref {--operational data is referenced from rpc-leafref output} { + ly_cmd "-t reply -O $ddir/modconfig.xml $mdir/modoper-leafref.yang $ddir/modoper_leafref_rpc_reply.xml" +} {} + +cleanupTests diff --git a/tests/yanglint/non-interactive/data_present.test b/tests/yanglint/non-interactive/data_present.test new file mode 100644 index 0000000..81aac14 --- /dev/null +++ b/tests/yanglint/non-interactive/data_present.test @@ -0,0 +1,25 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/non-interactive/ly.tcl" : "ly.tcl"}] + +set mdir $::env(YANG_MODULES_DIR) +set ddir $::env(TESTS_DIR)/data + +test data_present_via_mandatory {validation of mandatory-stmt will pass only with the --present} { + set mods "$mdir/modleaf.yang $mdir/modmandatory.yang" + ly_cmd_err "$ddir/modleaf.xml $mods" "Mandatory node \"lft\" instance does not exist." + ly_cmd "-e $ddir/modleaf.xml $mods" +} {} + +test data_present_merge {validation with --present and --merge} { + set mods "$mdir/modleaf.yang $mdir/modmandatory.yang $mdir/moddefault.yang" + set data "$ddir/modleaf.xml $ddir/moddefault.xml" + ly_cmd_err "-m $data $mods" "Mandatory node \"lft\" instance does not exist." + ly_cmd "-m -e $data $mods" +} {} + +test data_present_merge_invalid {using --present and --merge but data are invalid} { + set mods "$mdir/modleaf.yang $mdir/modmandatory.yang" + set data "$ddir/modleaf.xml $ddir/modmandatory_invalid.xml" + ly_cmd_err "-e -m $data $mods" "Mandatory node \"lft\" instance does not exist." +} {} + +cleanupTests diff --git a/tests/yanglint/non-interactive/data_type.test b/tests/yanglint/non-interactive/data_type.test new file mode 100644 index 0000000..e3691d7 --- /dev/null +++ b/tests/yanglint/non-interactive/data_type.test @@ -0,0 +1,107 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/non-interactive/ly.tcl" : "ly.tcl"}] + +set mdir "$::env(YANG_MODULES_DIR)" +set ddir "$::env(TESTS_DIR)/data" +set modnc "$mdir/ietf-netconf@2011-06-01.yang" + +test data_type_data {data --type data} { + ly_cmd "-t data $mdir/modconfig.yang $ddir/modconfig.xml" +} {} + +test data_type_config {data --type config} { + ly_cmd_err "-t config $mdir/modconfig.yang $ddir/modconfig.xml" "Unexpected data state node \"lff\"" + ly_cmd "-t config $mdir/modconfig.yang $ddir/modconfig2.xml" +} {} + +test data_type_get {data --type get} { + ly_cmd_err "-t data $mdir/modleafref.yang $ddir/modleafref2.xml" "Invalid leafref value" + ly_cmd "-t get $mdir/modleafref.yang $ddir/modleafref2.xml" +} {} + +test data_type_getconfig_no_state {No state node for data --type getconfig} { + ly_cmd_err "-t getconfig $mdir/modconfig.yang $ddir/modconfig.xml" "Unexpected data state node \"lff\"" + ly_cmd "-t getconfig $mdir/modconfig.yang $ddir/modconfig2.xml" +} {} + +test data_type_getconfig_parse_only {No validation performed for data --type getconfig} { + ly_cmd_err "-t data $mdir/modleafref.yang $ddir/modleafref2.xml" "Invalid leafref value" + ly_cmd "-t getconfig $mdir/modleafref.yang $ddir/modleafref2.xml" +} {} + +test data_type_edit_no_state {No state node for data --type edit} { + ly_cmd_err "-t edit $mdir/modconfig.yang $ddir/modconfig.xml" "Unexpected data state node \"lff\"" + ly_cmd "-t edit $mdir/modconfig.yang $ddir/modconfig2.xml" +} {} + +test data_type_edit_parse_only {No validation performed for data --type edit} { + ly_cmd_err "-t data $mdir/modleafref.yang $ddir/modleafref2.xml" "Invalid leafref value" + ly_cmd "-t edit $mdir/modleafref.yang $ddir/modleafref2.xml" +} {} + +test data_type_rpc {Validation of rpc-statement by data --type rpc} { + ly_cmd_err "-t rpc $mdir/modleaf.yang $ddir/modleaf.xml" "Missing the operation node." + ly_cmd "-t rpc $mdir/modrpc.yang $ddir/modrpc.xml" +} {} + +test data_type_rpc_nc {Validation of rpc-statement by data --type nc-rpc} { + ly_cmd_err "-t nc-rpc $modnc $mdir/modleaf.yang $ddir/modleaf.xml" "Missing NETCONF <rpc> envelope" + ly_cmd "-t nc-rpc $modnc $mdir/modrpc.yang $ddir/modrpc_nc.xml" +} {} + +test data_type_rpc_reply {Validation of rpc-reply by data --type reply} { + ly_cmd_err "-t rpc $mdir/modleaf.yang $ddir/modleaf.xml" "Missing the operation node." + ly_cmd_wrn "-t reply -R $ddir/modrpc.xml $mdir/modrpc.yang $ddir/modrpc_reply.xml" "needed only for NETCONF" + ly_cmd "-t reply $mdir/modrpc.yang $ddir/modrpc_reply.xml" +} {} + +test data_type_rpc_reply_nc {Validation of rpc-reply by data --type nc-reply} { + set err1 "Missing NETCONF <rpc-reply> envelope" + ly_cmd_err "-t nc-reply -R $ddir/modrpc_nc.xml $mdir/modrpc.yang $mdir/modleaf.yang $ddir/modleaf.xml" $err1 + ly_cmd_err "-t nc-reply $mdir/modrpc.yang $ddir/modrpc_reply_nc.xml" "Missing source RPC" + ly_cmd "-t nc-reply -R $ddir/modrpc_nc.xml $mdir/modrpc.yang $ddir/modrpc_reply_nc.xml" +} {} + +test data_type_rpc_action {Validation of action-statement by data --type rpc} { + ly_cmd_err "-t rpc $mdir/modleaf.yang $ddir/modleaf.xml" "Missing the operation node." + ly_cmd "-t rpc -O $ddir/modaction_ds.xml $mdir/modaction.yang $ddir/modaction.xml" +} {} + +test data_type_rpc_action_nc {Validation of action-statement by data --type nc-rpc} { + ly_cmd_err "-t nc-rpc $mdir/modleaf.yang $ddir/modleaf.xml" "Missing NETCONF <rpc> envelope" + ly_cmd "-t nc-rpc -O $ddir/modaction_ds.xml $mdir/modaction.yang $ddir/modaction_nc.xml" +} {} + +test data_type_rpc_action_reply {Validation of action-reply by data --type reply} { + ly_cmd_err "-t rpc $mdir/modleaf.yang $ddir/modleaf.xml" "Missing the operation node." + ly_cmd "-t reply -O $ddir/modaction_ds.xml $mdir/modaction.yang $ddir/modaction_reply.xml" +} {} + +test data_type_rpc_action_reply_nc {Validation of action-reply by data --type nc-reply} { + set err1 "Missing NETCONF <rpc-reply> envelope" + set err2 "operational parameter needed" + ly_cmd_err "-t nc-reply -R $ddir/modaction_nc.xml $mdir/modaction.yang $mdir/modleaf.yang $ddir/modleaf.xml" $err1 + ly_cmd_err "-t nc-reply $mdir/modaction.yang $ddir/modaction_reply_nc.xml" "Missing source RPC" + ly_cmd_err "-t nc-reply -R $ddir/modaction_nc.xml $mdir/modaction.yang $ddir/modaction_reply_nc.xml" $err2 + ly_cmd "-t nc-reply -O $ddir/modaction_ds.xml -R $ddir/modaction_nc.xml $mdir/modaction.yang $ddir/modaction_reply_nc.xml" +} {} + +test data_type_notif {Validation of notification-statement by data --type notif} { + ly_cmd_err "-t notif $mdir/modleaf.yang $ddir/modleaf.xml" "Missing the operation node." + ly_cmd "-t notif $mdir/modnotif.yang $ddir/modnotif2.xml" +} {} + +test data_type_notif_nc {Validation of notification-statement by data --type nc-notif} { + ly_cmd_err "-t nc-notif $modnc $mdir/modleaf.yang $ddir/modleaf.xml" "Missing NETCONF <notification> envelope" + ly_cmd "-t nc-notif $modnc $mdir/modnotif.yang $ddir/modnotif2_nc.xml" +} {} + +test data_type_notif_nested {Validation of nested-notification-statement by data --type notif} { + ly_cmd "-t notif -O $ddir/modnotif_ds.xml $mdir/modnotif.yang $ddir/modnotif.xml" +} {} + +test data_type_notif_nested_nc {Validation of nested-notification-statement by data --type nc-notif} { + ly_cmd_err "-t nc-notif $modnc $mdir/modleaf.yang $ddir/modleaf.xml" "Missing NETCONF <notification> envelope" + ly_cmd "-t nc-notif -O $ddir/modnotif_ds.xml $modnc $mdir/modnotif.yang $ddir/modnotif_nc.xml" +} {} + +cleanupTests diff --git a/tests/yanglint/non-interactive/data_xpath.test b/tests/yanglint/non-interactive/data_xpath.test new file mode 100644 index 0000000..1d96106 --- /dev/null +++ b/tests/yanglint/non-interactive/data_xpath.test @@ -0,0 +1,42 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/non-interactive/ly.tcl" : "ly.tcl"}] + +set mod "$::env(YANG_MODULES_DIR)/moddatanodes.yang" +set data "$::env(TESTS_DIR)/data/moddatanodes.xml" + +test data_xpath_empty {--data-path to missing node} { + ly_cmd "-E /moddatanodes:dnc/mis $mod $data" "Empty" +} {} + +test data_xpath_leaf {--xpath to leaf node} { + ly_cmd "-E /moddatanodes:dnc/lf $mod $data" "leaf \"lf\" \\(value: \"x\"\\)" +} {} + +test data_xpath_leaflist {--xpath to leaf-list node} { + set r1 "leaf-list \"lfl\" \\(value: \"1\"\\)" + set r2 "leaf-list \"lfl\" \\(value: \"2\"\\)" + ly_cmd "-E /moddatanodes:dnc/lfl $mod $data" "$r1\n $r2" +} {} + +test data_xpath_list {--xpath to list} { + set r1 "list \"lt\" \\(\"kalf\": \"ka1\"; \"kblf\": \"kb1\";\\)" + set r2 "list \"lt\" \\(\"kalf\": \"ka2\"; \"kblf\": \"kb2\";\\)" + ly_cmd "-E /moddatanodes:dnc/con/lt $mod $data" "$r1\n $r2" +} {} + +test data_xpath_container {--xpath to container} { + ly_cmd "-E /moddatanodes:dnc/con $mod $data" "container \"con\"" +} {} + +test data_xpath_wrong_path {--xpath to a non-existent node} { + ly_cmd_err "-E /moddatanodes:dnc/wrng $mod $data" "xpath failed" +} {} + +test data_xpath_err_format {--xpath cannot be combined with --format} { + ly_cmd_err "-f xml -E /moddatanodes:dnc/lf $mod $data" "option cannot be combined" +} {} + +test data_xpath_err_default {--xpath cannot be combined with --default} { + ly_cmd_err "-d all -E /moddatanodes:dnc/lf $mod $data" "option cannot be combined" +} {} + +cleanupTests diff --git a/tests/yanglint/non-interactive/debug.test b/tests/yanglint/non-interactive/debug.test new file mode 100644 index 0000000..4543acb --- /dev/null +++ b/tests/yanglint/non-interactive/debug.test @@ -0,0 +1,25 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/non-interactive/ly.tcl" : "ly.tcl"}] + +set mdir $::env(YANG_MODULES_DIR) + +test debug_dict {Check debug message DICT} { +-constraints {[ly_opt_exists "-G"]} -body { + ly_cmd_wrn "-V -V -G dict $mdir/modleaf.yang" "DICT" +}} + +test debug_xpath {Check debug message XPATH} { +-constraints {[ly_opt_exists "-G"]} -body { + ly_cmd_wrn "-V -V -G xpath $mdir/modmust.yang" "XPATH" +}} + +test debug_dep_sets {Check debug message DEPSETS} { +-constraints {[ly_opt_exists "-G"]} -body { + ly_cmd_wrn "-V -V -G dep-sets $mdir/modleaf.yang" "DEPSETS" +}} + +test debug_depsets_xpath {Check debug message DEPSETS and XPATH} { +-constraints {[ly_opt_exists "-G"]} -body { + ly_cmd_wrn "-V -V -G dep-sets,xpath $mdir/modmust.yang" "DEPSETS.*XPATH" +}} + +cleanupTests diff --git a/tests/yanglint/non-interactive/disabled_searchdir.test b/tests/yanglint/non-interactive/disabled_searchdir.test new file mode 100644 index 0000000..49fe13e --- /dev/null +++ b/tests/yanglint/non-interactive/disabled_searchdir.test @@ -0,0 +1,18 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/non-interactive/ly.tcl" : "ly.tcl"}] + +set mdir $env(YANG_MODULES_DIR) + +# Test should be skipped if called by ctest. +test disable_searchdir_once {Unsuccessfully imports module due to disabled cwd searching} { +-constraints {!ctest} -body { + ly_cmd "$mdir/modimp-cwd.yang" + ly_cmd_err "-D $mdir/modimp-cwd.yang" "not found in local searchdirs" +}} + +test disable_searchdir_twice {Unsuccessfully imports module due to -D -D} { + ly_cmd "$mdir/ietf-ip.yang" + ly_cmd_err "-D -D $mdir/ietf-ip.yang" "Loading \"ietf-interfaces\" module failed." +} {} + +cleanupTests + diff --git a/tests/yanglint/non-interactive/ext_data.test b/tests/yanglint/non-interactive/ext_data.test new file mode 100644 index 0000000..d4e3c44 --- /dev/null +++ b/tests/yanglint/non-interactive/ext_data.test @@ -0,0 +1,29 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/non-interactive/ly.tcl" : "ly.tcl"}] + +set mdir "$::env(YANG_MODULES_DIR)" +set ddir "$::env(TESTS_DIR)/data" + +test ext_data_schema_mount_tree {Print tree output of a model with Schema Mount} { + # mounting node lfl from modleaf.yang into modsm.yang + set out1 "--mp root.*--rw lfl/" + ly_cmd "-f tree -p $mdir -y -x $ddir/modsm_ctx_ext.xml $mdir/modsm.yang" $out1 +} {} + +test ext_data_schema_mount_tree_yanglibfile {Print tree output of a model with Schema Mount and --yang-library-file} { + # yang-library-file context contains an augment node 'alf' for modsm + set out1 "--mp root.*--rw lfl/.*--rw msa:alf?" + ly_cmd "-f tree -p $mdir -Y $ddir/modsm_ctx_main.xml -x $ddir/modsm_ctx_ext.xml $mdir/modsm.yang" $out1 +} {} + +test ext_data_schema_mount_xml {Validating and printing mounted data} { + ly_cmd "-f xml -t config -p $mdir -y -x $ddir/modsm_ctx_ext.xml $mdir/modsm.yang $ddir/modsm.xml" "</lfl>" +} {} + +test ext_data_schema_mount_xml_yanglibfile {Validating and printing mounted data with --yang-library-file} { + set yanglibfile "$ddir/modsm_ctx_main.xml" + set extdata "$ddir/modsm_ctx_ext.xml" + set out1 "</lfl>.*</alf>" + ly_cmd "-f xml -t config -p $mdir -Y $yanglibfile -x $extdata $mdir/modsm.yang $ddir/modsm2.xml" $out1 +} {} + +cleanupTests diff --git a/tests/yanglint/non-interactive/extended_leafref.test b/tests/yanglint/non-interactive/extended_leafref.test new file mode 100644 index 0000000..5e1a90e --- /dev/null +++ b/tests/yanglint/non-interactive/extended_leafref.test @@ -0,0 +1,13 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/non-interactive/ly.tcl" : "ly.tcl"}] + +set mdir $::env(YANG_MODULES_DIR) + +test extended_leafref_enabled {Valid module with --extended-leafref option} { + ly_cmd "-X $mdir/modextleafref.yang" +} {} + +test extended_leafref_disabled {Expected error if --extended-leafref is not set} { + ly_cmd_err "$mdir/modextleafref.yang" "Unexpected XPath token \"FunctionName\"" +} {} + +cleanupTests diff --git a/tests/yanglint/non-interactive/format.test b/tests/yanglint/non-interactive/format.test new file mode 100644 index 0000000..8df5544 --- /dev/null +++ b/tests/yanglint/non-interactive/format.test @@ -0,0 +1,72 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/non-interactive/ly.tcl" : "ly.tcl"}] + +set mdir $::env(YANG_MODULES_DIR) +set ddir $::env(TESTS_DIR)/data +set ipv6_path "/ietf-interfaces:interfaces/interface/ietf-ip:ipv6/address" + +test format_yang {} { + ly_cmd "-f yang $mdir/modleaf.yang" "leaf lfl" +} {} + +test format_yang_submodule {Print submodule in yang format} { + ly_cmd "-s modsub -f yang $mdir/modinclude.yang" "submodule modsub" +} {} + +test format_yin {} { + ly_cmd "-f yin $mdir/modleaf.yang" "<leaf name=\"lfl\">" +} {} + +test format_yin_submodule {Print submodule in yin format} { + ly_cmd "-s modsub -f yin $mdir/modinclude.yang" "<submodule name=\"modsub\"" +} {} + +test format_info {} { + ly_cmd "-f info $mdir/modleaf.yang" "status current" +} {} + +test format_tree {} { + ly_cmd "-f tree $mdir/modleaf.yang" "\\+--rw lfl" +} {} + +test format_data_xml {Print data in xml format} { + ly_cmd "-f xml $mdir/modleaf.yang $ddir/modleaf.xml" "<lfl xmlns=\"urn:yanglint:modleaf\">7</lfl>" +} {} + +test format_data_json {Print data in json format} { + ly_cmd "-f json $mdir/modleaf.yang $ddir/modleaf.xml" "{\n \"modleaf:lfl\": 7\n}" +} {} + +test format_data_lyb_err {Printing in LYB format: expect error due to missing parameter} { + ly_cmd_err "-f lyb $mdir/modleaf.yang $ddir/modleaf.xml" "The LYB format requires the -o" +} {} + +test format_tree_submodule {Print submodule in tree format} { + ly_cmd "-s modsub -f tree $mdir/modinclude.yang" "submodule: modsub" +} {} + +test format_tree_path {Print subtree in tree format} { + ly_cmd "-f tree -P $ipv6_path $mdir/ietf-ip.yang" "\\+--rw address.*\\+--rw prefix-length" +} {} + +test format_tree_path_single_node {Print node in tree format} { + ly_cmd "-f tree -q -P $ipv6_path $mdir/ietf-ip.yang" "\\+--rw address\\* \\\[ip\\\]$" +} {} + +test format_tree_path_single_node_line_length {Print node in the tree format and limit row size} { + ly_cmd "-f tree -L 20 -q -P $ipv6_path $mdir/ietf-ip.yang" "\\+--rw address\\*\n *\\\[ip\\\]$" +} {} + +test format_feature_param_one_module {Show features for one module} { + ly_cmd "-f feature-param $mdir/ietf-ip.yang" " -F ietf-ip:ipv4-non-contiguous-netmasks,ipv6-privacy-autoconf" -ex +} {} + +test format_feature_param_more_modules {Show a mix of modules with and without features} { + + set features " -F modfeature:ftr1,ftr2\ +-F modleaf:\ +-F ietf-ip:ipv4-non-contiguous-netmasks,ipv6-privacy-autoconf" + + ly_cmd "-f feature-param $mdir/modfeature.yang $mdir/modleaf.yang $mdir/ietf-ip.yang" $features -ex +} {} + +cleanupTests diff --git a/tests/yanglint/non-interactive/list.test b/tests/yanglint/non-interactive/list.test new file mode 100644 index 0000000..626d9a1 --- /dev/null +++ b/tests/yanglint/non-interactive/list.test @@ -0,0 +1,26 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/non-interactive/ly.tcl" : "ly.tcl"}] +namespace import uti::regex_xml_elements uti::regex_json_pairs + +set modules {ietf-yang-library ietf-inet-types} + +test list_basic {} { + ly_cmd "-l" "ietf-yang-types" +} {} + +test list_format_xml {list --format xml} { + ly_cmd "-y -f xml -l" [regex_xml_elements $modules "name"] +} {} + +test list_format_json {list --format json} { + ly_cmd "-y -f json -l" [regex_json_pairs $modules "name"] +} {} + +test list_ietf_yang_library {Error due to missing ietf-yang-library} { + ly_cmd_err "-f xml -l" "Module \"ietf-yang-library\" is not implemented." +} {} + +test list_bad_format {Error due to bad format} { + ly_cmd_err "-f csv -l" "Unknown output format csv" +} {} + +cleanupTests diff --git a/tests/yanglint/non-interactive/ly.tcl b/tests/yanglint/non-interactive/ly.tcl new file mode 100644 index 0000000..f6bb2c7 --- /dev/null +++ b/tests/yanglint/non-interactive/ly.tcl @@ -0,0 +1,8 @@ +# @brief The main source of functions and variables for testing yanglint in the non-interactive mode. + +# For testing yanglint. +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/common.tcl" : "../common.tcl"}] +# For testing any non-interactive tool. +source "$::env(TESTS_DIR)/../tool_ni.tcl" + +# The script continues by defining variables and functions specific to the non-interactive yanglint tool. diff --git a/tests/yanglint/non-interactive/make_implemented.test b/tests/yanglint/non-interactive/make_implemented.test new file mode 100644 index 0000000..40cead9 --- /dev/null +++ b/tests/yanglint/non-interactive/make_implemented.test @@ -0,0 +1,17 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/non-interactive/ly.tcl" : "ly.tcl"}] + +set mdir $::env(YANG_MODULES_DIR) + +test make_impl_no_set {Import while --make-implemented is not set} { + ly_cmd "-l $mdir/modleafref.yang" "I modleafref\n.*I modleaf" +} {} + +test make_impl_set_once {--make-implemented} { + ly_cmd "-l -i $mdir/modmust.yang" "I modmust\n.*I modleaf" +} {} + +test make_impl_set_twice {-i -i} { + ly_cmd "-l -i -i $mdir/modimp-type.yang" "I modimp-type\n.*I modtypedef" +} {} + +cleanupTests diff --git a/tests/yanglint/non-interactive/modcwd.yang b/tests/yanglint/non-interactive/modcwd.yang new file mode 100644 index 0000000..db33e73 --- /dev/null +++ b/tests/yanglint/non-interactive/modcwd.yang @@ -0,0 +1,4 @@ +module modcwd { + namespace "urn:yanglint:modcwd"; + prefix mc; +} diff --git a/tests/yanglint/non-interactive/path.test b/tests/yanglint/non-interactive/path.test new file mode 100644 index 0000000..bf915ff --- /dev/null +++ b/tests/yanglint/non-interactive/path.test @@ -0,0 +1,9 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/non-interactive/ly.tcl" : "ly.tcl"}] + +set mdir $env(YANG_MODULES_DIR) + +test path_basic {} { + ly_cmd "-p $::env(TESTS_DIR)/data $::env(YANG_MODULES_DIR)/modimp-path.yang" +} {} + +cleanupTests diff --git a/tests/yanglint/non-interactive/yang_library_file.test b/tests/yanglint/non-interactive/yang_library_file.test new file mode 100644 index 0000000..bd95978 --- /dev/null +++ b/tests/yanglint/non-interactive/yang_library_file.test @@ -0,0 +1,18 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/non-interactive/ly.tcl" : "ly.tcl"}] + +set mdir "$::env(YANG_MODULES_DIR)" +set ddir "$::env(TESTS_DIR)/data" + +test ylf_list {apply --yang-library-file and check result by --list} { + ly_cmd "-Y $ddir/modimp_type_ctx.xml -p $mdir -l" "I modimp-type.*i modtypedef" +} {} + +test ylf_make_implemented {apply --yang-library-file and --make-implemented} { + ly_cmd "-Y $ddir/modimp_type_ctx.xml -p $mdir -i -i -l" "I modimp-type.*I modtypedef" +} {} + +test ylf_augment_ctx {Setup context by yang-library-file and augment module} { + ly_cmd "-Y $ddir/modconfig_ctx.xml -p $mdir -f tree $mdir/modconfig.yang $mdir/modconfig-augment.yang" "mca:alf" +} {} + +cleanupTests diff --git a/tests/yangre/CMakeLists.txt b/tests/yangre/CMakeLists.txt new file mode 100644 index 0000000..ce5b39b --- /dev/null +++ b/tests/yangre/CMakeLists.txt @@ -0,0 +1,8 @@ +find_program(PATH_TCLSH NAMES tclsh) +if(NOT PATH_TCLSH) + message(WARNING "'tclsh' not found! The yangre test will not be available.") +else() + add_test(NAME "yangre" COMMAND "tclsh" "${CMAKE_CURRENT_SOURCE_DIR}/all.tcl") + set_property(TEST "yangre" APPEND PROPERTY ENVIRONMENT "TESTS_DIR=${CMAKE_CURRENT_SOURCE_DIR}") + set_property(TEST "yangre" APPEND PROPERTY ENVIRONMENT "YANGRE=${PROJECT_BINARY_DIR}") +endif() diff --git a/tests/yangre/all.tcl b/tests/yangre/all.tcl new file mode 100644 index 0000000..f00563f --- /dev/null +++ b/tests/yangre/all.tcl @@ -0,0 +1,15 @@ +package require tcltest + +# Hook to determine if any of the tests failed. +# Sets a global variable exitCode to 1 if any test fails otherwise it is set to 0. +proc tcltest::cleanupTestsHook {} { + variable numTests + set ::exitCode [expr {$numTests(Failed) > 0}] +} + +if {[info exists ::env(TESTS_DIR)]} { + tcltest::configure -testdir "$env(TESTS_DIR)" +} + +tcltest::runAllTests +exit $exitCode diff --git a/tests/yangre/arg.test b/tests/yangre/arg.test new file mode 100644 index 0000000..821aad1 --- /dev/null +++ b/tests/yangre/arg.test @@ -0,0 +1,19 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/ly.tcl" : "ly.tcl"}] + +test arg_empty {Missing arguments} { + ly_cmd_err "" "missing <string> parameter to process" +} {} + +test arg_wrong {Wrong argument} { + ly_cmd_err "-j" "invalid option" +} {} + +test arg_help {Print help} { + ly_cmd "-h" "Usage:" +} {} + +test arg_version {Print version} { + ly_cmd "-v" "yangre" +} {} + +cleanupTests diff --git a/tests/yangre/file.test b/tests/yangre/file.test new file mode 100644 index 0000000..80ea3f6 --- /dev/null +++ b/tests/yangre/file.test @@ -0,0 +1,37 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/ly.tcl" : "ly.tcl"}] + +set fdir "$::env(TESTS_DIR)/files" + +test file_empty {file is empty} { + ly_cmd "-f $fdir/empty.txt" +} {} + +test file_empty_str {<string> is empty} { + ly_cmd "-f $fdir/empty_str.txt" +} {} + +test file_empty_str_err {empty <string> is not allowed} { + ly_cmd_err "-f $fdir/empty_str_err.txt" "does not conform" +} {} + +test file_one_pattern {one pattern in the file} { + ly_cmd "-f $fdir/one_pattern.txt" +} {} + +test file_two_patterns {two patterns in the file} { + ly_cmd "-f $fdir/two_patterns.txt" +} {} + +test file_two_patterns_err {two patterns and the <string> is wrong} { + ly_cmd_err "-f $fdir/two_patterns_err.txt" "does not conform" +} {} + +test file_two_patterns_invert_match {one pattern is inverted} { + ly_cmd "-f $fdir/two_patterns_invert_match.txt" +} {} + +test file_two_patterns_invert_match_err {one pattern is inverted and the <string> is wrong} { + ly_cmd_err "-f $fdir/two_patterns_invert_match_err.txt" "does not conform to inverted" +} {} + +cleanupTests diff --git a/tests/yangre/files/empty.txt b/tests/yangre/files/empty.txt new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/yangre/files/empty.txt diff --git a/tests/yangre/files/empty_str.txt b/tests/yangre/files/empty_str.txt new file mode 100644 index 0000000..bf9b1b5 --- /dev/null +++ b/tests/yangre/files/empty_str.txt @@ -0,0 +1,2 @@ +"[0-9a-fA-F]*" + diff --git a/tests/yangre/files/empty_str_err.txt b/tests/yangre/files/empty_str_err.txt new file mode 100644 index 0000000..f48a15d --- /dev/null +++ b/tests/yangre/files/empty_str_err.txt @@ -0,0 +1,2 @@ +"[0-9a-fA-F]+" + diff --git a/tests/yangre/files/one_pattern.txt b/tests/yangre/files/one_pattern.txt new file mode 100644 index 0000000..cf9acc5 --- /dev/null +++ b/tests/yangre/files/one_pattern.txt @@ -0,0 +1,3 @@ +"[0-9a-fA-F]*" + +1F diff --git a/tests/yangre/files/two_patterns.txt b/tests/yangre/files/two_patterns.txt new file mode 100644 index 0000000..7d04b2c --- /dev/null +++ b/tests/yangre/files/two_patterns.txt @@ -0,0 +1,4 @@ +"[0-9a-fA-F]*" +'[a-zA-Z0-9\-_.]*' + +1F diff --git a/tests/yangre/files/two_patterns_err.txt b/tests/yangre/files/two_patterns_err.txt new file mode 100644 index 0000000..78f9878 --- /dev/null +++ b/tests/yangre/files/two_patterns_err.txt @@ -0,0 +1,4 @@ +"[0-9a-fA-F]*" +'[a-zA-Z0-9\-_.]*' + +@!@ diff --git a/tests/yangre/files/two_patterns_invert_match.txt b/tests/yangre/files/two_patterns_invert_match.txt new file mode 100644 index 0000000..ffbd835 --- /dev/null +++ b/tests/yangre/files/two_patterns_invert_match.txt @@ -0,0 +1,4 @@ +"[a-z]*" + '[a-f]*' + +gh diff --git a/tests/yangre/files/two_patterns_invert_match_err.txt b/tests/yangre/files/two_patterns_invert_match_err.txt new file mode 100644 index 0000000..f182aab --- /dev/null +++ b/tests/yangre/files/two_patterns_invert_match_err.txt @@ -0,0 +1,4 @@ +"[a-z]*" + '[a-f]*' + +ab diff --git a/tests/yangre/invert_match.test b/tests/yangre/invert_match.test new file mode 100644 index 0000000..707ca9d --- /dev/null +++ b/tests/yangre/invert_match.test @@ -0,0 +1,28 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/ly.tcl" : "ly.tcl"}] + +test invert_match_from_help1 {Test the first pattern from help via invert match} { + ly_cmd_err {-p {"[0-9a-fA-F]*"} -i {1F}} "not conform to inverted" + ly_cmd {-p {"[0-9a-fA-F]*"} -i {GUN}} +} {} + +test invert_match_from_help2 {Test the second pattern from help via invert match} { + ly_cmd_err {-p {'[a-zA-Z0-9\-_.]*'} -i {a-b}} "not conform to inverted" + ly_cmd {-p {'[a-zA-Z0-9\-_.]*'} -i {%@}} +} {} + +test invert_match_from_help3 {Test the third pattern from help via invert match} { + ly_cmd_err {-p {[xX][mM][lL].*} -i {xml-encoding}} "not conform to inverted" + ly_cmd {-p {[xX][mM][lL].*} -i {json}} +} {} + +test invert_match_three_at_once {Test three inverted patterns and once} { + ly_cmd_err {-p {"[0-9a-zA-Z]*"} -i -p {'[a-zA-Z0-9\-_.]*'} -i -p {[xX][mM][lL].*} -i {xml}} "not conform to inverted" + ly_cmd {-p {"[0-9a-zA-Z]*"} -i -p {'[a-zA-Z0-9\-_.]*'} -i -p {[xX][mM][lL].*} -i {%@}} +} {} + +test invert_match_second_is_not {Test three patterns but the second one is not inverted} { + ly_cmd_err {-p {"[0-9a-zA-Z]*"} -i -p {'[a-zA-Z0-9\-_.]*'} -i -p {[xX][mM][lL].*} -i {o_O}} "not conform to inverted" + ly_cmd {-p {"[0-9a-zA-Z]*"} -i -p {'[a-zA-Z0-9\-_.]*'} -p {[xX][mM][lL].*} -i {o_O}} +} {} + +cleanupTests diff --git a/tests/yangre/ly.tcl b/tests/yangre/ly.tcl new file mode 100644 index 0000000..3bb62b5 --- /dev/null +++ b/tests/yangre/ly.tcl @@ -0,0 +1,17 @@ +# @brief The main source of functions and variables for testing yangre. + +package require tcltest +namespace import ::tcltest::test ::tcltest::cleanupTests + +if { ![info exists ::env(TESTS_DIR)] } { + # the script is not run via 'ctest' so paths must be set + set ::env(TESTS_DIR) "./" + set TUT_PATH "../../build" +} else { + # cmake (ctest) already sets ::env variables + set TUT_PATH $::env(YANGRE) +} +set TUT_NAME "yangre" +source "$::env(TESTS_DIR)/../tool_ni.tcl" + +# The script continues by defining variables and functions specific to the yangre tool. diff --git a/tests/yangre/pattern.test b/tests/yangre/pattern.test new file mode 100644 index 0000000..45b7e3b --- /dev/null +++ b/tests/yangre/pattern.test @@ -0,0 +1,19 @@ +source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/ly.tcl" : "ly.tcl"}] + +test pattern_from_help1 {Test the first pattern from help} { + ly_cmd {-p {"[0-9a-fA-F]*"} {1F}} +} {} + +test pattern_from_help2 {Test the second pattern from help} { + ly_cmd {-p {'[a-zA-Z0-9\-_.]*'} {a-b}} +} {} + +test pattern_from_help3 {Test the third pattern from help} { + ly_cmd {-p {[xX][mM][lL].*} {xml-encoding}} +} {} + +test pattern_three_at_once {Test three patterns and once} { + ly_cmd {-p {"[0-9a-zA-Z]*"} -p {'[a-zA-Z0-9\-_.]*'} -p {[xX][mM][lL].*} {xml}} +} {} + +cleanupTests |