yanglint FEATURE add tests for yanglint(1)

Not a complete set, only the first examples for future tests writing.
diff --git a/.travis.yml b/.travis.yml
index 799bb8f..331b410 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -62,7 +62,7 @@
       os: linux
       compiler: clang
       before_install:
-        - sudo apt-get update -qq && sudo apt-get install -y valgrind
+        - sudo apt-get update -qq && sudo apt-get install -y valgrind shunit2 expect
         - wget https://cmocka.org/files/1.1/cmocka-1.1.2.tar.xz
         - tar -xf cmocka-1.1.2.tar.xz
         - cd cmocka-1.1.2 && mkdir build && cd build && cmake .. && make -j2 && sudo make install && cd ../..
@@ -76,7 +76,7 @@
       os: linux
       compiled: gcc
       before_install:
-        - sudo apt-get update -qq && sudo apt-get install -y valgrind
+        - sudo apt-get update -qq && sudo apt-get install -y valgrind shunit2 expect
         - wget https://cmocka.org/files/1.1/cmocka-1.1.2.tar.xz
         - tar -xf cmocka-1.1.2.tar.xz
         - cd cmocka-1.1.2 && mkdir build && cd build && cmake .. && make -j2 && sudo make install && cd ../..
@@ -93,7 +93,7 @@
       os: linux
       compiler: clang
       before_install:
-        - sudo apt-get update -qq && sudo apt-get install -y valgrind
+        - sudo apt-get update -qq && sudo apt-get install -y valgrind shunit2 expect
         - wget https://cmocka.org/files/1.1/cmocka-1.1.2.tar.xz
         - tar -xf cmocka-1.1.2.tar.xz
         - cd cmocka-1.1.2 && mkdir build && cd build && cmake .. && make -j2 && sudo make install && cd ../..
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b1776a2..52aff02 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -296,29 +296,6 @@
     endif()
 endif()
 
-# tools - yanglint, yangre
-add_subdirectory(tools)
-
-# generate doxygen documentation for libyang API
-libyang_doc()
-
-# generate API/ABI report
-if ("${BUILD_TYPE_UPPER}" STREQUAL "ABICHECK")
-    libyang_abicheck()
-endif()
-
-# source code format
-if ("${BUILD_TYPE_UPPER}" STREQUAL "DEBUG")
-	source_format(${format_sources})
-endif()
-
-# clean cmake cache
-add_custom_target(cclean
-        COMMAND make clean
-        COMMAND find . -iname '*cmake*' -not -name CMakeLists.txt -not -path './CMakeModules*' -exec rm -rf {} +
-        COMMAND rm -rf Makefile Doxyfile
-        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
-
 # YANG extensions plugins
 #set(EXTENSIONS_LIST "nacm" "metadata" "yangdata")
 # if the tests are enabled, build libyang_ext_test
@@ -389,3 +366,27 @@
         set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address,undefined -fno-omit-frame-pointer")
     endif()
 endif()
+
+# tools - yanglint, yangre
+add_subdirectory(tools)
+
+# generate doxygen documentation for libyang API
+libyang_doc()
+
+# generate API/ABI report
+if ("${BUILD_TYPE_UPPER}" STREQUAL "ABICHECK")
+    libyang_abicheck()
+endif()
+
+# source code format
+if ("${BUILD_TYPE_UPPER}" STREQUAL "DEBUG")
+	source_format(${format_sources})
+endif()
+
+# clean cmake cache
+add_custom_target(cclean
+        COMMAND make clean
+        COMMAND find . -iname '*cmake*' -not -name CMakeLists.txt -not -path './CMakeModules*' -exec rm -rf {} +
+        COMMAND rm -rf Makefile Doxyfile
+        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
+
diff --git a/tools/lint/CMakeLists.txt b/tools/lint/CMakeLists.txt
index e4ad069..d8b00b0 100644
--- a/tools/lint/CMakeLists.txt
+++ b/tools/lint/CMakeLists.txt
@@ -28,3 +28,29 @@
 install(FILES ${PROJECT_SOURCE_DIR}/tools/lint/yanglint.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
 target_include_directories(yanglint BEFORE PRIVATE ${PROJECT_BINARY_DIR})
 
+#
+# tests
+#
+function(add_yanglint_test)
+    cmake_parse_arguments(ADDTEST "" "NAME;SCRIPT" "" ${ARGN})
+    set(TEST_NAME yanglint_${ADDTEST_NAME})
+
+	add_test(NAME ${TEST_NAME} COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/tests/${ADDTEST_SCRIPT})
+	set_property(TEST ${TEST_NAME} APPEND PROPERTY ENVIRONMENT "YANGLINT=${PROJECT_BINARY_DIR}/yanglint")
+endfunction(add_yanglint_test)
+
+# tests of non-interactive mode using shunit2
+find_program(PATH_SHUNIT NAMES shunit2)
+if(NOT PATH_SHUNIT)
+    message(WARNING "'shunit2' is not found! The yanglint(1) non-interactive tests will not be available.")
+else()
+	add_yanglint_test(NAME ni_list SCRIPT shunit2/list.sh)
+endif()
+
+# tests of interactive mode using expect
+find_program(PATH_SHUNIT NAMES shunit2)
+if(NOT PATH_SHUNIT)
+    message(WARNING "'expect' is not found! The yanglint(1) interactive tests will not be available.")
+else()
+	add_yanglint_test(NAME in_list SCRIPT expect/list.exp)
+endif()
diff --git a/tools/lint/tests/expect/list.exp b/tools/lint/tests/expect/list.exp
new file mode 100755
index 0000000..c7bf436
--- /dev/null
+++ b/tools/lint/tests/expect/list.exp
@@ -0,0 +1,21 @@
+#!/usr/bin/expect -f
+
+set timeout 1
+
+spawn $env(YANGLINT)
+expect -exact "> "
+send -- "list\r"
+expect { 
+	"list\r
+List of the loaded models:\r
+    I ietf-yang-metadata@2016-08-05\r
+    I yang@2020-06-17\r
+    i ietf-inet-types@2013-07-15\r
+    i ietf-yang-types@2013-07-15\r
+    I ietf-datastores@2018-02-14\r
+    I ietf-yang-library@2019-01-04\r
+> " { }
+	timeout { exit 1 }
+}
+send -- "exit\r"
+expect eof
\ No newline at end of file
diff --git a/tools/lint/tests/shunit2/list.sh b/tools/lint/tests/shunit2/list.sh
new file mode 100755
index 0000000..21260dc
--- /dev/null
+++ b/tools/lint/tests/shunit2/list.sh
@@ -0,0 +1,28 @@
+#! /bin/sh
+
+LIST_BASE="List of the loaded models:
+    I ietf-yang-metadata@2016-08-05
+    I yang@2020-06-17
+    i ietf-inet-types@2013-07-15
+    i ietf-yang-types@2013-07-15
+    I ietf-datastores@2018-02-14
+    I ietf-yang-library@2019-01-04"
+
+testListEmptyContext() {
+  output=`${YANGLINT} -l`
+  assertEquals "Unexpected list of modules in empty context." "${LIST_BASE}" "${output}"
+}
+
+testListAllImplemented() {
+  LIST_BASE_ALLIMPLEMENTED="List of the loaded models:
+    I ietf-yang-metadata@2016-08-05
+    I yang@2020-06-17
+    I ietf-inet-types@2013-07-15
+    I ietf-yang-types@2013-07-15
+    I ietf-datastores@2018-02-14
+    I ietf-yang-library@2019-01-04"
+  output=`${YANGLINT} -lii`
+  assertEquals "Unexpected list of modules in empty context with -ii." "${LIST_BASE_ALLIMPLEMENTED}" "${output}"
+}
+
+. shunit2