Merge "Skip rpc nodes in YangSchema::childNodes"
diff --git a/src/ast_handlers.hpp b/src/ast_handlers.hpp
index c046040..04e890a 100644
--- a/src/ast_handlers.hpp
+++ b/src/ast_handlers.hpp
@@ -652,7 +652,7 @@
parserContext.m_suggestions.clear();
boost::mpl::for_each<CommandTypes, boost::type<boost::mpl::_>>([&parserContext](auto cmd) {
- parserContext.m_suggestions.insert({commandNamesVisitor()(cmd)});
+ parserContext.m_suggestions.insert({commandNamesVisitor()(cmd), " "});
});
}
};
diff --git a/src/parser.cpp b/src/parser.cpp
index 85793a0..91b00a2 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -69,8 +69,8 @@
auto filtered = filterByPrefix(ctx.m_suggestions, std::string(completionIterator, line.end()));
if (filtered.size() == 1) {
- auto suffix = filtered.begin()->m_whenToAdd == Completion::WhenToAdd::IfFullMatch
- && filtered.begin()->m_value == std::string{completionIterator, line.end()}
+ auto suffix = filtered.begin()->m_whenToAdd == Completion::WhenToAdd::Always
+ || filtered.begin()->m_value == std::string{completionIterator, line.end()}
? filtered.begin()->m_suffix
: "";
return {{filtered.begin()->m_value + suffix}, completionContext};
diff --git a/src/schema.cpp b/src/schema.cpp
index c390e31..2cfcbf2 100644
--- a/src/schema.cpp
+++ b/src/schema.cpp
@@ -9,3 +9,40 @@
#include "schema.hpp"
Schema::~Schema() = default;
+
+bool Schema::isList(const schemaPath_& location, const ModuleNodePair& node) const
+{
+ try {
+ return nodeType(location, node) == yang::NodeTypes::List;
+ } catch (InvalidNodeException&) {
+ return false;
+ }
+}
+
+bool Schema::isPresenceContainer(const schemaPath_& location, const ModuleNodePair& node) const
+{
+ try {
+ return nodeType(location, node) == yang::NodeTypes::PresenceContainer;
+ } catch (InvalidNodeException&) {
+ return false;
+ }
+}
+
+bool Schema::isContainer(const schemaPath_& location, const ModuleNodePair& node) const
+{
+ try {
+ auto type = nodeType(location, node);
+ return type == yang::NodeTypes::Container || type == yang::NodeTypes::PresenceContainer;
+ } catch (InvalidNodeException&) {
+ return false;
+ }
+}
+
+bool Schema::isLeaf(const schemaPath_& location, const ModuleNodePair& node) const
+{
+ try {
+ return nodeType(location, node) == yang::NodeTypes::Leaf;
+ } catch (InvalidNodeException&) {
+ return false;
+ }
+}
diff --git a/src/schema.hpp b/src/schema.hpp
index 8b7031a..a85961b 100644
--- a/src/schema.hpp
+++ b/src/schema.hpp
@@ -35,6 +35,13 @@
IdentityRef,
LeafRef,
};
+
+enum class NodeTypes {
+ Container,
+ PresenceContainer,
+ List,
+ Leaf
+};
}
enum class Recursion {
@@ -43,10 +50,7 @@
};
-class InvalidNodeException : public std::invalid_argument {
-public:
- using std::invalid_argument::invalid_argument;
- ~InvalidNodeException() override;
+class InvalidNodeException {
};
/*! \class Schema
@@ -59,11 +63,13 @@
public:
virtual ~Schema();
- virtual bool isContainer(const schemaPath_& location, const ModuleNodePair& node) const = 0;
- virtual bool isLeaf(const schemaPath_& location, const ModuleNodePair& node) const = 0;
+ bool isContainer(const schemaPath_& location, const ModuleNodePair& node) const;
+ bool isLeaf(const schemaPath_& location, const ModuleNodePair& node) const;
+ bool isList(const schemaPath_& location, const ModuleNodePair& node) const;
+ bool isPresenceContainer(const schemaPath_& location, const ModuleNodePair& node) const;
+ virtual yang::NodeTypes nodeType(const std::string& path) const = 0;
+ virtual yang::NodeTypes nodeType(const schemaPath_& location, const ModuleNodePair& node) const = 0;
virtual bool isModule(const std::string& name) const = 0;
- virtual bool isList(const schemaPath_& location, const ModuleNodePair& node) const = 0;
- virtual bool isPresenceContainer(const schemaPath_& location, const ModuleNodePair& node) const = 0;
virtual bool leafEnumHasValue(const schemaPath_& location, const ModuleNodePair& node, const std::string& value) const = 0;
virtual bool leafIdentityIsValid(const schemaPath_& location, const ModuleNodePair& node, const ModuleValuePair& value) const = 0;
virtual bool listHasKey(const schemaPath_& location, const ModuleNodePair& node, const std::string& key) const = 0;
diff --git a/src/static_schema.cpp b/src/static_schema.cpp
index 47e0884..d2287dc 100644
--- a/src/static_schema.cpp
+++ b/src/static_schema.cpp
@@ -10,8 +10,6 @@
#include "static_schema.hpp"
#include "utils.hpp"
-InvalidNodeException::~InvalidNodeException() = default;
-
StaticSchema::StaticSchema()
{
m_nodes.emplace("/", std::unordered_map<std::string, NodeType>());
@@ -36,16 +34,6 @@
return m_modules.find(name) != m_modules.end();
}
-bool StaticSchema::isContainer(const schemaPath_& location, const ModuleNodePair& node) const
-{
- std::string locationString = pathToSchemaString(location, Prefixes::Always);
- auto fullName = fullNodeName(location, node);
- if (!nodeExists(locationString, fullName))
- return false;
-
- return children(locationString).at(fullName).type() == typeid(yang::container);
-}
-
void StaticSchema::addContainer(const std::string& location, const std::string& name, yang::ContainerTraits isPresence)
{
m_nodes.at(location).emplace(name, yang::container{isPresence});
@@ -75,19 +63,6 @@
return list.m_keys;
}
-bool StaticSchema::isList(const schemaPath_& location, const ModuleNodePair& node) const
-{
- std::string locationString = pathToSchemaString(location, Prefixes::Always);
- auto fullName = fullNodeName(location, node);
- if (!nodeExists(locationString, fullName))
- return false;
- const auto& child = children(locationString).at(fullName);
- if (child.type() != typeid(yang::list))
- return false;
-
- return true;
-}
-
void StaticSchema::addList(const std::string& location, const std::string& name, const std::set<std::string>& keys)
{
m_nodes.at(location).emplace(name, yang::list{keys});
@@ -96,14 +71,6 @@
m_nodes.emplace(key, std::unordered_map<std::string, NodeType>());
}
-bool StaticSchema::isPresenceContainer(const schemaPath_& location, const ModuleNodePair& node) const
-{
- if (!isContainer(location, node))
- return false;
- std::string locationString = pathToSchemaString(location, Prefixes::Always);
- return boost::get<yang::container>(children(locationString).at(fullNodeName(location, node))).m_presence == yang::ContainerTraits::Presence;
-}
-
void StaticSchema::addLeaf(const std::string& location, const std::string& name, const yang::LeafDataTypes& type)
{
m_nodes.at(location).emplace(name, yang::leaf{type, {}, {}, {}});
@@ -205,16 +172,6 @@
return std::any_of(identities.begin(), identities.end(), [toFind = identModule + ":" + value.second](const auto& x) { return x == toFind; });
}
-bool StaticSchema::isLeaf(const schemaPath_& location, const ModuleNodePair& node) const
-{
- std::string locationString = pathToSchemaString(location, Prefixes::Always);
- auto fullName = fullNodeName(location, node);
- if (!nodeExists(locationString, fullName))
- return false;
-
- return children(locationString).at(fullName).type() == typeid(yang::leaf);
-}
-
std::string lastNodeOfSchemaPath(const std::string& path)
{
std::string res = path;
@@ -284,3 +241,37 @@
}
return res;
}
+
+yang::NodeTypes StaticSchema::nodeType(const schemaPath_& location, const ModuleNodePair& node) const
+{
+ std::string locationString = pathToSchemaString(location, Prefixes::Always);
+ auto fullName = fullNodeName(location, node);
+ try {
+ auto targetNode = children(locationString).at(fullName);
+
+ if (targetNode.type() == typeid(yang::container)) {
+ if (boost::get<yang::container>(targetNode).m_presence == yang::ContainerTraits::Presence) {
+ return yang::NodeTypes::PresenceContainer;
+ }
+ return yang::NodeTypes::Container;
+ }
+
+ if (targetNode.type() == typeid(yang::list)) {
+ return yang::NodeTypes::List;
+ }
+
+ if (targetNode.type() == typeid(yang::leaf)) {
+ return yang::NodeTypes::Leaf;
+ }
+
+ throw std::runtime_error{"YangSchema::nodeType: unsupported type"};
+
+ } catch (std::out_of_range&) {
+ throw InvalidNodeException();
+ }
+}
+
+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 742c53d..c2623a5 100644
--- a/src/static_schema.hpp
+++ b/src/static_schema.hpp
@@ -48,11 +48,9 @@
public:
StaticSchema();
- bool isContainer(const schemaPath_& location, const ModuleNodePair& node) const override;
+ yang::NodeTypes nodeType(const std::string& path) const override;
+ yang::NodeTypes nodeType(const schemaPath_& location, const ModuleNodePair& node) const override;
bool isModule(const std::string& name) const override;
- bool isLeaf(const schemaPath_& location, const ModuleNodePair& node) const override;
- bool isList(const schemaPath_& location, const ModuleNodePair& node) const override;
- bool isPresenceContainer(const schemaPath_& location, const ModuleNodePair& node) const override;
bool leafEnumHasValue(const schemaPath_& location, const ModuleNodePair& node, const std::string& value) const override;
bool leafIdentityIsValid(const schemaPath_& location, const ModuleNodePair& node, const ModuleValuePair& value) const override;
bool listHasKey(const schemaPath_& location, const ModuleNodePair& node, const std::string& key) const override;
diff --git a/src/yang_schema.cpp b/src/yang_schema.cpp
index 4627bd2..88f0154 100644
--- a/src/yang_schema.cpp
+++ b/src/yang_schema.cpp
@@ -93,31 +93,6 @@
return set.find(name) != set.end();
}
-bool YangSchema::isContainer(const schemaPath_& location, const ModuleNodePair& node) const
-{
- const auto schemaNode = getSchemaNode(location, node);
- return schemaNode && schemaNode->nodetype() == LYS_CONTAINER;
-}
-
-bool YangSchema::isLeaf(const schemaPath_& location, const ModuleNodePair& node) const
-{
- const auto schemaNode = getSchemaNode(location, node);
- return schemaNode && schemaNode->nodetype() == LYS_LEAF;
-}
-
-bool YangSchema::isList(const schemaPath_& location, const ModuleNodePair& node) const
-{
- const auto schemaNode = getSchemaNode(location, node);
- return schemaNode && schemaNode->nodetype() == LYS_LIST;
-}
-
-bool YangSchema::isPresenceContainer(const schemaPath_& location, const ModuleNodePair& node) const
-{
- if (!isContainer(location, node))
- return false;
- return libyang::Schema_Node_Container(getSchemaNode(location, node)).presence();
-}
-
bool YangSchema::leafEnumHasValue(const schemaPath_& location, const ModuleNodePair& node, const std::string& value) const
{
auto enums = enumValues(location, node);
@@ -417,3 +392,32 @@
{
return m_context->get_module(name.c_str(), nullptr, 0);
}
+
+namespace {
+yang::NodeTypes impl_nodeType(const libyang::S_Schema_Node& node)
+{
+ if (!node) {
+ throw InvalidNodeException();
+ }
+ switch (node->nodetype()) {
+ case LYS_CONTAINER:
+ return libyang::Schema_Node_Container{node}.presence() ? yang::NodeTypes::PresenceContainer : yang::NodeTypes::Container;
+ case LYS_LEAF:
+ return yang::NodeTypes::Leaf;
+ case LYS_LIST:
+ return yang::NodeTypes::List;
+ default:
+ throw InvalidNodeException(); // FIXME: Implement all types.
+ }
+}
+}
+
+yang::NodeTypes YangSchema::nodeType(const schemaPath_& location, const ModuleNodePair& node) const
+{
+ return impl_nodeType(getSchemaNode(location, node));
+}
+
+yang::NodeTypes YangSchema::nodeType(const std::string& path) const
+{
+ return impl_nodeType(getSchemaNode(path));
+}
diff --git a/src/yang_schema.hpp b/src/yang_schema.hpp
index 1ff5144..ea204e2 100644
--- a/src/yang_schema.hpp
+++ b/src/yang_schema.hpp
@@ -30,11 +30,9 @@
YangSchema(std::shared_ptr<libyang::Context> lyCtx);
~YangSchema() override;
- bool isContainer(const schemaPath_& location, const ModuleNodePair& node) const override;
- bool isLeaf(const schemaPath_& location, const ModuleNodePair& node) const override;
+ yang::NodeTypes nodeType(const std::string& path) const override;
+ yang::NodeTypes nodeType(const schemaPath_& location, const ModuleNodePair& node) const override;
bool isModule(const std::string& name) const override;
- bool isList(const schemaPath_& location, const ModuleNodePair& node) const override;
- bool isPresenceContainer(const schemaPath_& location, const ModuleNodePair& node) const override;
bool leafEnumHasValue(const schemaPath_& location, const ModuleNodePair& node, const std::string& value) const override;
bool leafIdentityIsValid(const schemaPath_& location, const ModuleNodePair& node, const ModuleValuePair& value) const override;
bool listHasKey(const schemaPath_& location, const ModuleNodePair& node, const std::string& key) const override;
diff --git a/tests/command_completion.cpp b/tests/command_completion.cpp
index 9ab146e..1d44646 100644
--- a/tests/command_completion.cpp
+++ b/tests/command_completion.cpp
@@ -57,15 +57,14 @@
SECTION("cd")
{
input = "cd";
- // TODO: depending on how Readline works, this will have to be changed to include a space
- expectedCompletions = {"cd"};
+ expectedCompletions = {"cd "};
expectedContextLength = 2;
}
SECTION("create")
{
input = "create";
- expectedCompletions = {"create"};
+ expectedCompletions = {"create "};
expectedContextLength = 6;
}
diff --git a/tests/yang.cpp b/tests/yang.cpp
index a90cb8e..9af8b47 100644
--- a/tests/yang.cpp
+++ b/tests/yang.cpp
@@ -751,6 +751,37 @@
REQUIRE(ys.childNodes(path, Recursion::NonRecursive) == set);
}
+ 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")