Add Interpreter tests
Change-Id: Ic08f3e8d72f9591b0167eb1f5057168dedef84d1
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7e70b41..baec077 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -272,7 +272,7 @@
cli_test(set_value_completion)
target_link_libraries(test_set_value_completion leaf_data_type)
cli_test(list_manipulation)
- cli_test(ls_interpreter)
+ cli_test(interpreter)
cli_test(path_utils)
target_link_libraries(test_path_utils path)
cli_test(keyvalue_completion)
diff --git a/tests/interpreter.cpp b/tests/interpreter.cpp
new file mode 100644
index 0000000..b296ca1
--- /dev/null
+++ b/tests/interpreter.cpp
@@ -0,0 +1,395 @@
+/*
+ * 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_MOCK2(listHasKey);
+ IMPLEMENT_CONST_MOCK1(leafIsKey);
+ IMPLEMENT_CONST_MOCK1(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("interpreter tests")
+{
+ auto schema = std::make_shared<MockSchema>();
+ Parser parser(schema);
+ MockDatastoreAccess datastore;
+ std::vector<std::unique_ptr<trompeloeil::expectation>> expectations;
+
+ std::vector<command_> toInterpret;
+
+ SECTION("ls")
+ {
+ boost::variant<dataPath_, schemaPath_, module_> expectedPath;
+ boost::optional<boost::variant<dataPath_, schemaPath_, module_>> lsArg;
+ SECTION("cwd: /")
+ {
+ SECTION("arg: <none>")
+ {
+ expectedPath = dataPath_{};
+ }
+
+ SECTION("arg: example:a")
+ {
+ lsArg = dataPath_{Scope::Relative, {{module_{"example"}, container_{"a"}}}};
+ expectedPath = dataPath_{Scope::Absolute, {{module_{"example"}, container_{"a"}}}};
+ }
+
+ SECTION("arg: example:list")
+ {
+ lsArg = dataPath_{Scope::Relative, {{module_{"example"}, list_{"list"}}}};
+ expectedPath = dataPath_{Scope::Absolute, {{module_{"example"}, list_{"list"}}}};
+ }
+
+ SECTION("arg: /example:a")
+ {
+ lsArg = dataPath_{Scope::Absolute, {{module_{"example"}, container_{"a"}}}};
+ expectedPath = dataPath_{Scope::Absolute, {{module_{"example"}, container_{"a"}}}};
+ }
+
+ SECTION("arg: /example:list")
+ {
+ lsArg = dataPath_{Scope::Absolute, {{module_{"example"}, list_{"list"}}}};
+ expectedPath = dataPath_{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 = dataPath_{Scope::Absolute, {{module_{"example"}, container_{"a"}}}};
+ }
+
+ SECTION("arg: example:a2")
+ {
+ lsArg = dataPath_{Scope::Relative, {{container_{"a2"}}}};
+ expectedPath = dataPath_{Scope::Absolute, {{module_{"example"}, container_{"a"}}, {container_{"a2"}}}};
+ }
+
+ SECTION("arg: example:listInCont")
+ {
+ lsArg = dataPath_{Scope::Relative, {{list_{"listInCont"}}}};
+ expectedPath = dataPath_{Scope::Absolute, {{module_{"example"}, container_{"a"}}, {list_{"listInCont"}}}};
+ }
+
+ SECTION("arg: /example:a")
+ {
+ lsArg = dataPath_{Scope::Absolute, {{module_{"example"}, container_{"a"}}}};
+ expectedPath = dataPath_{Scope::Absolute, {{module_{"example"}, container_{"a"}}}};
+ }
+
+ SECTION("arg: /example:list")
+ {
+ lsArg = dataPath_{Scope::Absolute, {{module_{"example"}, list_{"list"}}}};
+ expectedPath = dataPath_{Scope::Absolute, {{module_{"example"}, list_{"list"}}}};
+ }
+ }
+ SECTION("cwd: /example:list")
+ {
+ parser.changeNode({Scope::Relative, {{module_{"example"}, list_{"list"}}}});
+
+ SECTION("arg: <none>")
+ {
+ expectedPath = dataPath_{Scope::Absolute, {{module_{"example"}, list_{"list"}}}};
+ }
+
+ SECTION("arg: example:contInList")
+ {
+ lsArg = schemaPath_{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 = dataPath_{Scope::Absolute, {{module_{"example"}, container_{"a"}}}};
+ }
+
+ SECTION("arg: /example:list")
+ {
+ lsArg = dataPath_{Scope::Absolute, {{module_{"example"}, list_{"list"}}}};
+ expectedPath = dataPath_{Scope::Absolute, {{module_{"example"}, list_{"list"}}}};
+ }
+
+ SECTION("arg example:*")
+ {
+ lsArg = module_{"example"};
+ expectedPath = module_{"example"};
+ }
+ }
+ ls_ ls;
+ ls.m_path = lsArg;
+ expectations.push_back(NAMED_REQUIRE_CALL(datastore, schema()).RETURN(schema));
+ expectations.push_back(NAMED_REQUIRE_CALL(*schema, availableNodes(expectedPath, Recursion::NonRecursive)).RETURN(std::set<ModuleNodePair>{}));
+ toInterpret.push_back(ls);
+ }
+
+ SECTION("get")
+ {
+ using namespace std::string_literals;
+ DatastoreAccess::Tree treeReturned;
+ decltype(get_::m_path) inputPath;
+ std::string expectedPathArg;
+
+ SECTION("paths")
+ {
+ SECTION("/")
+ {
+ expectedPathArg = "/";
+ }
+
+ SECTION("module")
+ {
+ inputPath = module_{"mod"};
+ expectedPathArg = "/mod:*";
+ }
+
+ SECTION("path to a leaf")
+ {
+ expectedPathArg = "/mod:myLeaf";
+ Scope scope;
+ SECTION("cwd: /")
+ {
+ SECTION("absolute")
+ {
+ scope = Scope::Absolute;
+ }
+
+ SECTION("relative")
+ {
+ scope = Scope::Relative;
+ }
+
+ inputPath = dataPath_{scope, {dataNode_{{"mod"}, leaf_{"myLeaf"}}}};
+ }
+
+ SECTION("cwd: /mod:whatever")
+ {
+ parser.changeNode(dataPath_{Scope::Relative, {dataNode_{{"mod"}, container_{"whatever"}}}});
+ SECTION("absolute")
+ {
+ scope = Scope::Absolute;
+ inputPath = dataPath_{scope, {dataNode_{{"mod"}, leaf_{"myLeaf"}}}};
+ }
+
+ SECTION("relative")
+ {
+ scope = Scope::Relative;
+ inputPath = dataPath_{scope, {dataNode_{nodeup_{}}, dataNode_{{"mod"}, leaf_{"myLeaf"}}}};
+ }
+
+ }
+ }
+
+ SECTION("path to a list")
+ {
+ expectedPathArg = "/mod:myList[name='AHOJ']";
+ Scope scope;
+ SECTION("cwd: /")
+ {
+ SECTION("absolute")
+ {
+ scope = Scope::Absolute;
+ }
+
+ SECTION("relative")
+ {
+ scope = Scope::Relative;
+ }
+
+ inputPath = dataPath_{scope, {dataNode_{{"mod"}, listElement_{"myList", {{"name", "AHOJ"s}}}}}};
+ }
+
+ SECTION("cwd: /mod:whatever")
+ {
+ parser.changeNode(dataPath_{Scope::Relative, {dataNode_{{"mod"}, container_{"whatever"}}}});
+ SECTION("absolute")
+ {
+ scope = Scope::Absolute;
+ inputPath = dataPath_{scope, {dataNode_{{"mod"}, listElement_{"myList", {{"name", "AHOJ"s}}}}}};
+ }
+
+ SECTION("relative")
+ {
+ scope = Scope::Relative;
+ inputPath = dataPath_{scope, {dataNode_{nodeup_{}}, dataNode_{{"mod"}, listElement_{"myList", {{"name", "AHOJ"s}}}}}};
+ }
+ }
+ }
+ }
+
+ SECTION("trees")
+ {
+ expectedPathArg = "/";
+ SECTION("no leaflists")
+ {
+ treeReturned = {
+ {"/mod:AHOJ", 30},
+ {"/mod:CAU", std::string{"AYYY"}},
+ {"/mod:CUS", bool{true}}
+ };
+ }
+
+ SECTION("leaflist at the beginning of a tree")
+ {
+ treeReturned = {
+ {"/mod:addresses", special_{SpecialValue::LeafList}},
+ {"/mod:addresses[.='0.0.0.0']", std::string{"0.0.0.0"}},
+ {"/mod:addresses[.='127.0.0.1']", std::string{"127.0.0.1"}},
+ {"/mod:addresses[.='192.168.0.1']", std::string{"192.168.0.1"}},
+ {"/mod:AHOJ", 30},
+ {"/mod:CAU", std::string{"AYYY"}},
+ };
+ }
+
+ SECTION("leaflist in the middle of a tree")
+ {
+ treeReturned = {
+ {"/mod:AHOJ", 30},
+ {"/mod:addresses", special_{SpecialValue::LeafList}},
+ {"/mod:addresses[.='0.0.0.0']", std::string{"0.0.0.0"}},
+ {"/mod:addresses[.='127.0.0.1']", std::string{"127.0.0.1"}},
+ {"/mod:addresses[.='192.168.0.1']", std::string{"192.168.0.1"}},
+ {"/mod:CAU", std::string{"AYYY"}},
+ };
+ }
+
+ SECTION("leaflist at the end of a tree")
+ {
+ treeReturned = {
+ {"/mod:AHOJ", 30},
+ {"/mod:CAU", std::string{"AYYY"}},
+ {"/mod:addresses", special_{SpecialValue::LeafList}},
+ {"/mod:addresses[.='0.0.0.0']", std::string{"0.0.0.0"}},
+ {"/mod:addresses[.='127.0.0.1']", std::string{"127.0.0.1"}},
+ {"/mod:addresses[.='192.168.0.1']", std::string{"192.168.0.1"}},
+ };
+ }
+ }
+
+ get_ getCmd;
+ getCmd.m_path = inputPath;
+ expectations.push_back(NAMED_REQUIRE_CALL(datastore, getItems(expectedPathArg)).RETURN(treeReturned));
+ toInterpret.push_back(getCmd);
+ }
+
+ SECTION("create/delete")
+ {
+ using namespace std::string_literals;
+ dataPath_ inputPath;
+
+ SECTION("list instance")
+ {
+ inputPath.m_nodes = {dataNode_{{"mod"}, listElement_{"department", {{"name", "engineering"s}}}}};
+ expectations.push_back(NAMED_REQUIRE_CALL(datastore, createListInstance("/mod:department[name='engineering']")));
+ expectations.push_back(NAMED_REQUIRE_CALL(datastore, deleteListInstance("/mod:department[name='engineering']")));
+ }
+
+ SECTION("leaflist instance")
+ {
+ inputPath.m_nodes = {dataNode_{{"mod"}, leafListElement_{"addresses", "127.0.0.1"s}}};
+ expectations.push_back(NAMED_REQUIRE_CALL(datastore, createLeafListInstance("/mod:addresses[.='127.0.0.1']")));
+ expectations.push_back(NAMED_REQUIRE_CALL(datastore, deleteLeafListInstance("/mod:addresses[.='127.0.0.1']")));
+ }
+
+ SECTION("presence container")
+ {
+ inputPath.m_nodes = {dataNode_{{"mod"}, container_{"pContainer"}}};
+ expectations.push_back(NAMED_REQUIRE_CALL(datastore, createPresenceContainer("/mod:pContainer")));
+ expectations.push_back(NAMED_REQUIRE_CALL(datastore, deletePresenceContainer("/mod:pContainer")));
+ }
+
+ create_ createCmd;
+ createCmd.m_path = inputPath;
+ delete_ deleteCmd;
+ deleteCmd.m_path = inputPath;
+ toInterpret.push_back(createCmd);
+ toInterpret.push_back(deleteCmd);
+ }
+
+ SECTION("commit")
+ {
+ expectations.push_back(NAMED_REQUIRE_CALL(datastore, commitChanges()));
+ toInterpret.push_back(commit_{});
+ }
+
+ SECTION("discard")
+ {
+ expectations.push_back(NAMED_REQUIRE_CALL(datastore, discardChanges()));
+ toInterpret.push_back(discard_{});
+ }
+
+
+ SECTION("set")
+ {
+ dataPath_ inputPath;
+ leaf_data_ inputData;
+
+ SECTION("setting identityRef without module") // The parser has to fill in the module
+ {
+ inputPath.m_nodes = {dataNode_{{"mod"}, leaf_{"animal"}}};
+ inputData = identityRef_{"Doge"};
+ expectations.push_back(NAMED_REQUIRE_CALL(datastore, setLeaf("/mod:animal", identityRef_{"mod", "Doge"})));
+ }
+
+
+ set_ setCmd;
+ setCmd.m_path = inputPath;
+ setCmd.m_data = inputData;
+ toInterpret.push_back(setCmd);
+ }
+
+
+ SECTION("copy")
+ {
+ SECTION("running -> startup")
+ {
+ expectations.push_back(NAMED_REQUIRE_CALL(datastore, copyConfig(Datastore::Running, Datastore::Startup)));
+ toInterpret.push_back(copy_{{}, Datastore::Running, Datastore::Startup});
+ }
+
+ SECTION("startup -> running")
+ {
+ expectations.push_back(NAMED_REQUIRE_CALL(datastore, copyConfig(Datastore::Startup, Datastore::Running)));
+ toInterpret.push_back(copy_{{}, Datastore::Startup, Datastore::Running});
+ }
+ }
+
+ for (const auto& command : toInterpret) {
+ boost::apply_visitor(Interpreter(parser, datastore), command);
+ }
+}
diff --git a/tests/ls_interpreter.cpp b/tests/ls_interpreter.cpp
deleted file mode 100644
index b3d927b..0000000
--- a/tests/ls_interpreter.cpp
+++ /dev/null
@@ -1,154 +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 "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_MOCK2(listHasKey);
- IMPLEMENT_CONST_MOCK1(leafIsKey);
- IMPLEMENT_CONST_MOCK1(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 = dataPath_{};
- }
-
- SECTION("arg: example:a")
- {
- lsArg = dataPath_{Scope::Relative, {{module_{"example"}, container_{"a"}}}};
- expectedPath = dataPath_{Scope::Absolute, {{module_{"example"}, container_{"a"}}}};
- }
-
- SECTION("arg: example:list")
- {
- lsArg = dataPath_{Scope::Relative, {{module_{"example"}, list_{"list"}}}};
- expectedPath = dataPath_{Scope::Absolute, {{module_{"example"}, list_{"list"}}}};
- }
-
- SECTION("arg: /example:a")
- {
- lsArg = dataPath_{Scope::Absolute, {{module_{"example"}, container_{"a"}}}};
- expectedPath = dataPath_{Scope::Absolute, {{module_{"example"}, container_{"a"}}}};
- }
-
- SECTION("arg: /example:list")
- {
- lsArg = dataPath_{Scope::Absolute, {{module_{"example"}, list_{"list"}}}};
- expectedPath = dataPath_{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 = dataPath_{Scope::Absolute, {{module_{"example"}, container_{"a"}}}};
- }
-
- SECTION("arg: example:a2")
- {
- lsArg = dataPath_{Scope::Relative, {{container_{"a2"}}}};
- expectedPath = dataPath_{Scope::Absolute, {{module_{"example"}, container_{"a"}}, {container_{"a2"}}}};
- }
-
- SECTION("arg: example:listInCont")
- {
- lsArg = dataPath_{Scope::Relative, {{list_{"listInCont"}}}};
- expectedPath = dataPath_{Scope::Absolute, {{module_{"example"}, container_{"a"}}, {list_{"listInCont"}}}};
- }
-
- SECTION("arg: /example:a")
- {
- lsArg = dataPath_{Scope::Absolute, {{module_{"example"}, container_{"a"}}}};
- expectedPath = dataPath_{Scope::Absolute, {{module_{"example"}, container_{"a"}}}};
- }
-
- SECTION("arg: /example:list")
- {
- lsArg = dataPath_{Scope::Absolute, {{module_{"example"}, list_{"list"}}}};
- expectedPath = dataPath_{Scope::Absolute, {{module_{"example"}, list_{"list"}}}};
- }
- }
- SECTION("cwd: /example:list")
- {
- parser.changeNode({Scope::Relative, {{module_{"example"}, list_{"list"}}}});
-
- SECTION("arg: <none>")
- {
- expectedPath = dataPath_{Scope::Absolute, {{module_{"example"}, list_{"list"}}}};
- }
-
- SECTION("arg: example:contInList")
- {
- lsArg = dataPath_{Scope::Relative, {{container_{"contInList"}}}};
- expectedPath = dataPath_{Scope::Absolute, {{module_{"example"}, list_{"list"}}, {container_{"contInList"}}}};
- }
-
- SECTION("arg: /example:a")
- {
- lsArg = dataPath_{Scope::Absolute, {{module_{"example"}, container_{"a"}}}};
- expectedPath = dataPath_{Scope::Absolute, {{module_{"example"}, container_{"a"}}}};
- }
-
- SECTION("arg: /example:list")
- {
- lsArg = dataPath_{Scope::Absolute, {{module_{"example"}, list_{"list"}}}};
- expectedPath = dataPath_{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<ModuleNodePair>{});
- Interpreter(parser, datastore)(ls);
-}