Add support for leaflist

Change-Id: Idcb529f85240a32e84d82934c81fcf0c3451f94e
diff --git a/tests/datastore_access.cpp b/tests/datastore_access.cpp
index 088fc4b..e11eec5 100644
--- a/tests/datastore_access.cpp
+++ b/tests/datastore_access.cpp
@@ -386,6 +386,36 @@
         REQUIRE(datastore.getItems(xpath) == expected);
     }
 
+    SECTION("leaf list")
+    {
+        DatastoreAccess::Tree expected;
+        REQUIRE_CALL(mock, write("/example-schema:addresses", std::nullopt, "0.0.0.0"s));
+        REQUIRE_CALL(mock, write("/example-schema:addresses", std::nullopt, "127.0.0.1"s));
+        datastore.createLeafListInstance("/example-schema:addresses[.='0.0.0.0']");
+        datastore.createLeafListInstance("/example-schema:addresses[.='127.0.0.1']");
+        datastore.commitChanges();
+        expected = {
+            {"/example-schema:addresses", special_{SpecialValue::LeafList}},
+            {"/example-schema:addresses[.='0.0.0.0']", "0.0.0.0"s},
+            {"/example-schema:addresses[.='127.0.0.1']", "127.0.0.1"s},
+        };
+        REQUIRE(datastore.getItems("/example-schema:addresses") == expected);
+
+        REQUIRE_CALL(mock, write("/example-schema:addresses", "0.0.0.0"s, std::nullopt));
+        datastore.deleteLeafListInstance("/example-schema:addresses[.='0.0.0.0']");
+        datastore.commitChanges();
+        expected = {
+            {"/example-schema:addresses", special_{SpecialValue::LeafList}},
+            {"/example-schema:addresses[.='127.0.0.1']", "127.0.0.1"s},
+        };
+        REQUIRE(datastore.getItems("/example-schema:addresses") == expected);
+
+        REQUIRE_CALL(mock, write("/example-schema:addresses", "127.0.0.1"s, std::nullopt));
+        datastore.deleteLeafListInstance("/example-schema:addresses[.='127.0.0.1']");
+        datastore.commitChanges();
+        expected = {};
+        REQUIRE(datastore.getItems("/example-schema:addresses") == expected);
+    }
 
     SECTION("copying data from startup refreshes the data")
     {
diff --git a/tests/datastoreaccess_mock.hpp b/tests/datastoreaccess_mock.hpp
index 8798973..ac75875 100644
--- a/tests/datastoreaccess_mock.hpp
+++ b/tests/datastoreaccess_mock.hpp
@@ -23,6 +23,8 @@
     IMPLEMENT_MOCK2(setLeaf);
     IMPLEMENT_MOCK1(createPresenceContainer);
     IMPLEMENT_MOCK1(deletePresenceContainer);
+    IMPLEMENT_MOCK1(createLeafListInstance);
+    IMPLEMENT_MOCK1(deleteLeafListInstance);
     IMPLEMENT_MOCK1(createListInstance);
     IMPLEMENT_MOCK1(deleteListInstance);
     IMPLEMENT_MOCK2(executeRpc);
diff --git a/tests/example-schema.yang b/tests/example-schema.yang
index ef9d02d..3f32a87 100644
--- a/tests/example-schema.yang
+++ b/tests/example-schema.yang
@@ -247,4 +247,8 @@
     leaf dummy {
         type empty;
     }
+
+    leaf-list addresses {
+        type string;
+    }
 }
diff --git a/tests/list_manipulation.cpp b/tests/list_manipulation.cpp
index 15f2f04..974d806 100644
--- a/tests/list_manipulation.cpp
+++ b/tests/list_manipulation.cpp
@@ -11,11 +11,13 @@
 
 TEST_CASE("list manipulation")
 {
+    using namespace std::string_literals;
     auto schema = std::make_shared<StaticSchema>();
     schema->addModule("mod");
     schema->addList("/", "mod:list", {"number"});
     schema->addLeaf("/mod:list", "mod:number", yang::Int32{});
     schema->addLeaf("/mod:list", "mod:leafInList", yang::String{});
+    schema->addLeafList("/", "mod:addresses", yang::String{});
     Parser parser(schema);
     std::string input;
     std::ostringstream errorStream;
@@ -31,6 +33,13 @@
             expectedPath.m_nodes.push_back(dataNode_{module_{"mod"}, listElement_("list", keys)});
         }
 
+        SECTION("create mod:addresses['0.0.0.0']")
+        {
+            input = "mod:addresses['0.0.0.0']";
+            expectedPath.m_nodes.push_back(dataNode_{module_{"mod"}, leafListElement_{"addresses", "0.0.0.0"s}});
+        }
+
+
         command_ parsedCreate = parser.parseCommand("create " + input, errorStream);
         command_ parsedDelete = parser.parseCommand("delete " + input, errorStream);
         create_ expectedCreate;
@@ -42,4 +51,17 @@
         REQUIRE(boost::get<create_>(parsedCreate) == expectedCreate);
         REQUIRE(boost::get<delete_>(parsedDelete) == expectedDelete);
     }
+
+    SECTION("retrieving all leaflist instances")
+    {
+        dataPath_ expected;
+        input = "get mod:addresses";
+        expected.m_nodes.push_back(dataNode_{module_{"mod"}, leafList_{"addresses"}});
+
+        get_ expectedGet;
+        expectedGet.m_path = expected;
+        command_ commandGet = parser.parseCommand(input, errorStream);
+        REQUIRE(commandGet.type() == typeid(get_));
+        REQUIRE(boost::get<get_>(commandGet) == expectedGet);
+    }
 }
diff --git a/tests/path_utils.cpp b/tests/path_utils.cpp
index 3a3fb72..6765001 100644
--- a/tests/path_utils.cpp
+++ b/tests/path_utils.cpp
@@ -28,6 +28,21 @@
             path.m_nodes.push_back(dataNode_{module_{"example-schema"}, listElement_{"twoKeyList", {{"first", std::string{"a"}}, {"second", std::string{"b"}}}}});
             expected += "example-schema:twoKeyList[first='a'][second='b']";
         }
+
+        SECTION("example-schema:addresses[.='0.0.0.0']")
+        {
+            SECTION("absolute")
+            {
+                path.m_scope = Scope::Absolute;
+                expected += "/";
+            }
+            SECTION("relative")
+            {
+                path.m_scope = Scope::Relative;
+            }
+            path.m_nodes.push_back(dataNode_{module_{"example-schema"}, leafListElement_{"addresses", std::string{"0.0.0.0"}}});
+            expected += "example-schema:addresses[.='0.0.0.0']";
+        }
         REQUIRE(pathToDataString(path, Prefixes::WhenNeeded) == expected);
     }
 }
diff --git a/tests/yang.cpp b/tests/yang.cpp
index 3d42c5e..71cb69d 100644
--- a/tests/yang.cpp
+++ b/tests/yang.cpp
@@ -419,6 +419,9 @@
         status obsolete;
     }
 
+    leaf-list addresses {
+        type string;
+    }
 })";
 
 namespace std {
@@ -809,6 +812,14 @@
                 }};
             }
 
+            SECTION("addresses")
+            {
+                node.first = "example-schema";
+                node.second = "addresses";
+                type.emplace<yang::String>();
+            }
+
+
             REQUIRE(ys.leafType(path, node) == type);
         }
         SECTION("availableNodes")
@@ -851,6 +862,7 @@
                         {"example-schema"s, "myRpc"},
                         {"example-schema"s, "systemStats"},
                         {"example-schema"s, "dummyLeaf"},
+                        {"example-schema"s, "addresses"},
                         {"example-schema"s, "subLeaf"}};
                 }
 
@@ -894,6 +906,7 @@
                         {"example-schema"s, "activeMappedPort"},
                         {"example-schema"s, "activeNumber"},
                         {"example-schema"s, "activePort"},
+                        {"example-schema"s, "addresses"},
                         {"example-schema"s, "another-duration"},
                         {"example-schema"s, "b"},
                         {"example-schema"s, "carry"},
@@ -943,6 +956,7 @@
                         {boost::none, "/example-schema:_list/contInList"},
                         {boost::none, "/example-schema:_list/number"},
                         {boost::none, "/example-schema:a"},
+                        {boost::none, "/example-schema:addresses"},
                         {boost::none, "/example-schema:a/a2"},
                         {boost::none, "/example-schema:a/a2/a3"},
                         {boost::none, "/example-schema:a/leafa"},
@@ -1129,6 +1143,8 @@
                 expectedType.emplace<yang::Int32>();
                 expectedUnits = "vt";
             }
+            auto nodeType = ys.nodeType(pathToSchemaString(path, Prefixes::WhenNeeded));
+            REQUIRE((nodeType == yang::NodeTypes::Leaf || nodeType == yang::NodeTypes::LeafList));
             REQUIRE(ys.leafType(pathToSchemaString(path, Prefixes::WhenNeeded)) == yang::TypeInfo{expectedType, expectedUnits});
         }