Move ls logic to Interpreter

Change-Id: I9d1e04573be5d7701e4e66e53aefb9dc1a1fd8ab
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2f4068a..78e67f0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -277,7 +277,7 @@
     cli_test(enum_completion)
     target_link_libraries(test_enum_completion leaf_data_type)
     cli_test(list_manipulation)
-    cli_test(parser_methods)
+    cli_test(ls_interpreter)
     cli_test(path_utils)
     target_link_libraries(test_path_utils path)
     cli_test(keyvalue_completion)
diff --git a/src/interpreter.cpp b/src/interpreter.cpp
index 8f419c3..9912584 100644
--- a/src/interpreter.cpp
+++ b/src/interpreter.cpp
@@ -76,7 +76,26 @@
             recursion = Recursion::Recursive;
     }
 
-    for (const auto& it : m_parser.availableNodes(ls.m_path, recursion))
+    std::set<std::string> toPrint;
+
+    auto pathArg = dataPathToSchemaPath(m_parser.currentPath());
+    if (ls.m_path) {
+        if (ls.m_path->type() == typeid(module_)) {
+            toPrint = m_datastore.schema()->availableNodes(*ls.m_path, recursion);
+        } else {
+            auto schemaPath = anyPathToSchemaPath(*ls.m_path);
+            if (schemaPath.m_scope == Scope::Absolute) {
+                pathArg = schemaPath;
+            } else {
+                pathArg.m_nodes.insert(pathArg.m_nodes.end(), schemaPath.m_nodes.begin(), schemaPath.m_nodes.end());
+            }
+            toPrint = m_datastore.schema()->availableNodes(pathArg, recursion);
+        }
+    } else {
+        toPrint = m_datastore.schema()->availableNodes(pathArg, recursion);
+    }
+
+    for (const auto& it : toPrint)
         std::cout << it << std::endl;
 }
 
diff --git a/src/parser.cpp b/src/parser.cpp
index 245de1d..2942d56 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -101,20 +101,7 @@
     return pathToDataString(m_curDir, Prefixes::WhenNeeded);
 }
 
-std::set<std::string> Parser::availableNodes(const boost::optional<boost::variant<dataPath_, schemaPath_, module_>>& path, const Recursion& option) const
+dataPath_ Parser::currentPath()
 {
-    auto pathArg = dataPathToSchemaPath(m_curDir);
-    if (path) {
-        if (path->type() == typeid(module_)) {
-            return m_schema->availableNodes(*path, option);
-        }
-
-        auto schemaPath = anyPathToSchemaPath(*path);
-        if (schemaPath.m_scope == Scope::Absolute) {
-            pathArg = schemaPath;
-        } else {
-            pathArg.m_nodes.insert(pathArg.m_nodes.end(), schemaPath.m_nodes.begin(), schemaPath.m_nodes.end());
-        }
-    }
-    return m_schema->availableNodes(pathArg, option);
+    return m_curDir;
 }
diff --git a/src/parser.hpp b/src/parser.hpp
index 82e7daf..14daa9e 100644
--- a/src/parser.hpp
+++ b/src/parser.hpp
@@ -37,8 +37,8 @@
     command_ parseCommand(const std::string& line, std::ostream& errorStream);
     void changeNode(const dataPath_& name);
     std::string currentNode() const;
-    std::set<std::string> availableNodes(const boost::optional<boost::variant<dataPath_, schemaPath_, module_>>& path, const Recursion& option) const;
     Completions completeCommand(const std::string& line, std::ostream& errorStream) const;
+    dataPath_ currentPath();
 
 private:
     const std::shared_ptr<const Schema> m_schema;
diff --git a/tests/ls_interpreter.cpp b/tests/ls_interpreter.cpp
new file mode 100644
index 0000000..6b02d80
--- /dev/null
+++ b/tests/ls_interpreter.cpp
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2018 CESNET, https://photonics.cesnet.cz/
+ * Copyright (C) 2018 FIT CVUT, https://fit.cvut.cz/
+ *
+ * Written by Václav Kubernát <kubervac@fit.cvut.cz>
+ *
+*/
+
+#include <experimental/iterator>
+#include "trompeloeil_doctest.hpp"
+#include "ast_commands.hpp"
+#include "interpreter.hpp"
+#include "datastoreaccess_mock.hpp"
+#include "parser.hpp"
+#include "pretty_printers.hpp"
+#include "static_schema.hpp"
+
+class MockSchema : public trompeloeil::mock_interface<Schema> {
+public:
+    IMPLEMENT_CONST_MOCK1(defaultValue);
+    IMPLEMENT_CONST_MOCK1(description);
+    IMPLEMENT_CONST_MOCK2(availableNodes);
+    IMPLEMENT_CONST_MOCK1(isConfig);
+    MAKE_CONST_MOCK1(leafType, yang::TypeInfo(const std::string&), override);
+    MAKE_CONST_MOCK2(leafType, yang::TypeInfo(const schemaPath_&, const ModuleNodePair&), override);
+    IMPLEMENT_CONST_MOCK1(leafTypeName);
+    IMPLEMENT_CONST_MOCK1(isModule);
+    IMPLEMENT_CONST_MOCK1(leafrefPath);
+    IMPLEMENT_CONST_MOCK3(listHasKey);
+    IMPLEMENT_CONST_MOCK1(leafIsKey);
+    IMPLEMENT_CONST_MOCK2(listKeys);
+    MAKE_CONST_MOCK1(nodeType, yang::NodeTypes(const std::string&), override);
+    MAKE_CONST_MOCK2(nodeType, yang::NodeTypes(const schemaPath_&, const ModuleNodePair&), override);
+    IMPLEMENT_CONST_MOCK1(status);
+};
+
+TEST_CASE("ls interpreter")
+{
+    auto schema = std::make_shared<MockSchema>();
+    Parser parser(schema);
+
+    boost::variant<dataPath_, schemaPath_, module_> expectedPath;
+    boost::optional<boost::variant<dataPath_, schemaPath_, module_>> lsArg{boost::none};
+    SECTION("cwd: /")
+    {
+        SECTION("arg: <none>")
+        {
+            expectedPath = schemaPath_{};
+        }
+
+        SECTION("arg: example:a")
+        {
+            lsArg = dataPath_{Scope::Relative, {{module_{"example"}, container_{"a"}}}};
+            expectedPath = schemaPath_{Scope::Absolute, {{module_{"example"}, container_{"a"}}}};
+        }
+
+        SECTION("arg: example:list")
+        {
+            lsArg = dataPath_{Scope::Relative, {{module_{"example"}, list_{"list"}}}};
+            expectedPath = schemaPath_{Scope::Absolute, {{module_{"example"}, list_{"list"}}}};
+        }
+
+        SECTION("arg: /example:a")
+        {
+            lsArg = dataPath_{Scope::Absolute, {{module_{"example"}, container_{"a"}}}};
+            expectedPath = schemaPath_{Scope::Absolute, {{module_{"example"}, container_{"a"}}}};
+        }
+
+        SECTION("arg: /example:list")
+        {
+            lsArg = dataPath_{Scope::Absolute, {{module_{"example"}, list_{"list"}}}};
+            expectedPath = schemaPath_{Scope::Absolute, {{module_{"example"}, list_{"list"}}}};
+        }
+
+        SECTION("arg example:*")
+        {
+            lsArg = module_{"example"};
+            expectedPath = module_{"example"};
+        }
+    }
+
+    SECTION("cwd: /example:a")
+    {
+        parser.changeNode({Scope::Relative, {{module_{"example"}, container_{"a"}}}});
+
+        SECTION("arg: <none>")
+        {
+            expectedPath = schemaPath_{Scope::Absolute, {{module_{"example"}, container_{"a"}}}};
+        }
+
+        SECTION("arg: example:a2")
+        {
+            lsArg = dataPath_{Scope::Relative, {{container_{"a2"}}}};
+            expectedPath = schemaPath_{Scope::Absolute, {{module_{"example"}, container_{"a"}}, {container_{"a2"}}}};
+        }
+
+        SECTION("arg: example:listInCont")
+        {
+            lsArg = dataPath_{Scope::Relative, {{list_{"listInCont"}}}};
+            expectedPath = schemaPath_{Scope::Absolute, {{module_{"example"}, container_{"a"}}, {list_{"listInCont"}}}};
+        }
+
+        SECTION("arg: /example:a")
+        {
+            lsArg = dataPath_{Scope::Absolute, {{module_{"example"}, container_{"a"}}}};
+            expectedPath = schemaPath_{Scope::Absolute, {{module_{"example"}, container_{"a"}}}};
+        }
+
+        SECTION("arg: /example:list")
+        {
+            lsArg = dataPath_{Scope::Absolute, {{module_{"example"}, list_{"list"}}}};
+            expectedPath = schemaPath_{Scope::Absolute, {{module_{"example"}, list_{"list"}}}};
+        }
+    }
+    SECTION("cwd: /example:list")
+    {
+        parser.changeNode({Scope::Relative, {{module_{"example"}, list_{"list"}}}});
+
+        SECTION("arg: <none>")
+        {
+            expectedPath = schemaPath_{Scope::Absolute, {{module_{"example"}, list_{"list"}}}};
+        }
+
+        SECTION("arg: example:contInList")
+        {
+            lsArg = dataPath_{Scope::Relative, {{container_{"contInList"}}}};
+            expectedPath = schemaPath_{Scope::Absolute, {{module_{"example"}, list_{"list"}}, {container_{"contInList"}}}};
+        }
+
+        SECTION("arg: /example:a")
+        {
+            lsArg = dataPath_{Scope::Absolute, {{module_{"example"}, container_{"a"}}}};
+            expectedPath = schemaPath_{Scope::Absolute, {{module_{"example"}, container_{"a"}}}};
+        }
+
+        SECTION("arg: /example:list")
+        {
+            lsArg = dataPath_{Scope::Absolute, {{module_{"example"}, list_{"list"}}}};
+            expectedPath = schemaPath_{Scope::Absolute, {{module_{"example"}, list_{"list"}}}};
+        }
+
+        SECTION("arg example:*")
+        {
+            lsArg = module_{"example"};
+            expectedPath = module_{"example"};
+        }
+    }
+    MockDatastoreAccess datastore;
+    REQUIRE_CALL(datastore, schema()).RETURN(schema);
+    ls_ ls;
+    ls.m_path = lsArg;
+    REQUIRE_CALL(*schema, availableNodes(expectedPath, Recursion::NonRecursive)).RETURN(std::set<std::string>{});
+    Interpreter(parser, datastore)(ls);
+}
diff --git a/tests/parser_methods.cpp b/tests/parser_methods.cpp
deleted file mode 100644
index 4f7a482..0000000
--- a/tests/parser_methods.cpp
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2018 CESNET, https://photonics.cesnet.cz/
- * Copyright (C) 2018 FIT CVUT, https://fit.cvut.cz/
- *
- * Written by Václav Kubernát <kubervac@fit.cvut.cz>
- *
-*/
-
-#include <experimental/iterator>
-#include "trompeloeil_doctest.hpp"
-#include "ast_commands.hpp"
-#include "parser.hpp"
-#include "static_schema.hpp"
-
-namespace std {
-std::ostream& operator<<(std::ostream& s, const std::set<std::string> set)
-{
-    s << std::endl
-      << "{";
-    std::copy(set.begin(), set.end(), std::experimental::make_ostream_joiner(s, ", "));
-    s << "}" << std::endl;
-    return s;
-}
-}
-
-TEST_CASE("parser methods")
-{
-    auto schema = std::make_shared<StaticSchema>();
-    schema->addModule("example");
-    schema->addModule("second");
-    schema->addContainer("/", "example:a");
-    schema->addList("/example:a", "example:listInCont", {"number"});
-    schema->addContainer("/", "second:a");
-    schema->addContainer("/", "example:b");
-    schema->addContainer("/example:a", "example:a2");
-    schema->addContainer("/example:b", "example:b2");
-    schema->addContainer("/example:a/example:a2", "example:a3");
-    schema->addContainer("/example:b/example:b2", "example:b3");
-    schema->addList("/", "example:list", {"number"});
-    schema->addContainer("/example:list", "example:contInList");
-    schema->addList("/", "example:twoKeyList", {"number", "name"});
-    Parser parser(schema);
-
-    SECTION("availableNodes")
-    {
-        std::set<std::string> expected;
-        boost::optional<boost::variant<dataPath_, schemaPath_, module_>> arg{boost::none};
-        SECTION("cwd: /")
-        {
-            SECTION("arg: <none>")
-            {
-                expected = {"example:a", "example:b", "example:list", "example:twoKeyList", "second:a"};
-            }
-
-            SECTION("arg: example:a")
-            {
-                arg = dataPath_{Scope::Relative, {{module_{"example"}, container_{"a"}}}};
-                expected = {"example:a2", "example:listInCont"};
-            }
-
-            SECTION("arg: example:list")
-            {
-                arg = dataPath_{Scope::Relative, {{module_{"example"}, list_{"list"}}}};
-                expected = {"example:contInList"};
-            }
-
-            SECTION("arg: /example:a")
-            {
-                arg = dataPath_{Scope::Absolute, {{module_{"example"}, container_{"a"}}}};
-                expected = {"example:a2", "example:listInCont"};
-            }
-
-            SECTION("arg: /example:list")
-            {
-                arg = dataPath_{Scope::Absolute, {{module_{"example"}, list_{"list"}}}};
-                expected = {"example:contInList"};
-            }
-        }
-        SECTION("cwd: /example:a")
-        {
-            parser.changeNode({Scope::Relative, {{module_{"example"}, container_{"a"}}}});
-
-            SECTION("arg: <none>")
-            {
-                expected = {"example:a2", "example:listInCont"};
-            }
-
-            SECTION("arg: example:a2")
-            {
-                arg = dataPath_{Scope::Relative, {{container_{"a2"}}}};
-                expected = {"example:a3"};
-            }
-
-            SECTION("arg: example:listInCont")
-            {
-                arg = dataPath_{Scope::Relative, {{list_{"listInCont"}}}};
-            }
-
-            SECTION("arg: /example:a")
-            {
-                arg = dataPath_{Scope::Absolute, {{module_{"example"}, container_{"a"}}}};
-                expected = {"example:a2", "example:listInCont"};
-            }
-
-            SECTION("arg: /example:list")
-            {
-                arg = dataPath_{Scope::Absolute, {{module_{"example"}, list_{"list"}}}};
-                expected = {"example:contInList"};
-            }
-        }
-        SECTION("cwd: /example:list")
-        {
-            parser.changeNode({Scope::Relative, {{module_{"example"}, list_{"list"}}}});
-
-            SECTION("arg: <none>")
-            {
-                expected = {"example:contInList"};
-            }
-
-            SECTION("arg: example:contInList")
-            {
-                arg = dataPath_{Scope::Relative, {{container_{"contInList"}}}};
-            }
-
-            SECTION("arg: /example:a")
-            {
-                arg = dataPath_{Scope::Absolute, {{module_{"example"}, container_{"a"}}}};
-                expected = {"example:a2", "example:listInCont"};
-            }
-
-            SECTION("arg: /example:list")
-            {
-                arg = dataPath_{Scope::Absolute, {{module_{"example"}, list_{"list"}}}};
-                expected = {"example:contInList"};
-            }
-        }
-
-        REQUIRE(expected == parser.availableNodes(arg, Recursion::NonRecursive));
-    }
-}
diff --git a/tests/pretty_printers.hpp b/tests/pretty_printers.hpp
index 98638ea..d49d244 100644
--- a/tests/pretty_printers.hpp
+++ b/tests/pretty_printers.hpp
@@ -82,4 +82,22 @@
     s << type.m_type << (type.m_units ? " units: " + *type.m_units : "");
     return s;
 }
+
+std::ostream& operator<<(std::ostream& s, const boost::optional<std::string>& opt)
+{
+    s << (opt ? *opt : "std::nullopt");
+    return s;
+}
+}
+
+std::ostream& operator<<(std::ostream& s, const boost::variant<dataPath_, schemaPath_, module_>& path)
+{
+    if (path.type() == typeid(module_)) {
+        s << "module: " << boost::get<module_>(path).m_name << "\n";
+    } else if (path.type() == typeid(dataPath_)) {
+        s << "dataPath: " << pathToDataString(boost::get<dataPath_>(path), Prefixes::WhenNeeded) << "\n";
+    } else {
+        s << "schemaPath: " << pathToSchemaString(boost::get<schemaPath_>(path), Prefixes::WhenNeeded) << "\n";
+    }
+    return s;
 }