Change DatastoreAccess::Tree typedef

Before this, the order of items we get in DatastoreAccess::getItems
wasn't preserved. Because (leaf)lists can be ordered, we need to
preserver the order.

Change-Id: Ie4914025b7d868fd9cbbea5e4f1498115030d126
diff --git a/src/datastore_access.hpp b/src/datastore_access.hpp
index f9ea901..287ba94 100644
--- a/src/datastore_access.hpp
+++ b/src/datastore_access.hpp
@@ -39,7 +39,7 @@
 
 class DatastoreAccess {
 public:
-    using Tree = std::map<std::string, leaf_data_>;
+    using Tree = std::vector<std::pair<std::string, leaf_data_>>;
     virtual ~DatastoreAccess() = 0;
     virtual Tree getItems(const std::string& path) = 0;
     virtual void setLeaf(const std::string& path, leaf_data_ value) = 0;
diff --git a/src/netconf_access.cpp b/src/netconf_access.cpp
index 6fd3f69..5e2e52a 100644
--- a/src/netconf_access.cpp
+++ b/src/netconf_access.cpp
@@ -5,6 +5,7 @@
  *
 */
 
+#include <boost/algorithm/string/predicate.hpp>
 #include <libyang/Libyang.hpp>
 #include <libyang/Tree_Data.hpp>
 #include "libyang_utils.hpp"
@@ -32,21 +33,16 @@
                 // The fact that the container is included in the data tree
                 // means that it is present and I don't need to check any
                 // value.
-                res.emplace(stripXPathPrefix(it->path()), special_{SpecialValue::PresenceContainer});
+                res.emplace_back(stripXPathPrefix(it->path()), special_{SpecialValue::PresenceContainer});
             }
         }
         if (it->schema()->nodetype() == LYS_LIST) {
-            res.emplace(stripXPathPrefix(it->path()), special_{SpecialValue::List});
+            res.push_back({stripXPathPrefix(it->path()), special_{SpecialValue::List}});
         }
         if (it->schema()->nodetype() == LYS_LEAF || it->schema()->nodetype() == LYS_LEAFLIST) {
-            using namespace std::string_literals;
             libyang::Data_Node_Leaf_List leaf(it);
             auto value = leafValueFromValue(leaf.value(), leaf.leaf_type()->base());
-            if (it->schema()->nodetype() == LYS_LEAFLIST) {
-                std::string strippedLeafListValue = stripLeafListValueFromPath(it->path());
-                res.emplace(stripXPathPrefix(strippedLeafListValue), special_{SpecialValue::LeafList});
-            }
-            res.emplace(stripXPathPrefix(it->path()), value);
+            res.emplace_back(stripXPathPrefix(it->path()), value);
         }
     }
 }
@@ -61,8 +57,18 @@
     auto config = m_session->get((path != "/") ? std::optional{path} : std::nullopt);
 
     if (config) {
-        for (auto it : config->tree_for()) {
-            fillMap(res, it->tree_dfs());
+        auto siblings = config->tree_for();
+        for (auto it = siblings.begin(); it < siblings.end(); it++) {
+            if ((*it)->schema()->nodetype() == LYS_LEAFLIST) {
+                auto leafListPath = stripLeafListValueFromPath((*it)->path());
+                res.emplace_back(leafListPath, special_{SpecialValue::LeafList});
+                while (it != siblings.end() && boost::starts_with((*it)->path(), leafListPath)) {
+                    fillMap(res, (*it)->tree_dfs());
+                    it++;
+                }
+            } else {
+                fillMap(res, (*it)->tree_dfs());
+            }
         }
     }
     return res;
diff --git a/src/sysrepo_access.cpp b/src/sysrepo_access.cpp
index 4aaa156..3af5f79 100644
--- a/src/sysrepo_access.cpp
+++ b/src/sysrepo_access.cpp
@@ -197,10 +197,15 @@
         for (unsigned int i = 0; i < items->val_cnt(); i++) {
             auto value = leafValueFromVal(items->val(i));
             if (m_schema->isLeafList(items->val(i)->xpath())) {
-                res.emplace(items->val(i)->xpath(), special_{SpecialValue::LeafList});
-                res.emplace(items->val(i)->xpath() + "[.="s + escapeListKeyString(leafDataToString(value)) + "]", value);
+                res.push_back({items->val(i)->xpath(), special_{SpecialValue::LeafList}});
+                std::string leafListPath = items->val(i)->xpath();
+                while (i < items->val_cnt() && leafListPath == items->val(i)->xpath()) {
+                    auto leafListValue = leafDataToString(leafValueFromVal(items->val(i)));
+                    res.push_back({items->val(i)->xpath() + "[.="s + escapeListKeyString(leafListValue) + "]", leafListValue});
+                    i++;
+                }
             } else {
-                res.emplace(items->val(i)->xpath(), value);
+                res.push_back({items->val(i)->xpath(), value});
             }
         }
     };
@@ -316,7 +321,7 @@
     Tree res;
     for (size_t i = 0; i < output->val_cnt(); ++i) {
         const auto& v = output->val(i);
-        res.emplace(std::string(v->xpath()).substr(joinPaths(path, "/").size()), leafValueFromVal(v));
+        res.push_back({std::string(v->xpath()).substr(joinPaths(path, "/").size()), leafValueFromVal(v)});
     }
     return res;
 }
diff --git a/tests/datastore_access.cpp b/tests/datastore_access.cpp
index e11eec5..07320c9 100644
--- a/tests/datastore_access.cpp
+++ b/tests/datastore_access.cpp
@@ -202,7 +202,7 @@
             datastore.commitChanges();
         }
 
-        DatastoreAccess::Tree expected{{"/example-schema:down", bool{false}},
+        DatastoreAccess::Tree expected{
         // Sysrepo always returns containers when getting values, but
         // libnetconf does not. This is fine by the YANG standard:
         // https://tools.ietf.org/html/rfc7950#section-7.5.7 Furthermore,
@@ -212,10 +212,11 @@
         // because it'll use the same data structure as libnetconf, so the
         // results will be consistent.
 #ifdef sysrepo_BACKEND
-                                                   {"/example-schema:lol", special_{SpecialValue::Container}},
                                                    {"/example-schema:inventory", special_{SpecialValue::Container}},
+                                                   {"/example-schema:lol", special_{SpecialValue::Container}},
 #endif
-                                                   {"/example-schema:up", bool{true}}};
+                                                   {"/example-schema:up", bool{true}},
+                                                   {"/example-schema:down", bool{false}}};
         REQUIRE(datastore.getItems("/example-schema:*") == expected);
     }
 
diff --git a/tests/python_netconfaccess.py b/tests/python_netconfaccess.py
index a4f6c94..b04eb24 100644
--- a/tests/python_netconfaccess.py
+++ b/tests/python_netconfaccess.py
@@ -2,7 +2,7 @@
 
 c = nc.NetconfAccess(socketPath = "@NETOPEER_SOCKET_PATH@")
 data = c.getItems("/ietf-netconf-server:netconf-server")
-for (k, v) in data.items():
+for (k, v) in data:
     print(f"{k}: {type(v)} {v}", flush=True)
 
 if len(data) == 0:
@@ -14,9 +14,10 @@
     c.setLeaf(hello_timeout_xp, EXPECTED)
     c.commitChanges()
     data = c.getItems(hello_timeout_xp)
-    if (data[hello_timeout_xp] != EXPECTED):
+    (_, value) = next(filter(lambda keyValue: keyValue[0] == hello_timeout_xp, data))
+    if value != EXPECTED:
         if isinstance(EXPECTED, str):
-            if str(data[hello_timeout_xp]) != EXPECTED:
+            if str(value) != EXPECTED:
                 print(f"ERROR: hello-timeout not updated (via string) to {EXPECTED}")
                 exit(1)
         else: