Add ls
Change-Id: I86f799ff9577940c7df8e01cda6c6b7867de8e7e
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cae063a..df49648 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -114,6 +114,7 @@
target_link_libraries(test_${fname} TestCatchIntegration)
endmacro()
cli_test(cd)
+ cli_test(ls)
cli_test(presence_containers)
cli_test(leaf_editing)
diff --git a/src/ast_commands.cpp b/src/ast_commands.cpp
index 9ef9044..89e2f74 100644
--- a/src/ast_commands.cpp
+++ b/src/ast_commands.cpp
@@ -24,6 +24,11 @@
return this->m_path == b.m_path;
}
+bool ls_::operator==(const ls_& b) const
+{
+ return this->m_path == b.m_path;
+}
+
bool enum_::operator==(const enum_& b) const
{
return this->m_value == b.m_value;
diff --git a/src/ast_commands.hpp b/src/ast_commands.hpp
index 90af8ea..d7d47c9 100644
--- a/src/ast_commands.hpp
+++ b/src/ast_commands.hpp
@@ -28,6 +28,11 @@
using keyValue_ = std::pair<std::string, std::string>;
+struct ls_ : x3::position_tagged {
+ bool operator==(const ls_& b) const;
+ boost::optional<path_> m_path;
+};
+
struct cd_ : x3::position_tagged {
bool operator==(const cd_& b) const;
path_ m_path;
@@ -63,8 +68,9 @@
leaf_data_ m_data;
};
-using command_ = boost::variant<cd_, create_, delete_, set_>;
+using command_ = boost::variant<ls_, cd_, create_, delete_, set_>;
+BOOST_FUSION_ADAPT_STRUCT(ls_, m_path)
BOOST_FUSION_ADAPT_STRUCT(cd_, m_path)
BOOST_FUSION_ADAPT_STRUCT(create_, m_path)
BOOST_FUSION_ADAPT_STRUCT(delete_, m_path)
diff --git a/src/ast_handlers.hpp b/src/ast_handlers.hpp
index b58613c..2953dad 100644
--- a/src/ast_handlers.hpp
+++ b/src/ast_handlers.hpp
@@ -204,6 +204,8 @@
};
+struct ls_class;
+
struct cd_class {
template <typename Iterator, typename Exception, typename Context>
x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const& x, Context const& context)
diff --git a/src/grammars.hpp b/src/grammars.hpp
index ed21e31..06e1bf8 100644
--- a/src/grammars.hpp
+++ b/src/grammars.hpp
@@ -34,6 +34,7 @@
x3::rule<leaf_data_uint_class, uint32_t> const leaf_data_uint = "leaf_data_uint";
x3::rule<leaf_data_string_class, std::string> const leaf_data_string = "leaf_data_string";
+x3::rule<ls_class, ls_> const ls = "ls";
x3::rule<cd_class, cd_> const cd = "cd";
x3::rule<set_class, set_> const set = "set";
x3::rule<create_class, create_> const create = "create";
@@ -125,6 +126,9 @@
auto const space_separator =
x3::omit[x3::no_skip[space]];
+auto const ls_def =
+ lit("ls") >> -path;
+
auto const cd_def =
lit("cd") >> space_separator > path;
@@ -138,7 +142,7 @@
lit("set") >> space_separator > leafPath > leaf_data;
auto const command_def =
- x3::expect[cd | create | delete_rule | set] >> x3::eoi;
+ x3::expect[cd | create | delete_rule | set | ls] >> x3::eoi;
#if __clang__
#pragma GCC diagnostic pop
@@ -165,6 +169,7 @@
BOOST_SPIRIT_DEFINE(leaf_data_uint)
BOOST_SPIRIT_DEFINE(leaf_data_string)
BOOST_SPIRIT_DEFINE(set)
+BOOST_SPIRIT_DEFINE(ls)
BOOST_SPIRIT_DEFINE(cd)
BOOST_SPIRIT_DEFINE(create)
BOOST_SPIRIT_DEFINE(delete_rule)
diff --git a/src/interpreter.cpp b/src/interpreter.cpp
index 19a163b..f71c12f 100644
--- a/src/interpreter.cpp
+++ b/src/interpreter.cpp
@@ -45,6 +45,14 @@
std::cout << "Presence container " << cont.m_name << " deleted." << std::endl;
}
+void Interpreter::operator()(const ls_& ls) const
+{
+ std::cout << "Possible nodes:" << std::endl;
+
+ for (const auto& it : m_parser.availableNodes(ls.m_path))
+ std::cout << it << std::endl;
+}
+
Interpreter::Interpreter(Parser& parser, Schema&)
: m_parser(parser)
{
diff --git a/src/interpreter.hpp b/src/interpreter.hpp
index 64cc0e9..8acf8bd 100644
--- a/src/interpreter.hpp
+++ b/src/interpreter.hpp
@@ -18,6 +18,7 @@
void operator()(const cd_&) const;
void operator()(const create_&) const;
void operator()(const delete_&) const;
+ void operator()(const ls_&) const;
private:
Parser& m_parser;
diff --git a/src/parser.cpp b/src/parser.cpp
index ac3ba84..0eb94fd 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -53,3 +53,11 @@
{
return pathToDataString(m_curDir);
}
+
+std::set<std::string> Parser::availableNodes(const boost::optional<path_>& path) const
+{
+ auto pathArg = m_curDir;
+ if (path)
+ pathArg.m_nodes.insert(pathArg.m_nodes.end(), path->m_nodes.begin(), path->m_nodes.end());
+ return m_schema->childNodes(pathArg);
+}
diff --git a/src/parser.hpp b/src/parser.hpp
index 05e636e..0f1fd79 100644
--- a/src/parser.hpp
+++ b/src/parser.hpp
@@ -30,6 +30,7 @@
command_ parseCommand(const std::string& line, std::ostream& errorStream);
void changeNode(const path_& name);
std::string currentNode() const;
+ std::set<std::string> availableNodes(const boost::optional<path_>& path) const;
private:
const std::shared_ptr<const Schema> m_schema;
diff --git a/tests/ls.cpp b/tests/ls.cpp
new file mode 100644
index 0000000..c2cc5fe
--- /dev/null
+++ b/tests/ls.cpp
@@ -0,0 +1,61 @@
+/*
+ * 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 "trompeloeil_catch.h"
+#include "ast_commands.hpp"
+#include "parser.hpp"
+#include "static_schema.hpp"
+
+TEST_CASE("ls")
+{
+ auto schema = std::make_shared<StaticSchema>();
+ schema->addModule("example");
+ schema->addModule("second");
+ schema->addContainer("", "example:a");
+ 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);
+ std::string input;
+ std::ostringstream errorStream;
+
+ SECTION("valid input")
+ {
+ ls_ expected;
+
+ SECTION("no arguments")
+ {
+ input = "ls";
+ }
+
+ SECTION("with path argument")
+ {
+ input = "ls example:a";
+ expected.m_path = path_{{node_(module_{"example"}, container_{"a"})}};
+ }
+
+ command_ command = parser.parseCommand(input, errorStream);
+ REQUIRE(command.type() == typeid(ls_));
+ REQUIRE(boost::get<ls_>(command) == expected);
+ }
+ SECTION("invalid input")
+ {
+ SECTION("invalid path")
+ {
+ input = "ls example:nonexistent";
+ }
+
+ REQUIRE_THROWS(parser.parseCommand(input, errorStream));
+ }
+}