Add modules

Change-Id: Idafb0f57dd032d4f88658de15d293bdefac0567f
diff --git a/tests/cd.cpp b/tests/cd.cpp
index 29187ff..5bf0172 100644
--- a/tests/cd.cpp
+++ b/tests/cd.cpp
@@ -14,114 +14,131 @@
 TEST_CASE("cd")
 {
     auto schema = std::make_shared<StaticSchema>();
-    schema->addContainer("", "a");
-    schema->addContainer("", "b");
-    schema->addContainer("a", "a2");
-    schema->addContainer("b", "b2");
-    schema->addContainer("a/a2", "a3");
-    schema->addContainer("b/b2", "b3");
-    schema->addList("", "list", {"number"});
-    schema->addContainer("list", "contInList");
-    schema->addList("", "twoKeyList", {"number", "name"});
+    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")
     {
         cd_ expected;
 
         SECTION("container")
         {
-            SECTION("a")
+            SECTION("example:a")
             {
-                input = "cd a";
-                expected.m_path.m_nodes.push_back(container_("a"));
+                input = "cd example:a";
+                expected.m_path.m_nodes.push_back(node_(module_{"example"}, container_("a")));
             }
 
-            SECTION("b")
+            SECTION("second:a")
             {
-                input = "cd b";
-                expected.m_path.m_nodes.push_back(container_("b"));
+                input = "cd second:a";
+                expected.m_path.m_nodes.push_back(node_(module_{"second"}, container_("a")));
             }
 
-            SECTION("a/a2")
+            SECTION("example:b")
             {
-                input = "cd a/a2";
-                expected.m_path.m_nodes.push_back(container_("a"));
-                expected.m_path.m_nodes.push_back(container_("a2"));
+                input = "cd example:b";
+                expected.m_path.m_nodes.push_back(node_(module_{"example"}, container_("b")));
             }
 
-            SECTION("b/b2")
+            SECTION("example:a/a2")
             {
-                input = "cd b/b2";
-                expected.m_path.m_nodes.push_back(container_("b"));
-                expected.m_path.m_nodes.push_back(container_("b2"));
+                input = "cd example:a/a2";
+                expected.m_path.m_nodes.push_back(node_(module_{"example"}, container_("a")));
+                expected.m_path.m_nodes.push_back(node_(container_("a2")));
+            }
+
+            SECTION("example:a/example:a2")
+            {
+                input = "cd example:a/example:a2";
+                expected.m_path.m_nodes.push_back(node_(module_{"example"}, container_("a")));
+                expected.m_path.m_nodes.push_back(node_(module_{"example"}, container_("a2")));
+            }
+
+            SECTION("example:b/b2")
+            {
+                input = "cd example:b/b2";
+                expected.m_path.m_nodes.push_back(node_(module_{"example"}, container_("b")));
+                expected.m_path.m_nodes.push_back(node_(container_("b2")));
             }
         }
 
         SECTION("list elements")
         {
-            SECTION("list[number=1]")
+            SECTION("example:list[number=1]")
             {
-                input = "cd list[number=1]";
+                input = "cd example:list[number=1]";
                 auto keys = std::map<std::string, std::string>{
                     {"number", "1"}};
-                expected.m_path.m_nodes.push_back(listElement_("list", keys));
+                expected.m_path.m_nodes.push_back(node_(module_{"example"}, listElement_("list", keys)));
             }
 
-            SECTION("list[number=1]/contInList")
+            SECTION("example:list[number=1]/contInList")
             {
-                input = "cd list[number=1]/contInList";
+                input = "cd example:list[number=1]/contInList";
                 auto keys = std::map<std::string, std::string>{
                     {"number", "1"}};
-                expected.m_path.m_nodes.push_back(listElement_("list", keys));
-                expected.m_path.m_nodes.push_back(container_("contInList"));
+                expected.m_path.m_nodes.push_back(node_(module_{"example"}, listElement_("list", keys)));
+                expected.m_path.m_nodes.push_back(node_(container_("contInList")));
             }
 
-            SECTION("twoKeyList[number=4 name=abcd]")
+            SECTION("example:twoKeyList[number=4 name=abcd]")
             {
-                input = "cd twoKeyList[number=4 name=abcd]";
+                input = "cd example:twoKeyList[number=4 name=abcd]";
                 auto keys = std::map<std::string, std::string>{
                     {"number", "4"},
                     {"name", "abcd"}};
-                expected.m_path.m_nodes.push_back(listElement_("twoKeyList", keys));
+                expected.m_path.m_nodes.push_back(node_(module_{"example"}, listElement_("twoKeyList", keys)));
             }
         }
 
         SECTION("whitespace handling")
         {
-            SECTION("  cd   a     ")
+            SECTION("  cd   example:a     ")
             {
-                input = "  cd   a     ";
-                expected.m_path.m_nodes.push_back(container_("a"));
+                input = "  cd   example:a     ";
+                expected.m_path.m_nodes.push_back(node_(module_{"example"}, container_("a")));
             }
         }
 
         SECTION("moving up")
         {
-            SECTION("a/..")
+            SECTION("example:a/..")
             {
-                input = "cd a/..";
-                expected.m_path.m_nodes.push_back(container_("a"));
-                expected.m_path.m_nodes.push_back(nodeup_());
+                input = "cd example:a/..";
+                expected.m_path.m_nodes.push_back(node_(module_{"example"}, container_("a")));
+                expected.m_path.m_nodes.push_back(node_(nodeup_()));
             }
 
-            SECTION("a/../a")
+            SECTION("example:a/../example:a")
             {
-                input = "cd a/../a";
-                expected.m_path.m_nodes.push_back(container_("a"));
-                expected.m_path.m_nodes.push_back(nodeup_());
-                expected.m_path.m_nodes.push_back(container_("a"));
+                input = "cd example:a/../example:a";
+                expected.m_path.m_nodes.push_back(node_(module_{"example"}, container_("a")));
+                expected.m_path.m_nodes.push_back(node_(nodeup_()));
+                expected.m_path.m_nodes.push_back(node_(module_{"example"}, container_("a")));
             }
 
-            SECTION("a/../a/a2")
+            SECTION("example:a/../example:a/a2")
             {
-                input = "cd a/../a/a2";
-                expected.m_path.m_nodes.push_back(container_("a"));
-                expected.m_path.m_nodes.push_back(nodeup_());
-                expected.m_path.m_nodes.push_back(container_("a"));
-                expected.m_path.m_nodes.push_back(container_("a2"));
+                input = "cd example:a/../example:a/a2";
+                expected.m_path.m_nodes.push_back(node_(module_{"example"}, container_("a")));
+                expected.m_path.m_nodes.push_back(node_(nodeup_()));
+                expected.m_path.m_nodes.push_back(node_(module_{"example"}, container_("a")));
+                expected.m_path.m_nodes.push_back(node_(container_("a2")));
             }
         }
 
@@ -133,65 +150,124 @@
     {
         SECTION("missing space between a command and its arguments")
         {
-            SECTION("cda")
+            SECTION("cdexample:a")
             {
-                input = "cda";
+                input = "cdexample:a";
             }
         }
-        SECTION("garbage arguments handling")
+
+        SECTION("whitespace between module and nodename")
         {
-            SECTION("cd a garbage")
+            SECTION("cd example: a")
             {
-                input = "cd a garbage";
-            }
-            SECTION("cd a/a2 garbage")
-            {
-                input = "cd a/a2 garbage";
-            }
-        }
-        SECTION("invalid identifiers")
-        {
-            SECTION("nonexistent")
-            {
-                input = "cd nonexistent";
+                input = "cd example: a";
             }
 
-            SECTION("nonexistent/lol")
+            SECTION("cd example : a")
             {
-                input = "cd nonexistent/lol";
+                input = "cd example : a";
+            }
+
+            SECTION("cd example :a")
+            {
+                input = "cd example :a";
+            }
+        }
+
+        SECTION("entering modules")
+        {
+            SECTION("cd example")
+            {
+                input = "cd example";
+            }
+
+            SECTION("cd example:")
+            {
+                input = "cd example:";
+            }
+        }
+
+        SECTION("garbage arguments handling")
+        {
+            SECTION("cd example:a garbage")
+            {
+                input = "cd example:a garbage";
+            }
+            SECTION("cd example:a/a2 garbage")
+            {
+                input = "cd example:a/a2 garbage";
+            }
+        }
+
+        SECTION("invalid node identifiers")
+        {
+            SECTION("example:nonexistent")
+            {
+                input = "cd example:nonexistent";
+            }
+
+            SECTION("example:nonexistent/lol")
+            {
+                input = "cd example:nonexistent/lol";
+            }
+        }
+
+        SECTION("invalid module identifiers")
+        {
+            SECTION("elpmaxe:nonexistent")
+            {
+                input = "cd elpmaxe:nonexistent";
+            }
+
+            SECTION("elpmaxe:nonexistent/example:lol")
+            {
+                input = "cd elpmaxe:nonexistent/example:lol";
+            }
+        }
+
+        SECTION("no top-level module")
+        {
+            SECTION("cd a")
+            {
+                input = "cd a";
+            }
+
+            SECTION("cd example:a/../a")
+            {
+                input = "cd example:a/../a";
             }
         }
 
         SECTION("invalid list key identifiers")
         {
-            SECTION("list")
+            SECTION("example:list")
             {
-                input = "cd list";
+                input = "cd example:list";
             }
 
-            SECTION("list[]")
+            SECTION("example:list[]")
             {
-                input = "cd list[]";
+                input = "cd example:list[]";
             }
 
-            SECTION("twoKeyList[invalidKey=4]")
+            SECTION("example:twoKeyList[invalidKey=4]")
             {
-                input = "cd twoKeyList[invalidKey=4]";
+                input = "cd example:twoKeyList[invalidKey=4]";
             }
 
-            SECTION("twoKeyList[number=4 number=5]")
+            SECTION("example:twoKeyList[number=4 number=5]")
             {
-                input = "cd twoKeyList[number=4 number=5]";
+                input = "cd example:twoKeyList[number=4 number=5]";
             }
 
-            SECTION("twoKeyList[number=4 name=lol number=7]")
+            SECTION("example:twoKeyList[number=4 name=lol number=7]")
             {
-                input = "cd twoKeyList[number=4 name=lol number=7]";
+                input = "cd example:twoKeyList[number=4 name=lol number=7]";
             }
 
-            SECTION("twoKeyList[number=4]")
+            SECTION("example:twoKeyList[number=4]")
             {
-                input = "cd twoKeyList[number=4]";
+                input = "cd example:twoKeyList[number=4]";
             }
         }
         REQUIRE_THROWS(parser.parseCommand(input, errorStream));
diff --git a/tests/leaf_editing.cpp b/tests/leaf_editing.cpp
index b8c5591..d8f21db 100644
--- a/tests/leaf_editing.cpp
+++ b/tests/leaf_editing.cpp
@@ -14,16 +14,17 @@
 TEST_CASE("leaf editing")
 {
     auto schema = std::make_shared<StaticSchema>();
-    schema->addContainer("", "contA");
-    schema->addLeaf("", "leafString", yang::LeafDataTypes::String);
-    schema->addLeaf("", "leafDecimal", yang::LeafDataTypes::Decimal);
-    schema->addLeaf("", "leafBool", yang::LeafDataTypes::Bool);
-    schema->addLeaf("", "leafInt", yang::LeafDataTypes::Int);
-    schema->addLeaf("", "leafUint", yang::LeafDataTypes::Uint);
-    schema->addLeafEnum("", "leafEnum", {"lol", "data", "coze"});
-    schema->addLeaf("contA", "leafInCont", yang::LeafDataTypes::String);
-    schema->addList("", "list", {"number"});
-    schema->addLeaf("list", "leafInList", yang::LeafDataTypes::String);
+    schema->addModule("mod");
+    schema->addContainer("", "mod:contA");
+    schema->addLeaf("", "mod:leafString", yang::LeafDataTypes::String);
+    schema->addLeaf("", "mod:leafDecimal", yang::LeafDataTypes::Decimal);
+    schema->addLeaf("", "mod:leafBool", yang::LeafDataTypes::Bool);
+    schema->addLeaf("", "mod:leafInt", yang::LeafDataTypes::Int);
+    schema->addLeaf("", "mod:leafUint", yang::LeafDataTypes::Uint);
+    schema->addLeafEnum("", "mod:leafEnum", {"lol", "data", "coze"});
+    schema->addLeaf("mod:contA", "mod:leafInCont", yang::LeafDataTypes::String);
+    schema->addList("", "mod:list", {"number"});
+    schema->addLeaf("mod:list", "mod:leafInList", yang::LeafDataTypes::String);
     Parser parser(schema);
     std::string input;
     std::ostringstream errorStream;
@@ -34,26 +35,26 @@
 
         SECTION("set leafString some_data")
         {
-            input = "set leafString some_data";
-            expected.m_path.m_nodes.push_back(leaf_("leafString"));
+            input = "set mod:leafString some_data";
+            expected.m_path.m_nodes.push_back(node_{module_{"mod"}, leaf_("leafString")});
             expected.m_data = std::string("some_data");
         }
 
-        SECTION("set contA/leafInCont more_data")
+        SECTION("set mod:contA/leafInCont more_data")
         {
-            input = "set contA/leafInCont more_data";
-            expected.m_path.m_nodes.push_back(container_("contA"));
-            expected.m_path.m_nodes.push_back(leaf_("leafInCont"));
+            input = "set mod:contA/leafInCont more_data";
+            expected.m_path.m_nodes.push_back(node_{module_{"mod"}, container_("contA")});
+            expected.m_path.m_nodes.push_back(node_{leaf_("leafInCont")});
             expected.m_data = std::string("more_data");
         }
 
         SECTION("set list[number=1]/leafInList another_data")
         {
-            input = "set list[number=1]/leafInList another_data";
+            input = "set mod:list[number=1]/leafInList another_data";
             auto keys = std::map<std::string, std::string>{
                 {"number", "1"}};
-            expected.m_path.m_nodes.push_back(listElement_("list", keys));
-            expected.m_path.m_nodes.push_back(leaf_("leafInList"));
+            expected.m_path.m_nodes.push_back(node_{module_{"mod"}, listElement_("list", keys)});
+            expected.m_path.m_nodes.push_back(node_{leaf_("leafInList")});
             expected.m_data = std::string("another_data");
         }
 
@@ -61,36 +62,36 @@
         {
             SECTION("string")
             {
-                input = "set leafString somedata";
-                expected.m_path.m_nodes.push_back(leaf_("leafString"));
+                input = "set mod:leafString somedata";
+                expected.m_path.m_nodes.push_back(node_{module_{"mod"}, leaf_("leafString")});
                 expected.m_data = std::string("somedata");
             }
 
             SECTION("int")
             {
-                input = "set leafInt 2";
-                expected.m_path.m_nodes.push_back(leaf_("leafInt"));
+                input = "set mod:leafInt 2";
+                expected.m_path.m_nodes.push_back(node_{module_{"mod"}, leaf_("leafInt")});
                 expected.m_data = 2;
             }
 
             SECTION("decimal")
             {
-                input = "set leafDecimal 3.14159";
-                expected.m_path.m_nodes.push_back(leaf_("leafDecimal"));
+                input = "set mod:leafDecimal 3.14159";
+                expected.m_path.m_nodes.push_back(node_{module_{"mod"}, leaf_("leafDecimal")});
                 expected.m_data = 3.14159;
             }
 
             SECTION("enum")
             {
-                input = "set leafEnum coze";
-                expected.m_path.m_nodes.push_back(leaf_("leafEnum"));
+                input = "set mod:leafEnum coze";
+                expected.m_path.m_nodes.push_back(node_{module_{"mod"}, leaf_("leafEnum")});
                 expected.m_data = enum_("coze");
             }
 
             SECTION("bool")
             {
-                input = "set leafBool true";
-                expected.m_path.m_nodes.push_back(leaf_("leafBool"));
+                input = "set mod:leafBool true";
+                expected.m_path.m_nodes.push_back(node_{module_{"mod"}, leaf_("leafBool")});
                 expected.m_data = true;
             }
         }
diff --git a/tests/presence_containers.cpp b/tests/presence_containers.cpp
index 87957cb..9683daf 100644
--- a/tests/presence_containers.cpp
+++ b/tests/presence_containers.cpp
@@ -15,13 +15,14 @@
 TEST_CASE("presence containers")
 {
     auto schema = std::make_shared<StaticSchema>();
-    schema->addContainer("", "a", yang::ContainerTraits::Presence);
-    schema->addContainer("", "b");
-    schema->addContainer("a", "a2");
-    schema->addContainer("a/a2", "a3", yang::ContainerTraits::Presence);
-    schema->addContainer("b", "b2", yang::ContainerTraits::Presence);
-    schema->addList("", "list", {"quote"});
-    schema->addContainer("list", "contInList", yang::ContainerTraits::Presence);
+    schema->addModule("mod");
+    schema->addContainer("", "mod:a", yang::ContainerTraits::Presence);
+    schema->addContainer("", "mod:b");
+    schema->addContainer("mod:a", "mod:a2");
+    schema->addContainer("mod:a/mod:a2", "mod:a3", yang::ContainerTraits::Presence);
+    schema->addContainer("mod:b", "mod:b2", yang::ContainerTraits::Presence);
+    schema->addList("", "mod:list", {"quote"});
+    schema->addContainer("mod:list", "mod:contInList", yang::ContainerTraits::Presence);
     Parser parser(schema);
     std::string input;
     std::ostringstream errorStream;
@@ -30,30 +31,30 @@
     {
         path_ expectedPath;
 
-        SECTION("a")
+        SECTION("mod:a")
         {
-            input = "a";
-            expectedPath.m_nodes = {container_("a")};
+            input = "mod:a";
+            expectedPath.m_nodes = {{module_{"mod"}, {container_("a")}}};
         }
 
-        SECTION("b/b2")
+        SECTION("mod:b/b2")
         {
-            input = "b/b2";
-            expectedPath.m_nodes = {container_("b"), container_("b2")};
+            input = "mod:b/b2";
+            expectedPath.m_nodes = {{{module_{"mod"}}, container_("b")}, {container_("b2")}};
         }
 
-        SECTION("a/a2/a3")
+        SECTION("mod:a/a2/a3")
         {
-            input = "a/a2/a3";
-            expectedPath.m_nodes = {container_("a"), container_("a2"), container_("a3")};
+            input = "mod:a/a2/a3";
+            expectedPath.m_nodes = {{{module_{"mod"}}, container_("a")}, {container_("a2")}, {container_("a3")}};
         }
 
-        SECTION("list[quote=lol]/contInList")
+        SECTION("mod:list[quote=lol]/contInList")
         {
-            input = "list[quote=lol]/contInList";
+            input = "mod:list[quote=lol]/contInList";
             auto keys = std::map<std::string, std::string>{
                 {"quote", "lol"}};
-            expectedPath.m_nodes = {listElement_("list", keys), container_("contInList")};
+            expectedPath.m_nodes = {{{module_{"mod"}}, listElement_("list", keys)}, {container_("contInList")}};
         }
 
         create_ expectedCreate;