Merge "Update dependencies"
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 53dda3b..779b968 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -317,7 +317,7 @@
set_property(TEST ${TESTNAME} ${TESTNAME}_init ${TESTNAME}_cleanup APPEND PROPERTY ENVIRONMENT
"SYSREPO_REPOSITORY_PATH=${CMAKE_CURRENT_BINARY_DIR}/test_repositories/${TESTNAME}"
"SYSREPO_SHM_PREFIX=netconf-cli_${TESTNAME}"
- "NETOPEER_SOCKET=${CMAKE_CURRENT_BINARY_DIR}/test_netopeer_files/${TESTNAME}.sock"
+ "NETOPEER_SOCKET=test_netopeer_files/${TESTNAME}.sock"
)
endfunction()
@@ -386,7 +386,7 @@
set_property(TEST test_netconf_cli_py test_netconf_cli_py_init test_netconf_cli_py_cleanup APPEND PROPERTY ENVIRONMENT
"SYSREPO_REPOSITORY_PATH=${CMAKE_CURRENT_BINARY_DIR}/test_repositories/test_netconf_cli_py"
"SYSREPO_SHM_PREFIX=netconf-cli_test_netconf_cli_py"
- "NETOPEER_SOCKET=${CMAKE_CURRENT_BINARY_DIR}/test_netopeer_files/test_netconf_cli_py.sock"
+ "NETOPEER_SOCKET=test_netopeer_files/test_netconf_cli_py.sock"
)
set(sanitizer_active OFF)
diff --git a/src/cli.cpp b/src/cli.cpp
index a2c9cdc..271d9a5 100644
--- a/src/cli.cpp
+++ b/src/cli.cpp
@@ -63,7 +63,7 @@
)";
#include "cli-netconf.hpp"
#include "netconf_access.hpp"
-#define PROGRAM_NAME "netconf-access"
+#define PROGRAM_NAME "netconf-cli"
// FIXME: this should be replaced by C++20 std::jthread at some point
struct PoorMansJThread {
~PoorMansJThread()
diff --git a/src/datastore_access.hpp b/src/datastore_access.hpp
index 057c96a..b29e152 100644
--- a/src/datastore_access.hpp
+++ b/src/datastore_access.hpp
@@ -50,8 +50,7 @@
virtual void createItem(const std::string& path) = 0;
virtual void deleteItem(const std::string& path) = 0;
virtual void moveItem(const std::string& path, std::variant<yang::move::Absolute, yang::move::Relative> move) = 0;
- virtual Tree executeRpc(const std::string& path, const Tree& input) = 0;
- virtual Tree executeAction(const std::string& path, const Tree& input) = 0;
+ virtual Tree execute(const std::string& path, const Tree& input) = 0;
virtual std::shared_ptr<Schema> schema() = 0;
diff --git a/src/grammars.hpp b/src/grammars.hpp
index 02da179..7cc8de6 100644
--- a/src/grammars.hpp
+++ b/src/grammars.hpp
@@ -137,7 +137,7 @@
copy_::name > space_separator > copy_args;
auto const describe_def =
- describe_::name >> space_separator > (dataPathListEnd | anyPath);
+ describe_::name >> space_separator > anyPath;
struct mode_table : x3::symbols<MoveMode> {
mode_table()
diff --git a/src/interpreter.cpp b/src/interpreter.cpp
index f1682bf..9046b64 100644
--- a/src/interpreter.cpp
+++ b/src/interpreter.cpp
@@ -127,6 +127,7 @@
std::string Interpreter::buildTypeInfo(const std::string& path) const
{
std::ostringstream ss;
+ std::string typeDescription;
switch (m_datastore.schema()->nodeType(path)) {
case yang::NodeTypes::Container:
ss << "container";
@@ -156,6 +157,10 @@
ss << " [" + *leafType.m_units + "]";
}
+ if (leafType.m_description) {
+ typeDescription = "\nType description: " + *leafType.m_description;
+ }
+
if (m_datastore.schema()->leafIsKey(path)) {
ss << " (key)";
}
@@ -184,24 +189,29 @@
}
if (!m_datastore.schema()->isConfig(path)) {
- ss << " (ro)";
+ ss << " (ro)\n";
}
- return ss.str();
-}
-
-void Interpreter::operator()(const describe_& describe) const
-{
- auto path = pathToString(toCanonicalPath(describe.m_path));
auto status = m_datastore.schema()->status(path);
auto statusStr = status == yang::Status::Deprecated ? " (deprecated)" :
status == yang::Status::Obsolete ? " (obsolete)" :
"";
- std::cout << path << ": " << buildTypeInfo(path) << statusStr << std::endl;
+ ss << statusStr;
+
if (auto description = m_datastore.schema()->description(path)) {
- std::cout << std::endl << *description << std::endl;
+ ss << std::endl << *description << std::endl;
}
+
+ ss << typeDescription;
+ return ss.str();
+}
+
+void Interpreter::operator()(const describe_& describe) const
+{
+ auto fullPath = pathToString(toCanonicalPath(describe.m_path));
+
+ std::cout << pathToString(describe.m_path) << ": " << buildTypeInfo(fullPath) << std::endl;
}
void Interpreter::operator()(const move_& move) const
@@ -216,11 +226,7 @@
void Interpreter::operator()(const prepare_& prepare) const
{
- if (std::holds_alternative<rpcNode_>(prepare.m_path.m_nodes.back().m_suffix)) {
- m_datastore.initiateRpc(pathToString(toCanonicalPath(prepare.m_path)));
- } else {
- m_datastore.initiateAction(pathToString(toCanonicalPath(prepare.m_path)));
- }
+ m_datastore.initiate(pathToString(toCanonicalPath(prepare.m_path)));
m_parser.changeNode(prepare.m_path);
}
diff --git a/src/leaf_data.hpp b/src/leaf_data.hpp
index 7bab723..df0f9b3 100644
--- a/src/leaf_data.hpp
+++ b/src/leaf_data.hpp
@@ -162,6 +162,7 @@
parser.add(bit, bit);
parserContext.m_suggestions.insert(Completion{bit});
}
+ parserContext.m_completionIterator = first;
std::vector<std::string> bitsRes;
diff --git a/src/leaf_data_type.cpp b/src/leaf_data_type.cpp
index fe6fe04..f97e382 100644
--- a/src/leaf_data_type.cpp
+++ b/src/leaf_data_type.cpp
@@ -10,11 +10,12 @@
namespace yang {
bool TypeInfo::operator==(const TypeInfo& other) const
{
- return this->m_type == other.m_type && this->m_units == other.m_units;
+ return std::tie(this->m_type, this->m_units, this->m_description) == std::tie(other.m_type, other.m_units, other.m_description);
}
-TypeInfo::TypeInfo(const yang::LeafDataType& type, const std::optional<std::string> units)
+TypeInfo::TypeInfo(const yang::LeafDataType& type, const std::optional<std::string> units, const std::optional<std::string> description)
: m_type(type)
, m_units(units)
+ , m_description(description)
{
}
Enum::Enum(std::set<enum_>&& values)
diff --git a/src/leaf_data_type.hpp b/src/leaf_data_type.hpp
index 98cb12e..35a2961 100644
--- a/src/leaf_data_type.hpp
+++ b/src/leaf_data_type.hpp
@@ -105,9 +105,12 @@
std::vector<TypeInfo> m_unionTypes;
};
struct TypeInfo {
- TypeInfo(const yang::LeafDataType& type, const std::optional<std::string> units = std::nullopt);
+ TypeInfo(const yang::LeafDataType& type,
+ const std::optional<std::string> units = std::nullopt,
+ const std::optional<std::string> description = std::nullopt);
bool operator==(const TypeInfo& other) const;
yang::LeafDataType m_type;
std::optional<std::string> m_units;
+ std::optional<std::string> m_description;
};
}
diff --git a/src/netconf_access.cpp b/src/netconf_access.cpp
index 1e56659..4ed29ae 100644
--- a/src/netconf_access.cpp
+++ b/src/netconf_access.cpp
@@ -132,7 +132,7 @@
m_session->discard();
}
-DatastoreAccess::Tree NetconfAccess::impl_execute(const std::string& path, const Tree& input)
+DatastoreAccess::Tree NetconfAccess::execute(const std::string& path, const Tree& input)
{
auto root = m_schema->dataNodeFromPath(path);
for (const auto& [k, v] : input) {
@@ -149,16 +149,6 @@
return res;
}
-DatastoreAccess::Tree NetconfAccess::executeRpc(const std::string& path, const Tree& input)
-{
- return impl_execute(path, input);
-}
-
-DatastoreAccess::Tree NetconfAccess::executeAction(const std::string& path, const Tree& input)
-{
- return impl_execute(path, input);
-}
-
NC_DATASTORE toNcDatastore(Datastore datastore)
{
switch (datastore) {
diff --git a/src/netconf_access.hpp b/src/netconf_access.hpp
index 45973a6..c54434d 100644
--- a/src/netconf_access.hpp
+++ b/src/netconf_access.hpp
@@ -47,8 +47,7 @@
void moveItem(const std::string& path, std::variant<yang::move::Absolute, yang::move::Relative> move) override;
void commitChanges() override;
void discardChanges() override;
- Tree executeRpc(const std::string& path, const Tree& input) override;
- Tree executeAction(const std::string& path, const Tree& input) override;
+ Tree execute(const std::string& path, const Tree& input) override;
void copyConfig(const Datastore source, const Datastore destination) override;
std::shared_ptr<Schema> schema() override;
@@ -57,14 +56,12 @@
private:
std::vector<ListInstance> listInstances(const std::string& path) override;
- DatastoreAccess::Tree impl_execute(const std::string& path, const Tree& input);
std::string fetchSchema(const std::string_view module, const
std::optional<std::string_view> revision, const
std::optional<std::string_view> submodule, const
std::optional<std::string_view> submoduleRevision);
std::vector<std::string> listImplementedSchemas();
- void datastoreInit();
void doEditFromDataNode(std::shared_ptr<libyang::Data_Node> dataNode);
std::unique_ptr<libnetconf::client::Session> m_session;
diff --git a/src/path_parser.hpp b/src/path_parser.hpp
index fca760d..58d174e 100644
--- a/src/path_parser.hpp
+++ b/src/path_parser.hpp
@@ -76,10 +76,8 @@
{
}
- // GCC complains that `end` isn't used when doing completions only
- // FIXME: GCC 10.1 doesn't emit a warning here. Remove [[maybe_unused]] when GCC 10 is available
template <typename It, typename Ctx, typename RCtx, typename Attr>
- bool parse(It& begin, [[maybe_unused]] It end, Ctx const& ctx, RCtx& rctx, Attr& attr) const
+ bool parse(It& begin, It end, Ctx const& ctx, RCtx& rctx, Attr& attr) const
{
std::string tableName;
if constexpr (std::is_same<attribute_type, schemaNode_>()) {
@@ -165,12 +163,7 @@
if constexpr (PARSER_MODE == NodeParserMode::CompletionsOnly) {
return true;
} else {
- It saveIter;
- // GCC complains that I assign saveIter because I use it only if NodeType is dataNode_
- // FIXME: GCC 10.1 doesn't emit a warning here. Make this unconditional when GCC 10 is available.
- if constexpr (std::is_same<attribute_type, dataNode_>()) {
- saveIter = begin;
- }
+ It saveIter = begin;
auto res = table.parse(begin, end, ctx, rctx, attr);
diff --git a/src/proxy_datastore.cpp b/src/proxy_datastore.cpp
index 113a923..ef3c5db 100644
--- a/src/proxy_datastore.cpp
+++ b/src/proxy_datastore.cpp
@@ -59,34 +59,14 @@
return m_datastore->dump(format);
}
-namespace {
-struct getInputPath {
- template <typename InputType>
- auto operator()(const InputType& input)
- {
- return input.m_path;
- }
-};
-}
-
-void ProxyDatastore::initiateRpc(const std::string& rpcPath)
+void ProxyDatastore::initiate(const std::string& path)
{
if (m_inputDatastore) {
- throw std::runtime_error("RPC/action input already in progress (" + std::visit(getInputPath{}, m_inputPath) + ")");
+ throw std::runtime_error("RPC/action input already in progress (" + m_inputPath + ")");
}
m_inputDatastore = m_createTemporaryDatastore(m_datastore);
- m_inputPath = RpcInput{rpcPath};
- m_inputDatastore->createItem(rpcPath);
-}
-
-void ProxyDatastore::initiateAction(const std::string& actionPath)
-{
- if (m_inputDatastore) {
- throw std::runtime_error("RPC/action input already in progress (" + std::visit(getInputPath{}, m_inputPath) + ")");
- }
- m_inputDatastore = m_createTemporaryDatastore(m_datastore);
- m_inputPath = ActionInput{actionPath};
- m_inputDatastore->createItem(actionPath);
+ m_inputPath = path;
+ m_inputDatastore->createItem(path);
}
DatastoreAccess::Tree ProxyDatastore::execute()
@@ -96,11 +76,7 @@
}
auto inputData = m_inputDatastore->getItems("/");
m_inputDatastore = nullptr;
- if (std::holds_alternative<RpcInput>(m_inputPath)) {
- return m_datastore->executeRpc(std::visit(getInputPath{}, m_inputPath), inputData);
- } else {
- return m_datastore->executeAction(std::visit(getInputPath{}, m_inputPath), inputData);
- }
+ return m_datastore->execute(m_inputPath, inputData);
}
void ProxyDatastore::cancel()
@@ -115,7 +91,7 @@
std::shared_ptr<DatastoreAccess> ProxyDatastore::pickDatastore(const std::string& path) const
{
- if (!m_inputDatastore || !boost::starts_with(path, std::visit(getInputPath{}, m_inputPath))) {
+ if (!m_inputDatastore || !boost::starts_with(path, m_inputPath)) {
return m_datastore;
} else {
return m_inputDatastore;
diff --git a/src/proxy_datastore.hpp b/src/proxy_datastore.hpp
index e7650cd..ab7e3a2 100644
--- a/src/proxy_datastore.hpp
+++ b/src/proxy_datastore.hpp
@@ -29,8 +29,7 @@
void copyConfig(const Datastore source, const Datastore destination);
[[nodiscard]] std::string dump(const DataFormat format) const;
- void initiateRpc(const std::string& rpcPath);
- void initiateAction(const std::string& actionPath);
+ void initiate(const std::string& path);
[[nodiscard]] DatastoreAccess::Tree execute();
void cancel();
@@ -48,14 +47,5 @@
std::function<std::shared_ptr<DatastoreAccess>(const std::shared_ptr<DatastoreAccess>&)> m_createTemporaryDatastore;
std::shared_ptr<DatastoreAccess> m_inputDatastore;
- struct RpcInput {
- std::string m_path;
- };
-
- struct ActionInput {
- std::string m_path;
- };
- // This variant is needed, so that I know whether to call executeRpc or executeAction
- // TODO: get rid of this variant with sysrepo2 because the method for RPC/action is the same there
- std::variant<ActionInput, RpcInput> m_inputPath;
+ std::string m_inputPath;
};
diff --git a/src/python_netconf.cpp b/src/python_netconf.cpp
index 7a0e4d3..c6e3c44 100644
--- a/src/python_netconf.cpp
+++ b/src/python_netconf.cpp
@@ -70,7 +70,7 @@
.def("setLeaf", &NetconfAccess::setLeaf, "xpath"_a, "value"_a)
.def("createItem", &NetconfAccess::createItem, "xpath"_a)
.def("deleteItem", &NetconfAccess::deleteItem, "xpath"_a)
- .def("executeRpc", &NetconfAccess::executeRpc, "rpc"_a, "input"_a=DatastoreAccess::Tree{})
+ .def("execute", &NetconfAccess::execute, "rpc"_a, "input"_a=DatastoreAccess::Tree{})
.def("commitChanges", &NetconfAccess::commitChanges)
;
}
diff --git a/src/sysrepo_access.cpp b/src/sysrepo_access.cpp
index 7c21cad..21eca7e 100644
--- a/src/sysrepo_access.cpp
+++ b/src/sysrepo_access.cpp
@@ -329,15 +329,7 @@
}
}
-// TODO: merge this with executeAction
-DatastoreAccess::Tree SysrepoAccess::executeRpc(const std::string& path, const Tree& input)
-{
- auto srInput = toSrVals(path, input);
- auto output = m_session->rpc_send(path.c_str(), srInput);
- return toTree(path, output);
-}
-
-DatastoreAccess::Tree SysrepoAccess::executeAction(const std::string& path, const Tree& input)
+DatastoreAccess::Tree SysrepoAccess::execute(const std::string& path, const Tree& input)
{
auto srInput = toSrVals(path, input);
auto output = m_session->rpc_send(path.c_str(), srInput);
diff --git a/src/sysrepo_access.hpp b/src/sysrepo_access.hpp
index d0ad869..55e8ac6 100644
--- a/src/sysrepo_access.hpp
+++ b/src/sysrepo_access.hpp
@@ -33,8 +33,7 @@
void createItem(const std::string& path) override;
void deleteItem(const std::string& path) override;
void moveItem(const std::string& source, std::variant<yang::move::Absolute, yang::move::Relative> move) override;
- Tree executeRpc(const std::string& path, const Tree& input) override;
- Tree executeAction(const std::string& path, const Tree& input) override;
+ Tree execute(const std::string& path, const Tree& input) override;
std::shared_ptr<Schema> schema() override;
diff --git a/src/yang_access.cpp b/src/yang_access.cpp
index a460150..7a43507 100644
--- a/src/yang_access.cpp
+++ b/src/yang_access.cpp
@@ -229,7 +229,7 @@
{
}
-[[noreturn]] void YangAccess::impl_execute(const std::string& type, const std::string& path, const Tree& input)
+[[noreturn]] DatastoreAccess::Tree YangAccess::execute(const std::string& path, const Tree& input)
{
auto root = lyWrap(lyd_new_path(nullptr, m_ctx.get(), path.c_str(), nullptr, LYD_ANYDATA_CONSTSTRING, 0));
if (!root) {
@@ -244,17 +244,7 @@
getErrorsAndThrow();
}
}
- throw std::logic_error("in-memory datastore doesn't support executing " + type + "s");
-}
-
-DatastoreAccess::Tree YangAccess::executeRpc(const std::string& path, const Tree& input)
-{
- impl_execute("RPC", path, input);
-}
-
-DatastoreAccess::Tree YangAccess::executeAction(const std::string& path, const Tree& input)
-{
- impl_execute("action", path, input);
+ throw std::logic_error("in-memory datastore doesn't support executing RPC/action");
}
void YangAccess::copyConfig(const Datastore source, const Datastore dest)
diff --git a/src/yang_access.hpp b/src/yang_access.hpp
index 62c43d6..c009420 100644
--- a/src/yang_access.hpp
+++ b/src/yang_access.hpp
@@ -30,8 +30,7 @@
void moveItem(const std::string& source, std::variant<yang::move::Absolute, yang::move::Relative> move) override;
void commitChanges() override;
void discardChanges() override;
- Tree executeRpc(const std::string& path, const Tree& input) override;
- Tree executeAction(const std::string& path, const Tree& input) override;
+ [[noreturn]] Tree execute(const std::string& path, const Tree& input) override;
void copyConfig(const Datastore source, const Datastore destination) override;
std::shared_ptr<Schema> schema() override;
diff --git a/src/yang_schema.cpp b/src/yang_schema.cpp
index 7f27711..7e5bb9f 100644
--- a/src/yang_schema.cpp
+++ b/src/yang_schema.cpp
@@ -284,7 +284,19 @@
}
}
- return yang::TypeInfo(resType, resUnits);
+ std::optional<std::string> resDescription;
+
+ // checking for parentTypedef->type()->der() means I'm going to enter inside base types like "string". These
+ // also have a description, but it isn't too helpful ("human-readable string")
+ for (auto parentTypedef = type->der(); parentTypedef && parentTypedef->type()->der(); parentTypedef = parentTypedef->type()->der()) {
+ auto dsc = parentTypedef->dsc();
+ if (dsc) {
+ resDescription = dsc;
+ break;
+ }
+ }
+
+ return yang::TypeInfo(resType, resUnits, resDescription);
};
return resolveType(leaf->type());
}
diff --git a/tests/datastore_access.cpp b/tests/datastore_access.cpp
index 43d6038..ddfe288 100644
--- a/tests/datastore_access.cpp
+++ b/tests/datastore_access.cpp
@@ -951,7 +951,7 @@
SECTION("noop")
{
rpc = "/example-schema:noop";
- proxyDatastore.initiateRpc(rpc);
+ proxyDatastore.initiate(rpc);
}
SECTION("small nuke")
@@ -961,7 +961,7 @@
{"description", "dummy"s},
{"payload/kilotons", uint64_t{333'666}},
};
- proxyDatastore.initiateRpc(rpc);
+ proxyDatastore.initiate(rpc);
proxyDatastore.setLeaf("/example-schema:launch-nukes/example-schema:payload/example-schema:kilotons", uint64_t{333'666});
// no data are returned
}
@@ -973,7 +973,7 @@
{"description", "dummy"s},
{"payload/kilotons", uint64_t{4}},
};
- proxyDatastore.initiateRpc(rpc);
+ proxyDatastore.initiate(rpc);
proxyDatastore.setLeaf("/example-schema:launch-nukes/example-schema:payload/example-schema:kilotons", uint64_t{4});
output = {
@@ -989,7 +989,7 @@
{"payload/kilotons", uint64_t{6}},
{"cities/targets[city='Prague']/city", "Prague"s},
};
- proxyDatastore.initiateRpc(rpc);
+ proxyDatastore.initiate(rpc);
proxyDatastore.setLeaf("/example-schema:launch-nukes/example-schema:payload/example-schema:kilotons", uint64_t{6});
proxyDatastore.createItem("/example-schema:launch-nukes/example-schema:cities/example-schema:targets[city='Prague']");
output = {
@@ -1012,17 +1012,17 @@
input = {
{"whom", "Colton"s}
};
- proxyDatastore.initiateRpc(rpc);
+ proxyDatastore.initiate(rpc);
proxyDatastore.setLeaf("/example-schema:fire/example-schema:whom", "Colton"s);
}
- catching<OnExec>([&] { REQUIRE(datastore->executeRpc(rpc, input) == output); });
+ catching<OnExec>([&] { REQUIRE(datastore->execute(rpc, input) == output); });
catching<OnExec>([&] { REQUIRE(proxyDatastore.execute() == output); });
}
SECTION("non-existing RPC")
{
- catching<OnInvalidRpcPath>([&] { datastore->executeRpc("/example-schema:non-existing", DatastoreAccess::Tree{}); });
+ catching<OnInvalidRpcPath>([&] { datastore->execute("/example-schema:non-existing", DatastoreAccess::Tree{}); });
}
}
@@ -1045,7 +1045,7 @@
path = "/example-schema:ports[name='A']/shutdown";
}
- catching<OnExec>([&] { REQUIRE(datastore->executeAction(path, input) == output); });
+ catching<OnExec>([&] { REQUIRE(datastore->execute(path, input) == output); });
}
waitForCompletionAndBitMore(seq1);
diff --git a/tests/datastoreaccess_mock.hpp b/tests/datastoreaccess_mock.hpp
index 751cdad..e708149 100644
--- a/tests/datastoreaccess_mock.hpp
+++ b/tests/datastoreaccess_mock.hpp
@@ -24,8 +24,7 @@
IMPLEMENT_MOCK1(createItem);
IMPLEMENT_MOCK1(deleteItem);
IMPLEMENT_MOCK2(moveItem);
- IMPLEMENT_MOCK2(executeRpc);
- IMPLEMENT_MOCK2(executeAction);
+ IMPLEMENT_MOCK2(execute);
// Can't use IMPLEMENT_MOCK for private methods - IMPLEMENT_MOCK needs full visibility of the method
MAKE_MOCK1(listInstances, std::vector<ListInstance>(const std::string&), override);
diff --git a/tests/example-schema.yang b/tests/example-schema.yang
index 6c546d3..0db4c4f 100644
--- a/tests/example-schema.yang
+++ b/tests/example-schema.yang
@@ -88,6 +88,16 @@
}
}
+ typedef myType {
+ type int32;
+ description "My type.";
+ }
+
+ leaf typedefedLeaf {
+ type myType;
+ description "This is a typedefed leaf.";
+ }
+
grouping upAndDown {
leaf up {
type boolean;
diff --git a/tests/interpreter.cpp b/tests/interpreter.cpp
index d57ad64..c6d7c9c 100644
--- a/tests/interpreter.cpp
+++ b/tests/interpreter.cpp
@@ -454,7 +454,7 @@
SECTION("exec")
{
REQUIRE_CALL(*input_datastore, getItems("/")).RETURN(DatastoreAccess::Tree{});
- REQUIRE_CALL(*datastore, executeRpc("/example:launch-nukes", DatastoreAccess::Tree{})).RETURN(DatastoreAccess::Tree{});
+ REQUIRE_CALL(*datastore, execute("/example:launch-nukes", DatastoreAccess::Tree{})).RETURN(DatastoreAccess::Tree{});
boost::apply_visitor(Interpreter(parser, proxyDatastore), command_{exec_{}});
}
diff --git a/tests/path_completion.cpp b/tests/path_completion.cpp
index ffd3e93..6c7a8e6 100644
--- a/tests/path_completion.cpp
+++ b/tests/path_completion.cpp
@@ -205,6 +205,16 @@
}
}
+ SECTION("describe completion")
+ {
+ SECTION("path with list at the end")
+ {
+ input = "describe /example:list/";
+ expectedCompletions = {"contInList/", "number "};
+ expectedContextLength = 0;
+ }
+ }
+
SECTION("list keys completion")
{
SECTION("cd example:lis")
diff --git a/tests/prepare.cpp b/tests/prepare.cpp
index 139ef4b..d56a488 100644
--- a/tests/prepare.cpp
+++ b/tests/prepare.cpp
@@ -28,14 +28,14 @@
SECTION("rpc")
{
input = "prepare example:fire";
- expected.m_path.m_nodes.push_back({module_{"example"}, rpcNode_{"fire"}});
+ expected.m_path.m_nodes.emplace_back(module_{"example"}, rpcNode_{"fire"});
}
SECTION("action")
{
input = "prepare example:port[name='eth0']/shutdown";
- expected.m_path.m_nodes.push_back({module_{"example"}, listElement_{"port", {{"name", std::string{"eth0"}}}}});
- expected.m_path.m_nodes.push_back({actionNode_{"shutdown"}});
+ expected.m_path.m_nodes.emplace_back(module_{"example"}, listElement_{"port", {{"name", std::string{"eth0"}}}});
+ expected.m_path.m_nodes.emplace_back(actionNode_{"shutdown"});
}
command_ command = parser.parseCommand(input, errorStream);
diff --git a/tests/pretty_printers.hpp b/tests/pretty_printers.hpp
index 1c7154b..7f19a8e 100644
--- a/tests/pretty_printers.hpp
+++ b/tests/pretty_printers.hpp
@@ -96,7 +96,9 @@
std::ostream& operator<<(std::ostream& s, const yang::TypeInfo& type)
{
- s << type.m_type << (type.m_units ? " units: " + *type.m_units : "");
+ s << type.m_type;
+ s << " units: " << (type.m_units ? *type.m_units : "std::nullopt");
+ s << " description: " << (type.m_description ? *type.m_description : "std::nullopt");
return s;
}
diff --git a/tests/set_value_completion.cpp b/tests/set_value_completion.cpp
index dd36e34..f4d8124 100644
--- a/tests/set_value_completion.cpp
+++ b/tests/set_value_completion.cpp
@@ -29,6 +29,7 @@
schema->addIdentity(identityRef_{"mod", "food"}, identityRef_{"mod", "spaghetti"});
schema->addIdentity(identityRef_{"mod", "pizza"}, identityRef_{"pizza-module", "hawaii"});
schema->addLeaf("/", "mod:foodIdentRef", yang::IdentityRef{schema->validIdentities("mod", "food")});
+ schema->addLeaf("/", "mod:flags", yang::Bits{{"parity", "zero", "carry", "sign"}});
auto mockDatastore = std::make_shared<MockDatastoreAccess>();
// The parser will use DataQuery for key value completion, but I'm not testing that here, so I don't return anything.
ALLOW_CALL(*mockDatastore, listInstances("/mod:list"))
@@ -88,5 +89,19 @@
expectedContextLength = 0;
}
+ SECTION("set mod:flags ")
+ {
+ input = "set mod:flags ";
+ expectedCompletions = {"carry", "sign", "parity", "zero"};
+ expectedContextLength = 0;
+ }
+
+ SECTION("set mod:flags ze")
+ {
+ input = "set mod:flags ze";
+ expectedCompletions = {"zero"};
+ expectedContextLength = 2;
+ }
+
REQUIRE(parser.completeCommand(input, errorStream) == (Completions{expectedCompletions, expectedContextLength}));
}
diff --git a/tests/yang.cpp b/tests/yang.cpp
index 1ec6507..699a05c 100644
--- a/tests/yang.cpp
+++ b/tests/yang.cpp
@@ -171,6 +171,7 @@
enum lol;
enum data;
}
+ description "This is a restricted enum typedef.";
}
leaf leafEnumTypedef {
@@ -518,6 +519,7 @@
SECTION("leafType")
{
yang::LeafDataType type;
+ std::optional<std::string> expectedDescription;
SECTION("leafString")
{
@@ -622,6 +624,7 @@
node.first = "example-schema";
node.second = "leafEnumTypedefRestricted2";
type = createEnum({"lol", "data"});
+ expectedDescription = "This is a restricted enum typedef.";
}
SECTION("pizzaSize")
@@ -736,7 +739,7 @@
}
- REQUIRE(ys.leafType(path, node) == type);
+ REQUIRE(ys.leafType(path, node) == yang::TypeInfo(type, std::nullopt, expectedDescription));
}
SECTION("availableNodes")
{
@@ -1072,6 +1075,16 @@
REQUIRE(ys.leafType(pathToSchemaString(path, Prefixes::WhenNeeded)) == yang::TypeInfo{expectedType, expectedUnits});
}
+ SECTION("type description")
+ {
+ yang::LeafDataType expectedType = createEnum({"lol", "data"});
+ std::optional<std::string> expectedDescription;
+
+ path.m_nodes.emplace_back(module_{"example-schema"}, leaf_("leafEnumTypedefRestricted2"));
+ expectedDescription = "This is a restricted enum typedef.";
+ REQUIRE(ys.leafType(pathToSchemaString(path, Prefixes::WhenNeeded)) == yang::TypeInfo{expectedType, std::nullopt, expectedDescription});
+ }
+
SECTION("nodeType")
{
yang::NodeTypes expected;