Add node-info getters to Schema
Change-Id: Iffea96cdcf20763286db19b0ee2b92dbf7c69b6c
diff --git a/src/schema.hpp b/src/schema.hpp
index a85961b..e4636cf 100644
--- a/src/schema.hpp
+++ b/src/schema.hpp
@@ -76,6 +76,8 @@
virtual const std::set<std::string> listKeys(const schemaPath_& location, const ModuleNodePair& node) const = 0;
virtual yang::LeafDataTypes leafType(const schemaPath_& location, const ModuleNodePair& node) const = 0;
virtual yang::LeafDataTypes leafrefBase(const schemaPath_& location, const ModuleNodePair& node) const = 0;
+ virtual std::optional<std::string> description(const std::string& location) const = 0;
+ virtual std::optional<std::string> units(const std::string& location) const = 0;
virtual const std::set<std::string> validIdentities(const schemaPath_& location, const ModuleNodePair& node, const Prefixes prefixes) const = 0;
virtual const std::set<std::string> enumValues(const schemaPath_& location, const ModuleNodePair& node) const = 0;
diff --git a/src/static_schema.cpp b/src/static_schema.cpp
index d2287dc..9b4f00b 100644
--- a/src/static_schema.cpp
+++ b/src/static_schema.cpp
@@ -271,6 +271,16 @@
}
}
+std::optional<std::string> StaticSchema::description([[maybe_unused]] const std::string& path) const
+{
+ throw std::runtime_error{"StaticSchema::description not implemented"};
+}
+
+std::optional<std::string> StaticSchema::units([[maybe_unused]] const std::string& path) const
+{
+ throw std::runtime_error{"StaticSchema::units not implemented"};
+}
+
yang::NodeTypes StaticSchema::nodeType([[maybe_unused]] const std::string& path) const
{
throw std::runtime_error{"Internal error: StaticSchema::nodeType(std::string) not implemented. The tests should not have called this overload."};
diff --git a/src/static_schema.hpp b/src/static_schema.hpp
index c2623a5..a63f92c 100644
--- a/src/static_schema.hpp
+++ b/src/static_schema.hpp
@@ -61,6 +61,8 @@
const std::set<std::string> validIdentities(const schemaPath_& location, const ModuleNodePair& node, const Prefixes prefixes) const override;
std::set<std::string> childNodes(const schemaPath_& path, const Recursion) const override;
std::set<std::string> moduleNodes(const module_& module, const Recursion recursion) const override;
+ std::optional<std::string> description(const std::string& path) const override;
+ std::optional<std::string> units(const std::string& path) const override;
void addContainer(const std::string& location, const std::string& name, yang::ContainerTraits isPresence = yang::ContainerTraits::None);
void addLeaf(const std::string& location, const std::string& name, const yang::LeafDataTypes& type);
diff --git a/src/yang_schema.cpp b/src/yang_schema.cpp
index 10565d3..d915eef 100644
--- a/src/yang_schema.cpp
+++ b/src/yang_schema.cpp
@@ -416,3 +416,34 @@
{
return impl_nodeType(getSchemaNode(path));
}
+
+std::optional<std::string> YangSchema::description(const std::string& path) const
+{
+ auto node = getSchemaNode(path.c_str());
+ return node->dsc() ? std::optional{node->dsc()} : std::nullopt;
+}
+
+std::optional<std::string> YangSchema::units(const std::string& path) const
+{
+ auto node = getSchemaNode(path.c_str());
+ if (node->nodetype() != LYS_LEAF) {
+ return std::nullopt;
+ }
+ libyang::Schema_Node_Leaf leaf{node};
+ auto units = leaf.units();
+
+ // A leaf can specify units as part of its definition.
+ if (units) {
+ return units;
+ }
+
+ // A typedef (or its parent typedefs) can specify units too. We'll use the first `units` we find.
+ for (auto parentTypedef = leaf.type()->der(); parentTypedef; parentTypedef = parentTypedef->type()->der()) {
+ units = parentTypedef->units();
+ if (units) {
+ return units;
+ }
+ }
+
+ return std::nullopt;
+}
diff --git a/src/yang_schema.hpp b/src/yang_schema.hpp
index ea204e2..8471bea 100644
--- a/src/yang_schema.hpp
+++ b/src/yang_schema.hpp
@@ -43,6 +43,8 @@
const std::set<std::string> enumValues(const schemaPath_& location, const ModuleNodePair& node) const override;
std::set<std::string> childNodes(const schemaPath_& path, const Recursion recursion) const override;
std::set<std::string> moduleNodes(const module_& module, const Recursion recursion) const override;
+ std::optional<std::string> description(const std::string& path) const override;
+ std::optional<std::string> units(const std::string& path) const override;
void registerModuleCallback(const std::function<std::string(const char*, const char*, const char*, const char*)>& clb);
diff --git a/tests/datastore_access.cpp b/tests/datastore_access.cpp
index ba52b9c..311b395 100644
--- a/tests/datastore_access.cpp
+++ b/tests/datastore_access.cpp
@@ -27,25 +27,6 @@
IMPLEMENT_MOCK3(write);
};
-namespace std {
-std::ostream& operator<<(std::ostream& s, const std::optional<std::string>& opt)
-{
- s << (opt ? *opt : "std::nullopt");
- return s;
-}
-
-std::ostream& operator<<(std::ostream& s, const DatastoreAccess::Tree& map)
-{
- s << std::endl
- << "{";
- for (const auto& it : map) {
- s << "{\"" << it.first << "\", " << leafDataToString(it.second) << "}" << std::endl;
- }
- s << "}" << std::endl;
- return s;
-}
-}
-
TEST_CASE("setting/getting values")
{
trompeloeil::sequence seq1;
diff --git a/tests/pretty_printers.hpp b/tests/pretty_printers.hpp
index 42be33e..86bd20d 100644
--- a/tests/pretty_printers.hpp
+++ b/tests/pretty_printers.hpp
@@ -7,6 +7,7 @@
#include <experimental/iterator>
#include "parser.hpp"
+#include "utils.hpp"
namespace std {
std::ostream& operator<<(std::ostream& s, const Completions& completion)
{
@@ -18,4 +19,21 @@
s << "}" << std::endl;
return s;
}
+
+std::ostream& operator<<(std::ostream& s, const std::optional<std::string>& opt)
+{
+ s << (opt ? *opt : "std::nullopt");
+ return s;
+}
+
+std::ostream& operator<<(std::ostream& s, const DatastoreAccess::Tree& map)
+{
+ s << std::endl
+ << "{";
+ for (const auto& it : map) {
+ s << "{\"" << it.first << "\", " << leafDataToString(it.second) << "}" << std::endl;
+ }
+ s << "}" << std::endl;
+ return s;
+}
}
diff --git a/tests/yang.cpp b/tests/yang.cpp
index 017107c..5f2f0c3 100644
--- a/tests/yang.cpp
+++ b/tests/yang.cpp
@@ -7,6 +7,7 @@
*/
#include <experimental/iterator>
+#include "pretty_printers.hpp"
#include "trompeloeil_doctest.hpp"
#include "yang_schema.hpp"
@@ -114,6 +115,7 @@
}
leaf leafInt32 {
+ description "A 32-bit integer leaf.";
type int32;
}
@@ -262,6 +264,32 @@
}
}
+ leaf length {
+ type int32;
+ units "m";
+ }
+
+ leaf wavelength {
+ type decimal64 {
+ fraction-digits 10;
+ }
+ units "nm";
+ }
+
+ typedef seconds {
+ type int32;
+ units "s";
+ }
+
+ leaf duration {
+ type seconds;
+ }
+
+ leaf another-duration {
+ type seconds;
+ units "vt";
+ }
+
})";
namespace std {
@@ -726,7 +754,9 @@
"example-schema:carry", "example-schema:zero", "example-schema:direction",
"example-schema:interrupt",
"example-schema:ethernet", "example-schema:loopback",
- "example-schema:pizzaSize"};
+ "example-schema:pizzaSize",
+ "example-schema:length", "example-schema:wavelength",
+ "example-schema:duration", "example-schema:another-duration"};
}
SECTION("example-schema:a")
@@ -780,6 +810,90 @@
REQUIRE(ys.nodeType(pathToSchemaString(path, Prefixes::WhenNeeded)) == expected);
}
+
+ SECTION("description")
+ {
+ std::optional<std::string> expected;
+ SECTION("leafInt32")
+ {
+ path.m_nodes.push_back(schemaNode_(module_{"example-schema"}, leaf_("leafInt32")));
+ expected = "A 32-bit integer leaf.";
+ }
+
+ SECTION("leafString")
+ {
+ path.m_nodes.push_back(schemaNode_(module_{"example-schema"}, leaf_("leafString")));
+ }
+
+ REQUIRE(ys.description(pathToSchemaString(path, Prefixes::WhenNeeded)) == expected);
+ }
+
+ SECTION("units")
+ {
+ std::optional<std::string> expected;
+ SECTION("length")
+ {
+ path.m_nodes.push_back(schemaNode_(module_{"example-schema"}, leaf_("length")));
+ expected = "m";
+ }
+
+ SECTION("wavelength")
+ {
+ path.m_nodes.push_back(schemaNode_(module_{"example-schema"}, leaf_("wavelength")));
+ expected = "nm";
+ }
+
+ SECTION("leafInt32")
+ {
+ path.m_nodes.push_back(schemaNode_(module_{"example-schema"}, leaf_("leafInt32")));
+ }
+
+ SECTION("duration")
+ {
+ path.m_nodes.push_back(schemaNode_(module_{"example-schema"}, leaf_("duration")));
+ expected = "s";
+ }
+
+ SECTION("another-duration")
+ {
+ path.m_nodes.push_back(schemaNode_(module_{"example-schema"}, leaf_("another-duration")));
+ expected = "vt";
+ }
+
+ REQUIRE(ys.units(pathToSchemaString(path, Prefixes::WhenNeeded)) == expected);
+ }
+
+ SECTION("nodeType")
+ {
+ yang::NodeTypes expected;
+ SECTION("leafInt32")
+ {
+ path.m_nodes.push_back(schemaNode_(module_{"example-schema"}, leaf_("leafInt32")));
+ expected = yang::NodeTypes::Leaf;
+ }
+
+ SECTION("a")
+ {
+ path.m_nodes.push_back(schemaNode_(module_{"example-schema"}, container_("a")));
+ expected = yang::NodeTypes::Container;
+ }
+
+ SECTION("a/a2/a3")
+ {
+ path.m_nodes.push_back(schemaNode_(module_{"example-schema"}, container_("a")));
+ path.m_nodes.push_back(schemaNode_(container_("a2")));
+ path.m_nodes.push_back(schemaNode_(container_("a3")));
+ expected = yang::NodeTypes::PresenceContainer;
+ }
+
+ SECTION("_list")
+ {
+ path.m_nodes.push_back(schemaNode_(module_{"example-schema"}, list_("_list")));
+ expected = yang::NodeTypes::List;
+ }
+
+ REQUIRE(ys.nodeType(pathToSchemaString(path, Prefixes::WhenNeeded)) == expected);
+ }
}
SECTION("negative")