Merge "Add support for `empty` YANG leaf type"
diff --git a/.zuul.CzechLight-internal.yaml b/.zuul.CzechLight-internal.yaml
new file mode 100644
index 0000000..07aa1e8
--- /dev/null
+++ b/.zuul.CzechLight-internal.yaml
@@ -0,0 +1,7 @@
+- project:
+ check:
+ jobs:
+ - czechlight-clearfog:
+ required-projects:
+ - CzechLight/br2-external
+ requires: CzechLight-br2-build-clearfog
diff --git a/.zuul.yaml b/.zuul.public.yaml
similarity index 88%
rename from .zuul.yaml
rename to .zuul.public.yaml
index ecba5d1..b470c0a 100644
--- a/.zuul.yaml
+++ b/.zuul.public.yaml
@@ -9,8 +9,6 @@
requires: CzechLight-deps-f31-clang-asan
- f31-clang-tsan:
requires: CzechLight-deps-f31-clang-tsan
- - f29-gcc:
- requires: CzechLight-deps-f29-gcc
- f31-cpp-coverage-diff:
voting: false
- clang-format:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 78e67f0..abbe97b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -274,8 +274,8 @@
cli_test(utils)
cli_test(path_completion)
cli_test(command_completion)
- cli_test(enum_completion)
- target_link_libraries(test_enum_completion leaf_data_type)
+ cli_test(set_value_completion)
+ target_link_libraries(test_set_value_completion leaf_data_type)
cli_test(list_manipulation)
cli_test(ls_interpreter)
cli_test(path_utils)
diff --git a/ci/build.sh b/ci/build.sh
index fe8d8a7..3e2cf5d 100755
--- a/ci/build.sh
+++ b/ci/build.sh
@@ -75,18 +75,16 @@
if [[ -z "${ARTIFACT_URL}" ]]; then
# fallback to a promoted artifact
- ARTIFACT_URL="https://object-store.cloud.muni.cz/swift/v1/ci-artifacts-${ZUUL_TENANT}/${ZUUL_GERRIT_HOSTNAME}/CzechLight/dependencies/${ZUUL_JOB_NAME%%-cover?(-previous|-diff)}/${DEP_SUBMODULE_COMMIT}.tar.xz"
+ ARTIFACT_URL="https://object-store.cloud.muni.cz/swift/v1/ci-artifacts-${ZUUL_TENANT}/${ZUUL_GERRIT_HOSTNAME}/CzechLight/dependencies/${ZUUL_JOB_NAME%%-cover?(-previous|-diff)}/${DEP_SUBMODULE_COMMIT}.tar.zst"
fi
ARTIFACT_FILE=$(basename ${ARTIFACT_URL})
-DEP_HASH_FROM_ARTIFACT=$(echo "${ARTIFACT_FILE}" | sed -e 's/^czechlight-dependencies-//' -e 's/\.tar\.xz$//')
+DEP_HASH_FROM_ARTIFACT=$(echo "${ARTIFACT_FILE}" | sed -e 's/^czechlight-dependencies-//' -e 's/\.tar\.zst$//')
if [[ "${DEP_HASH_FROM_ARTIFACT}" != "${DEP_SUBMODULE_COMMIT}" ]]; then
echo "Mismatched artifact: HEAD of ./submodules/dependencies does not match artifact commit ref"
exit 1
fi
-curl ${ARTIFACT_URL} --output ${ARTIFACT_FILE}
-tar -C ${PREFIX} -xf ${ARTIFACT_FILE}
-rm ${ARTIFACT_FILE}
+curl ${ARTIFACT_URL} | unzstd --stdout | tar -C ${PREFIX} -xf -
cd ${BUILD_DIR}
cmake -GNinja -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE:-Debug} -DCMAKE_INSTALL_PREFIX=${PREFIX} ${CMAKE_OPTIONS} ${ZUUL_PROJECT_SRC_DIR}
diff --git a/src/ast_handlers.hpp b/src/ast_handlers.hpp
index 14d3451..ab9958a 100644
--- a/src/ast_handlers.hpp
+++ b/src/ast_handlers.hpp
@@ -172,34 +172,6 @@
struct dataPathListEnd_class;
-struct dataPath_class {
- template <typename Iterator, typename Exception, typename Context>
- x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const&, Context const& context)
- {
- auto& parserContext = x3::get<parser_context_tag>(context);
- if (parserContext.m_errorMsg.empty()) {
- parserContext.m_errorMsg = "Expected path.";
- return x3::error_handler_result::fail;
- } else {
- return x3::error_handler_result::rethrow;
- }
- }
-};
-
-struct schemaPath_class {
- template <typename Iterator, typename Exception, typename Context>
- x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const&, Context const& context)
- {
- auto& parserContext = x3::get<parser_context_tag>(context);
- if (parserContext.m_errorMsg.empty()) {
- parserContext.m_errorMsg = "Expected path.";
- return x3::error_handler_result::fail;
- } else {
- return x3::error_handler_result::rethrow;
- }
- }
-};
-
struct discard_class;
struct ls_class;
diff --git a/src/common_parsers.hpp b/src/common_parsers.hpp
index eac8e61..8da90a6 100644
--- a/src/common_parsers.hpp
+++ b/src/common_parsers.hpp
@@ -34,6 +34,22 @@
auto const space_separator_def =
x3::omit[x3::no_skip[x3::space]];
+template <typename CoerceTo>
+struct as_type {
+ template <typename...> struct Tag{};
+
+ template <typename ParserType>
+ auto operator[](ParserType p) const {
+ return x3::rule<Tag<CoerceTo, ParserType>, CoerceTo> {"as"} = x3::as_parser(p);
+ }
+};
+
+// The `as` parser creates an ad-hoc x3::rule with the attribute specified with `CoerceTo`.
+// Example usage: as<std::string>[someParser]
+// someParser will have its attribute coerced to std::string
+// https://github.com/boostorg/spirit/issues/530#issuecomment-584836532
+template <typename CoerceTo> const as_type<CoerceTo> as{};
+
BOOST_SPIRIT_DEFINE(node_identifier)
BOOST_SPIRIT_DEFINE(module)
BOOST_SPIRIT_DEFINE(module_identifier)
diff --git a/src/grammars.hpp b/src/grammars.hpp
index ae7a980..74a6a17 100644
--- a/src/grammars.hpp
+++ b/src/grammars.hpp
@@ -47,7 +47,7 @@
} const ls_options;
auto const ls_def =
- ls_::name >> *(space_separator >> ls_options) >> -(space_separator >> (dataPathListEnd | dataPath | schemaPath | (module >> "*")));
+ ls_::name >> *(space_separator >> ls_options) >> -(space_separator >> (dataPathListEnd | anyPath | (module >> "*")));
auto const cd_def =
cd_::name >> space_separator > dataPath;
@@ -132,7 +132,7 @@
copy_::name > space_separator > copy_args;
auto const describe_def =
- describe_::name >> space_separator > (dataPathListEnd | dataPath | schemaPath);
+ describe_::name >> space_separator > (dataPathListEnd | anyPath);
auto const createCommandSuggestions_def =
x3::eps;
diff --git a/src/leaf_data.hpp b/src/leaf_data.hpp
index 4330d5a..913de8b 100644
--- a/src/leaf_data.hpp
+++ b/src/leaf_data.hpp
@@ -22,8 +22,6 @@
x3::rule<struct leaf_data_class<yang::Binary>, binary_> const leaf_data_binary = "leaf_data_binary";
x3::rule<struct leaf_data_class<yang::Decimal>, double> const leaf_data_decimal = "leaf_data_decimal";
x3::rule<struct leaf_data_class<yang::String>, std::string> const leaf_data_string = "leaf_data_string";
-x3::rule<struct leaf_data_class_binary, std::string> const leaf_data_binary_data = "leaf_data_binary_data";
-x3::rule<struct leaf_data_identityRef_data_class, identityRef_> const leaf_data_identityRef_data = "leaf_data_identityRef_data";
using x3::char_;
@@ -43,22 +41,11 @@
'\'' >> *(char_-'\'') >> '\'' |
'\"' >> *(char_-'\"') >> '\"';
-// This intermediate rule is neccessary for coercing to std::string.
-// TODO: check if I can do the coercing right in the grammar with `as{}` from
-// https://github.com/boostorg/spirit/issues/530#issuecomment-584836532
-// This would shave off some more lines.
-auto const leaf_data_binary_data_def =
- +(x3::alnum | char_('+') | char_('/')) >> -char_('=') >> -char_('=');
-
auto const leaf_data_binary_def =
- leaf_data_binary_data;
+ as<std::string>[+(x3::alnum | char_('+') | char_('/')) >> -char_('=') >> -char_('=')];
-auto const leaf_data_identityRef_data_def =
- -module >> node_identifier;
-
-// TODO: get rid of this and use leaf_data_identityRef_data directly
auto const leaf_data_identityRef_def =
- leaf_data_identityRef_data;
+ -module >> node_identifier;
template <typename It, typename Ctx, typename RCtx, typename Attr>
struct impl_LeafData {
@@ -128,50 +115,42 @@
std::transform(type.m_allowedValues.begin(),
type.m_allowedValues.end(),
std::inserter(parserContext.m_suggestions, parserContext.m_suggestions.end()),
- [](auto it) { return Completion{it.m_value}; });
+ [](auto it) {
+ std::string res;
+ if constexpr (std::is_same<Type, yang::IdentityRef>()) {
+ res = it.m_prefix ? it.m_prefix->m_name + ":" : "";
+ }
+ res += it.m_value;
+ return Completion{res};
+ });
parserContext.m_completionIterator = first;
}
bool operator()(const yang::Enum& type) const
{
createSetSuggestions(type);
- // leaf_data_enum will advance the iterator if it succeeds, so I have
- // to save the iterator here, to roll it back in case the enum is
- // invalid.
- auto saveIter = first;
- auto pass = leaf_data_enum.parse(first, last, ctx, rctx, attr);
- if (!pass) {
- return false;
- }
- auto isValidEnum = type.m_allowedValues.count(boost::get<enum_>(attr)) != 0;
- if (!isValidEnum) {
- first = saveIter;
- parserContext.m_errorMsg = "leaf data type mismatch: Expected an enum here. Allowed values:";
- for (const auto& it : type.m_allowedValues) {
- parserContext.m_errorMsg += " " + it.m_value;
+ auto checkValidEnum = [this, type] (auto& ctx) {
+ if (type.m_allowedValues.count(boost::get<enum_>(attr)) == 0) {
+ _pass(ctx) = false;
+ parserContext.m_errorMsg = "leaf data type mismatch: Expected an enum here. Allowed values:";
+ for (const auto& it : type.m_allowedValues) {
+ parserContext.m_errorMsg += " " + it.m_value;
+ }
}
- }
- return isValidEnum;
+ };
+ return leaf_data_enum[checkValidEnum].parse(first, last, ctx, rctx, attr);
}
bool operator()(const yang::IdentityRef& type) const
{
createSetSuggestions(type);
- // leaf_data_identityRef will advance the iterator if it succeeds, so I have
- // to save the iterator here, to roll it back in case the enum is
- // invalid.
- auto saveIter = first;
- auto pass = leaf_data_identityRef.parse(first, last, ctx, rctx, attr);
- if (!pass) {
- return false;
- }
- identityRef_ pair{boost::get<identityRef_>(attr)};
- if (!pair.m_prefix) {
- pair.m_prefix = module_{parserContext.currentSchemaPath().m_nodes.front().m_prefix.get().m_name};
- }
- auto isValidIdentity = type.m_allowedValues.count(pair) != 0;
- if (!isValidIdentity) {
- first = saveIter;
- }
- return isValidIdentity;
+ auto checkValidIdentity = [this, type] (auto& ctx) {
+ identityRef_ pair{boost::get<identityRef_>(_attr(ctx))};
+ if (!pair.m_prefix) {
+ pair.m_prefix = module_{parserContext.currentSchemaPath().m_nodes.front().m_prefix.get().m_name};
+ }
+ _pass(ctx) = type.m_allowedValues.count(pair) != 0;
+ };
+
+ return leaf_data_identityRef[checkValidIdentity].parse(first, last, ctx, rctx, attr);
}
bool operator()(const yang::LeafRef& leafRef) const
{
@@ -211,7 +190,5 @@
BOOST_SPIRIT_DEFINE(leaf_data_enum)
BOOST_SPIRIT_DEFINE(leaf_data_string)
-BOOST_SPIRIT_DEFINE(leaf_data_binary_data)
BOOST_SPIRIT_DEFINE(leaf_data_binary)
-BOOST_SPIRIT_DEFINE(leaf_data_identityRef_data)
BOOST_SPIRIT_DEFINE(leaf_data_identityRef)
diff --git a/src/path_parser.hpp b/src/path_parser.hpp
index 19ab2a2..6360912 100644
--- a/src/path_parser.hpp
+++ b/src/path_parser.hpp
@@ -14,8 +14,6 @@
namespace x3 = boost::spirit::x3;
-x3::rule<dataPath_class, dataPath_> const dataPath = "dataPath";
-x3::rule<schemaPath_class, schemaPath_> const schemaPath = "schemaPath";
x3::rule<dataNodeList_class, decltype(dataPath_::m_nodes)::value_type> const dataNodeList = "dataNodeList";
x3::rule<dataNodesListEnd_class, decltype(dataPath_::m_nodes)> const dataNodesListEnd = "dataNodesListEnd";
x3::rule<dataPathListEnd_class, dataPath_> const dataPathListEnd = "dataPathListEnd";
@@ -128,6 +126,53 @@
NodeParser<schemaNode_> schemaNode;
NodeParser<dataNode_> dataNode;
+using AnyPath = boost::variant<schemaPath_, dataPath_>;
+
+template <typename PathType>
+struct PathParser : x3::parser<PathParser<PathType>> {
+ using attribute_type = PathType;
+ template <typename It, typename Ctx, typename RCtx, typename Attr>
+ bool parse(It& begin, It end, Ctx const& ctx, RCtx& rctx, Attr& attr) const
+ {
+ initializePath.parse(begin, end, ctx, rctx, x3::unused);
+ dataPath_ attrData;
+
+ // absoluteStart has to be separate from the dataPath parser,
+ // otherwise, if the "dataNode % '/'" parser fails, the begin iterator
+ // gets reverted to before the starting slash.
+ auto res = -absoluteStart.parse(begin, end, ctx, rctx, attrData.m_scope);
+ auto dataPath = x3::attr(attrData.m_scope) >> dataNode % '/' >> -trailingSlash;
+ res = dataPath.parse(begin, end, ctx, rctx, attrData);
+ attr = attrData;
+
+ if constexpr (std::is_same<Attr, AnyPath>()) {
+ auto pathEnd = x3::rule<class PathEnd>{"pathEnd"} = &space_separator | x3::eoi;
+ // If parsing failed, or if there's more input we try parsing schema nodes
+ if (!res || !pathEnd.parse(begin, end, ctx, rctx, x3::unused)) {
+ // If dataPath parsed some nodes, they will be saved in `attrData`. We have to keep these.
+ schemaPath_ attrSchema = dataPathToSchemaPath(attrData);
+ auto schemaPath = schemaNode % '/';
+ // The schemaPath parser continues where the dataPath parser ended.
+ res = schemaPath.parse(begin, end, ctx, rctx, attrSchema.m_nodes);
+ auto trailing = -trailingSlash >> pathEnd;
+ res = trailing.parse(begin, end, ctx, rctx, attrSchema.m_trailingSlash);
+ attr = attrSchema;
+ }
+ }
+ return res;
+ }
+};
+
+// Need to use these wrappers so that my PathParser class gets the proper
+// attribute. Otherwise, Spirit injects the attribute of the outer parser that
+// uses my PathParser.
+// Example grammar: anyPath | module.
+// The PathParser class would get a boost::variant as the attribute, but I
+// don't want to deal with that, so I use these wrappers to ensure the
+// attribute I want (and let Spirit deal with boost::variant).
+auto const anyPath = x3::rule<class anyPath_class, AnyPath>{"anyPath"} = PathParser<AnyPath>{};
+auto const dataPath = x3::rule<class dataPath_class, dataPath_>{"dataPath"} = PathParser<dataPath_>{};
+
#if __clang__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Woverloaded-shift-op-parentheses"
@@ -172,9 +217,6 @@
auto const createPathSuggestions_def =
x3::eps;
-// I have to insert an empty vector to the first alternative, otherwise they won't have the same attribute
-auto const dataPath_def = initializePath >> absoluteStart >> createPathSuggestions >> x3::attr(decltype(dataPath_::m_nodes)()) >> x3::attr(TrailingSlash::NonPresent) >> x3::eoi | initializePath >> -(absoluteStart >> createPathSuggestions) >> dataNode % '/' >> (-(trailingSlash >> createPathSuggestions) >> -(completing >> rest) >> (&space_separator | x3::eoi));
-
auto const dataNodeList_def =
createPathSuggestions >> -(module) >> list;
@@ -188,8 +230,6 @@
auto const dataPathListEnd_def = initializePath >> absoluteStart >> createPathSuggestions >> x3::attr(decltype(dataPath_::m_nodes)()) >> x3::attr(TrailingSlash::NonPresent) >> x3::eoi | initializePath >> -(absoluteStart >> createPathSuggestions) >> dataNodesListEnd >> (-(trailingSlash >> createPathSuggestions) >> -(completing >> rest) >> (&space_separator | x3::eoi));
-auto const schemaPath_def = initializePath >> absoluteStart >> createPathSuggestions >> x3::attr(decltype(schemaPath_::m_nodes)()) >> x3::attr(TrailingSlash::NonPresent) >> x3::eoi | initializePath >> -(absoluteStart >> createPathSuggestions) >> schemaNode % '/' >> (-(trailingSlash >> createPathSuggestions) >> -(completing >> rest) >> (&space_separator | x3::eoi));
-
auto const leafPath_def =
dataPath;
@@ -218,8 +258,6 @@
BOOST_SPIRIT_DEFINE(leafPath)
BOOST_SPIRIT_DEFINE(presenceContainerPath)
BOOST_SPIRIT_DEFINE(listInstancePath)
-BOOST_SPIRIT_DEFINE(schemaPath)
-BOOST_SPIRIT_DEFINE(dataPath)
BOOST_SPIRIT_DEFINE(dataPathListEnd)
BOOST_SPIRIT_DEFINE(initializePath)
BOOST_SPIRIT_DEFINE(createKeySuggestions)
diff --git a/src/schema.hpp b/src/schema.hpp
index f11265f..0a9b2ff 100644
--- a/src/schema.hpp
+++ b/src/schema.hpp
@@ -15,8 +15,6 @@
#include "ast_path.hpp"
#include "leaf_data_type.hpp"
-using ModuleValuePair = std::pair<boost::optional<std::string>, std::string>;
-
namespace yang {
enum class NodeTypes {
Container,
diff --git a/src/static_schema.cpp b/src/static_schema.cpp
index 2395aa0..aecad5a 100644
--- a/src/static_schema.cpp
+++ b/src/static_schema.cpp
@@ -73,15 +73,10 @@
std::set<identityRef_> StaticSchema::validIdentities(std::string_view module, std::string_view value)
{
- std::set<ModuleValuePair> identities;
- getIdentSet(ModuleNodePair{boost::optional<std::string>{module}, value}, identities);
- std::set<identityRef_> res;
+ std::set<identityRef_> identities;
+ getIdentSet(identityRef_{std::string{module}, std::string{value}}, identities);
- std::transform(identities.begin(), identities.end(), std::inserter(res, res.end()), [](const auto& identity) {
- return identityRef_{*identity.first, identity.second};
- });
-
- return res;
+ return identities;
}
void StaticSchema::addLeaf(const std::string& location, const std::string& name, const yang::LeafDataType& type)
@@ -96,15 +91,15 @@
m_modules.emplace(name);
}
-void StaticSchema::addIdentity(const std::optional<ModuleValuePair>& base, const ModuleValuePair& name)
+void StaticSchema::addIdentity(const std::optional<identityRef_>& base, const identityRef_& name)
{
if (base)
m_identities.at(base.value()).emplace(name);
- m_identities.emplace(name, std::set<ModuleValuePair>());
+ m_identities.emplace(name, std::set<identityRef_>());
}
-void StaticSchema::getIdentSet(const ModuleValuePair& ident, std::set<ModuleValuePair>& res) const
+void StaticSchema::getIdentSet(const identityRef_& ident, std::set<identityRef_>& res) const
{
res.insert(ident);
auto derivedIdentities = m_identities.at(ident);
diff --git a/src/static_schema.hpp b/src/static_schema.hpp
index 67bd7b9..5184ae6 100644
--- a/src/static_schema.hpp
+++ b/src/static_schema.hpp
@@ -69,16 +69,15 @@
void addLeaf(const std::string& location, const std::string& name, const yang::LeafDataType& type);
void addList(const std::string& location, const std::string& name, const std::set<std::string>& keys);
void addModule(const std::string& name);
- void addIdentity(const std::optional<ModuleValuePair>& base, const ModuleValuePair& name);
+ void addIdentity(const std::optional<identityRef_>& base, const identityRef_& name);
private:
const std::unordered_map<std::string, NodeType>& children(const std::string& name) const;
- void getIdentSet(const ModuleValuePair& ident, std::set<ModuleValuePair>& res) const;
+ void getIdentSet(const identityRef_& ident, std::set<identityRef_>& res) const;
bool nodeExists(const std::string& location, const std::string& node) const;
std::unordered_map<std::string, std::unordered_map<std::string, NodeType>> m_nodes;
std::set<std::string> m_modules;
- // FIXME: Change the template arguments to identityRef_
- std::map<ModuleValuePair, std::set<ModuleValuePair>> m_identities;
+ std::map<identityRef_, std::set<identityRef_>> m_identities;
};
diff --git a/submodules/dependencies b/submodules/dependencies
index 837e9f9..735daca 160000
--- a/submodules/dependencies
+++ b/submodules/dependencies
@@ -1 +1 @@
-Subproject commit 837e9f98f3176f02b01f7e2838fc3da0f0047c71
+Subproject commit 735daca4ccb8bb91f55d793387da50266609d538
diff --git a/tests/leaf_editing.cpp b/tests/leaf_editing.cpp
index 666c975..75433e0 100644
--- a/tests/leaf_editing.cpp
+++ b/tests/leaf_editing.cpp
@@ -37,11 +37,11 @@
schema->addLeaf("/", "mod:leafUint32", yang::Uint32{});
schema->addLeaf("/", "mod:leafUint64", yang::Uint64{});
schema->addLeaf("/", "mod:leafBinary", yang::Binary{});
- schema->addIdentity(std::nullopt, ModuleValuePair{"mod", "food"});
- schema->addIdentity(std::nullopt, ModuleValuePair{"mod", "vehicle"});
- schema->addIdentity(ModuleValuePair{"mod", "food"}, ModuleValuePair{"mod", "pizza"});
- schema->addIdentity(ModuleValuePair{"mod", "food"}, ModuleValuePair{"mod", "spaghetti"});
- schema->addIdentity(ModuleValuePair{"mod", "pizza"}, ModuleValuePair{"pizza-module", "hawaii"});
+ schema->addIdentity(std::nullopt, identityRef_{"mod", "food"});
+ schema->addIdentity(std::nullopt, identityRef_{"mod", "vehicle"});
+ schema->addIdentity(identityRef_{"mod", "food"}, identityRef_{"mod", "pizza"});
+ 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:pizzaIdentRef", yang::IdentityRef{schema->validIdentities("mod", "pizza")});
schema->addLeaf("/mod:contA", "mod:identInCont", yang::IdentityRef{schema->validIdentities("mod", "pizza")});
diff --git a/tests/enum_completion.cpp b/tests/set_value_completion.cpp
similarity index 77%
rename from tests/enum_completion.cpp
rename to tests/set_value_completion.cpp
index 07ea32c..c3ad64a 100644
--- a/tests/enum_completion.cpp
+++ b/tests/set_value_completion.cpp
@@ -1,4 +1,3 @@
-
/*
* Copyright (C) 2018 CESNET, https://photonics.cesnet.cz/
* Copyright (C) 2018 FIT CVUT, https://fit.cvut.cz/
@@ -14,7 +13,7 @@
#include "pretty_printers.hpp"
#include "static_schema.hpp"
-TEST_CASE("enum completion")
+TEST_CASE("set value completion")
{
auto schema = std::make_shared<StaticSchema>();
schema->addModule("mod");
@@ -24,6 +23,12 @@
schema->addList("/", "mod:list", {"number"});
schema->addLeaf("/mod:list", "mod:number", yang::Int32{});
schema->addLeaf("/mod:list", "mod:leafInList", createEnum({"ano", "anoda", "ne", "katoda"}));
+ schema->addIdentity(std::nullopt, identityRef_{"mod", "food"});
+ schema->addIdentity(std::nullopt, identityRef_{"mod", "vehicle"});
+ schema->addIdentity(identityRef_{"mod", "food"}, identityRef_{"mod", "pizza"});
+ 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")});
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"))
@@ -76,5 +81,12 @@
expectedContextLength = 0;
}
+ SECTION("set mod:foodIdentRef ")
+ {
+ input = "set mod:foodIdentRef ";
+ expectedCompletions = {"mod:food", "mod:pizza", "mod:spaghetti", "pizza-module:hawaii"};
+ expectedContextLength = 0;
+ }
+
REQUIRE(parser.completeCommand(input, errorStream) == (Completions{expectedCompletions, expectedContextLength}));
}