yanglint TEST moved to the tests directory
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 6f36f31..6b6bd72 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -45,6 +45,7 @@
         add_subdirectory(style)
         add_subdirectory(fuzz)
     endif()
+    add_subdirectory(yanglint)
 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/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