Merge changes from topic "ci-coverage"
* changes:
CI: compare code coverage changes
CI: start building with coverage profiling
CI: only build docs once
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 519e2c3..0aec7e1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -75,6 +75,11 @@
)
target_link_libraries(path PUBLIC ast_values Boost::boost)
+add_library(leaf_data_type STATIC
+ src/leaf_data_type.cpp
+ )
+target_link_libraries(leaf_data_type ast_values)
+
add_library(utils STATIC
src/utils.cpp
)
@@ -84,7 +89,7 @@
src/static_schema.cpp
src/schema.cpp
)
-target_link_libraries(schemas PUBLIC path Boost::boost)
+target_link_libraries(schemas PUBLIC path leaf_data_type Boost::boost)
add_library(datastoreaccess STATIC
src/datastore_access.cpp
@@ -125,7 +130,6 @@
src/interpreter.cpp
src/ast_handlers.cpp
src/completion.cpp
- src/leaf_data.cpp
)
target_link_libraries(parser schemas utils ast_values)
@@ -274,12 +278,14 @@
cli_test(ls)
cli_test(presence_containers)
cli_test(leaf_editing)
+ target_link_libraries(test_leaf_editing leaf_data_type)
cli_test(yang)
target_link_libraries(test_yang yangschema)
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(list_manipulation)
cli_test(parser_methods)
cli_test(path_utils)
diff --git a/src/interpreter.cpp b/src/interpreter.cpp
index 5b13337..ca227be 100644
--- a/src/interpreter.cpp
+++ b/src/interpreter.cpp
@@ -95,10 +95,10 @@
auto leafType = m_datastore.schema()->leafType(path);
auto typedefName = m_datastore.schema()->leafTypeName(path);
std::string baseTypeStr;
- if (leafType == yang::LeafDataTypes::LeafRef) {
+ if (std::holds_alternative<yang::LeafRef>(leafType)) {
ss << "-> ";
ss << m_datastore.schema()->leafrefPath(path) << " ";
- baseTypeStr = leafDataTypeToString(m_datastore.schema()->leafrefBaseType(path));
+ baseTypeStr = leafDataTypeToString(m_datastore.schema()->leafType(std::get<yang::LeafRef>(leafType).m_targetXPath));
} else {
baseTypeStr = leafDataTypeToString(leafType);
}
diff --git a/src/leaf_data.cpp b/src/leaf_data.cpp
deleted file mode 100644
index 0d14fe3..0000000
--- a/src/leaf_data.cpp
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2020 CESNET, https://photonics.cesnet.cz/
- *
- * Written by Václav Kubernát <kubernat@cesnet.cz>
- *
-*/
-
-#include "leaf_data.hpp"
-template <>
-std::set<std::string> createSetSuggestions_class<yang::LeafDataTypes::Enum>::getSuggestions(const ParserContext& parserContext, const Schema& schema) const
-{
- return schema.enumValues(parserContext.m_tmpListKeyLeafPath.m_location, parserContext.m_tmpListKeyLeafPath.m_node);
-}
-
-template <>
-std::set<std::string> createSetSuggestions_class<yang::LeafDataTypes::IdentityRef>::getSuggestions(const ParserContext& parserContext, const Schema& schema) const
-{
- return schema.validIdentities(parserContext.m_tmpListKeyLeafPath.m_location, parserContext.m_tmpListKeyLeafPath.m_node, Prefixes::WhenNeeded);
-}
diff --git a/src/leaf_data.hpp b/src/leaf_data.hpp
index bbacbea..1c4176e 100644
--- a/src/leaf_data.hpp
+++ b/src/leaf_data.hpp
@@ -8,102 +8,34 @@
#pragma once
#include <boost/spirit/home/x3.hpp>
-#include "ast_values.hpp"
#include "ast_handlers.hpp"
#include "common_parsers.hpp"
+#include "leaf_data_type.hpp"
#include "schema.hpp"
namespace x3 = boost::spirit::x3;
-template <yang::LeafDataTypes TYPE>
+template <typename TYPE>
struct leaf_data_class;
-template <yang::LeafDataTypes TYPE>
-struct createSetSuggestions_class {
- std::set<std::string> getSuggestions(const ParserContext& ctx, const Schema& schema) const;
-
- template <typename T, typename Iterator, typename Context>
- void on_success(Iterator const& begin, Iterator const&, T&, Context const& context)
- {
- auto& parserContext = x3::get<parser_context_tag>(context);
- const Schema& schema = parserContext.m_schema;
-
- // Only generate completions if the type is correct so that we don't
- // overwrite some other completions.
- if (schema.leafType(parserContext.m_tmpListKeyLeafPath.m_location, parserContext.m_tmpListKeyLeafPath.m_node) == TYPE) {
- parserContext.m_completionIterator = begin;
- auto suggestions = getSuggestions(parserContext, schema);
- std::set<Completion> res;
- std::transform(suggestions.begin(), suggestions.end(), std::inserter(res, res.end()), [](auto it) { return Completion{it}; });
- parserContext.m_suggestions = res;
- }
- }
-};
-
-template <>
-struct leaf_data_class<yang::LeafDataTypes::Enum> {
- template <typename T, typename Iterator, typename Context>
- void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
- {
- if (_pass(context) == false)
- return;
- auto& parserContext = x3::get<parser_context_tag>(context);
- auto& schema = parserContext.m_schema;
-
- if (!schema.leafEnumHasValue(parserContext.m_tmpListKeyLeafPath.m_location, parserContext.m_tmpListKeyLeafPath.m_node, ast.m_value)) {
- _pass(context) = false;
- parserContext.m_errorMsg = "leaf data type mismatch: Expected an enum here. Allowed values:";
- for (const auto& it : schema.enumValues(parserContext.m_tmpListKeyLeafPath.m_location, parserContext.m_tmpListKeyLeafPath.m_node)) {
- parserContext.m_errorMsg += " " + it;
- }
- }
- }
-};
-
-template <>
-struct leaf_data_class<yang::LeafDataTypes::IdentityRef> {
- template <typename T, typename Iterator, typename Context>
- void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
- {
- auto& parserContext = x3::get<parser_context_tag>(context);
- auto& schema = parserContext.m_schema;
-
- ModuleValuePair pair;
- if (ast.m_prefix) {
- pair.first = ast.m_prefix.get().m_name;
- }
- pair.second = ast.m_value;
-
- if (!schema.leafIdentityIsValid(parserContext.m_tmpListKeyLeafPath.m_location, parserContext.m_tmpListKeyLeafPath.m_node, pair)) {
- _pass(context) = false;
- }
- }
-};
-
-x3::rule<leaf_data_class<yang::LeafDataTypes::Enum>, enum_> const leaf_data_enum = "leaf_data_enum";
-x3::rule<leaf_data_class<yang::LeafDataTypes::IdentityRef>, identityRef_> const leaf_data_identityRef = "leaf_data_identityRef";
-x3::rule<struct leaf_data_class<yang::LeafDataTypes::Binary>, binary_> const leaf_data_binary = "leaf_data_binary";
-x3::rule<struct leaf_data_class<yang::LeafDataTypes::Decimal>, double> const leaf_data_decimal = "leaf_data_decimal";
-x3::rule<struct leaf_data_class<yang::LeafDataTypes::String>, std::string> const leaf_data_string = "leaf_data_string";
+x3::rule<struct leaf_data_class<yang::Enum>, enum_> const leaf_data_enum = "leaf_data_enum";
+x3::rule<struct leaf_data_class<yang::IdentityRef>, identityRef_> const leaf_data_identityRef = "leaf_data_identityRef";
+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";
-x3::rule<createSetSuggestions_class<yang::LeafDataTypes::Enum>, x3::unused_type> const createEnumSuggestions = "createEnumSuggestions";
-x3::rule<createSetSuggestions_class<yang::LeafDataTypes::IdentityRef>, x3::unused_type> const createIdentitySuggestions = "createIdentitySuggestions";
-
using x3::char_;
-auto const createEnumSuggestions_def =
- x3::eps;
-
auto const leaf_data_enum_def =
- createEnumSuggestions >> +char_;
+ +char_;
struct bool_symbol_table : x3::symbols<bool> {
bool_symbol_table()
{
- add
- ("true", true)
- ("false", false);
+ add
+ ("true", true)
+ ("false", false);
}
} const bool_symbols;
@@ -124,11 +56,130 @@
auto const leaf_data_identityRef_data_def =
-module >> node_identifier;
-auto const createIdentitySuggestions_def =
- x3::eps;
-
+// TODO: get rid of this and use leaf_data_identityRef_data directly
auto const leaf_data_identityRef_def =
- createIdentitySuggestions >> leaf_data_identityRef_data;
+ leaf_data_identityRef_data;
+
+template <typename It, typename Ctx, typename RCtx, typename Attr>
+struct impl_LeafData {
+ It& first;
+ It last;
+ Ctx const& ctx;
+ RCtx& rctx;
+ Attr& attr;
+ ParserContext& parserContext;
+
+ bool operator()(const yang::Binary&) const
+ {
+ return leaf_data_binary.parse(first, last, ctx, rctx, attr);
+ }
+ bool operator()(const yang::Bool&) const
+ {
+ return bool_symbols.parse(first, last, ctx, rctx, attr);
+ }
+ bool operator()(const yang::Decimal&) const
+ {
+ return x3::double_.parse(first, last, ctx, rctx, attr);
+ }
+ bool operator()(const yang::Uint8&) const
+ {
+ return x3::uint8.parse(first, last, ctx, rctx, attr);
+ }
+ bool operator()(const yang::Uint16&) const
+ {
+ return x3::uint16.parse(first, last, ctx, rctx, attr);
+ }
+ bool operator()(const yang::Uint32&) const
+ {
+ return x3::uint32.parse(first, last, ctx, rctx, attr);
+ }
+ bool operator()(const yang::Uint64&) const
+ {
+ return x3::uint64.parse(first, last, ctx, rctx, attr);
+ }
+ bool operator()(const yang::Int8&) const
+ {
+ return x3::int8.parse(first, last, ctx, rctx, attr);
+ }
+ bool operator()(const yang::Int16&) const
+ {
+ return x3::int16.parse(first, last, ctx, rctx, attr);
+ }
+ bool operator()(const yang::Int32&) const
+ {
+ return x3::int32.parse(first, last, ctx, rctx, attr);
+ }
+ bool operator()(const yang::Int64&) const
+ {
+ return x3::int64.parse(first, last, ctx, rctx, attr);
+ }
+ bool operator()(const yang::String&) const
+ {
+ return leaf_data_string.parse(first, last, ctx, rctx, attr);
+ }
+ template <typename Type>
+ void createSetSuggestions(const Type& type) const
+ {
+ parserContext.m_suggestions.clear();
+ 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}; });
+ 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;
+ }
+ }
+ return isValidEnum;
+ }
+ 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;
+ }
+ bool operator()(const yang::LeafRef& leafRef) const
+ {
+ return std::visit(*this, *leafRef.m_targetType);
+ }
+ bool operator()(const yang::Union& unionInfo) const
+ {
+ return std::any_of(unionInfo.m_unionTypes.begin(), unionInfo.m_unionTypes.end(), [this](const auto& type) {
+ return std::visit(*this, type);
+ });
+ }
+};
struct LeafData : x3::parser<LeafData> {
using attribute_type = leaf_data_;
@@ -141,43 +192,7 @@
const Schema& schema = parserContext.m_schema;
auto type = schema.leafType(parserContext.m_tmpListKeyLeafPath.m_location, parserContext.m_tmpListKeyLeafPath.m_node);
- std::function<bool(yang::LeafDataTypes)> parse_impl = [&](auto type) {
- switch (type) {
- case yang::LeafDataTypes::Binary:
- return leaf_data_binary.parse(first, last, ctx, rctx, attr);
- case yang::LeafDataTypes::Bool:
- return bool_symbols.parse(first, last, ctx, rctx, attr);
- case yang::LeafDataTypes::Decimal:
- return x3::double_.parse(first, last, ctx, rctx, attr);
- case yang::LeafDataTypes::Uint8:
- return x3::uint8.parse(first, last, ctx, rctx, attr);
- case yang::LeafDataTypes::Uint16:
- return x3::uint16.parse(first, last, ctx, rctx, attr);
- case yang::LeafDataTypes::Uint32:
- return x3::uint32.parse(first, last, ctx, rctx, attr);
- case yang::LeafDataTypes::Uint64:
- return x3::uint64.parse(first, last, ctx, rctx, attr);
- case yang::LeafDataTypes::Int8:
- return x3::int8.parse(first, last, ctx, rctx, attr);
- case yang::LeafDataTypes::Int16:
- return x3::int16.parse(first, last, ctx, rctx, attr);
- case yang::LeafDataTypes::Int32:
- return x3::int32.parse(first, last, ctx, rctx, attr);
- case yang::LeafDataTypes::Int64:
- return x3::int64.parse(first, last, ctx, rctx, attr);
- case yang::LeafDataTypes::String:
- return leaf_data_string.parse(first, last, ctx, rctx, attr);
- case yang::LeafDataTypes::Enum:
- return leaf_data_enum.parse(first, last, ctx, rctx, attr);
- case yang::LeafDataTypes::IdentityRef:
- return leaf_data_identityRef.parse(first, last, ctx, rctx, attr);
- case yang::LeafDataTypes::LeafRef:
- auto actualType = schema.leafrefBaseType(parserContext.m_tmpListKeyLeafPath.m_location, parserContext.m_tmpListKeyLeafPath.m_node);
- return parse_impl(actualType);
- }
- __builtin_unreachable();
- };
- auto pass = parse_impl(type);
+ auto pass = std::visit(impl_LeafData<It, Ctx, RCtx, Attr>{first, last, ctx, rctx, attr, parserContext}, type);
if (!pass) {
if (parserContext.m_errorMsg.empty()) {
@@ -197,5 +212,3 @@
BOOST_SPIRIT_DEFINE(leaf_data_binary)
BOOST_SPIRIT_DEFINE(leaf_data_identityRef_data)
BOOST_SPIRIT_DEFINE(leaf_data_identityRef)
-BOOST_SPIRIT_DEFINE(createEnumSuggestions)
-BOOST_SPIRIT_DEFINE(createIdentitySuggestions)
diff --git a/src/leaf_data_type.cpp b/src/leaf_data_type.cpp
new file mode 100644
index 0000000..8048efa
--- /dev/null
+++ b/src/leaf_data_type.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2020 CESNET, https://photonics.cesnet.cz/
+ *
+ * Written by Václav Kubernát <kubernat@cesnet.cz>
+ *
+*/
+#include "ast_values.hpp"
+#include "leaf_data_type.hpp"
+
+namespace yang {
+Enum::Enum(std::set<enum_>&& values)
+ : m_allowedValues(std::move(values))
+{
+}
+bool Enum::operator==(const Enum& other) const
+{
+ return this->m_allowedValues == other.m_allowedValues;
+}
+IdentityRef::IdentityRef(std::set<identityRef_>&& values)
+ : m_allowedValues(std::move(values))
+{
+}
+bool IdentityRef::operator==(const IdentityRef& other) const
+{
+ return this->m_allowedValues == other.m_allowedValues;
+}
+// Copy constructor needed, because unique_ptr is not copy-constructible
+LeafRef::LeafRef(const LeafRef& src)
+ : m_targetXPath(src.m_targetXPath)
+ , m_targetType(std::make_unique<LeafDataType>(*src.m_targetType))
+{
+}
+LeafRef::LeafRef(const std::string& xpath, std::unique_ptr<LeafDataType>&& type)
+ : m_targetXPath(xpath)
+ , m_targetType(std::move(type))
+{
+}
+bool LeafRef::operator==(const LeafRef& other) const
+{
+ return this->m_targetXPath == other.m_targetXPath && *this->m_targetType == *other.m_targetType;
+}
+bool Union::operator==(const Union& other) const
+{
+ return this->m_unionTypes == other.m_unionTypes;
+}
+bool String::operator==(const String&) const
+{
+ return true;
+}
+bool Decimal::operator==(const Decimal&) const
+{
+ return true;
+}
+bool Bool::operator==(const Bool&) const
+{
+ return true;
+}
+bool Int8::operator==(const Int8&) const
+{
+ return true;
+}
+bool Uint8::operator==(const Uint8&) const
+{
+ return true;
+}
+bool Int16::operator==(const Int16&) const
+{
+ return true;
+}
+bool Uint16::operator==(const Uint16&) const
+{
+ return true;
+}
+bool Int32::operator==(const Int32&) const
+{
+ return true;
+}
+bool Uint32::operator==(const Uint32&) const
+{
+ return true;
+}
+bool Int64::operator==(const Int64&) const
+{
+ return true;
+}
+bool Uint64::operator==(const Uint64&) const
+{
+ return true;
+}
+bool Binary::operator==(const Binary&) const
+{
+ return true;
+}
+}
diff --git a/src/leaf_data_type.hpp b/src/leaf_data_type.hpp
new file mode 100644
index 0000000..a86691b
--- /dev/null
+++ b/src/leaf_data_type.hpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2020 CESNET, https://photonics.cesnet.cz/
+ *
+ * Written by Václav Kubernát <kubernat@cesnet.cz>
+ *
+*/
+
+#pragma once
+#include <memory>
+#include <set>
+#include <string>
+#include <variant>
+#include <vector>
+
+struct enum_;
+struct identityRef_;
+
+namespace yang {
+struct String {
+ bool operator==(const String&) const;
+};
+struct Decimal {
+ bool operator==(const Decimal&) const;
+};
+struct Bool {
+ bool operator==(const Bool&) const;
+};
+struct Int8 {
+ bool operator==(const Int8&) const;
+};
+struct Uint8 {
+ bool operator==(const Uint8&) const;
+};
+struct Int16 {
+ bool operator==(const Int16&) const;
+};
+struct Uint16 {
+ bool operator==(const Uint16&) const;
+};
+struct Int32 {
+ bool operator==(const Int32&) const;
+};
+struct Uint32 {
+ bool operator==(const Uint32&) const;
+};
+struct Int64 {
+ bool operator==(const Int64&) const;
+};
+struct Uint64 {
+ bool operator==(const Uint64&) const;
+};
+struct Binary {
+ bool operator==(const Binary&) const;
+};
+struct Enum {
+ Enum(std::set<enum_>&& values);
+ bool operator==(const Enum& other) const;
+ std::set<enum_> m_allowedValues;
+};
+struct IdentityRef {
+ IdentityRef(std::set<identityRef_>&& list);
+ bool operator==(const IdentityRef& other) const;
+ std::set<identityRef_> m_allowedValues;
+};
+struct LeafRef;
+struct Union;
+using LeafDataType = std::variant<
+ yang::String,
+ yang::Decimal,
+ yang::Bool,
+ yang::Int8,
+ yang::Uint8,
+ yang::Int16,
+ yang::Uint16,
+ yang::Int32,
+ yang::Uint32,
+ yang::Int64,
+ yang::Uint64,
+ yang::Enum,
+ yang::Binary,
+ yang::IdentityRef,
+ yang::LeafRef,
+ yang::Union
+>;
+struct LeafRef {
+ LeafRef(const LeafRef& src);
+ LeafRef(const std::string& xpath, std::unique_ptr<LeafDataType>&& type);
+ bool operator==(const LeafRef& other) const;
+ std::string m_targetXPath;
+ std::unique_ptr<LeafDataType> m_targetType;
+};
+
+struct Union {
+ bool operator==(const Union& other) const;
+ std::vector<LeafDataType> m_unionTypes;
+};
+}
diff --git a/src/parser_context.hpp b/src/parser_context.hpp
index 3ad0179..f837934 100644
--- a/src/parser_context.hpp
+++ b/src/parser_context.hpp
@@ -31,6 +31,7 @@
schemaPath_ m_location;
ModuleNodePair m_node;
} m_tmpListKeyLeafPath;
+
std::map<std::string, leaf_data_> m_tmpListKeys;
bool m_errorHandled = false;
bool m_completing = false;
diff --git a/src/schema.hpp b/src/schema.hpp
index ea0deba..9a86045 100644
--- a/src/schema.hpp
+++ b/src/schema.hpp
@@ -1,4 +1,3 @@
-
/*
* Copyright (C) 2018 CESNET, https://photonics.cesnet.cz/
* Copyright (C) 2018 FIT CVUT, https://fit.cvut.cz/
@@ -14,28 +13,11 @@
#include <stdexcept>
#include <unordered_map>
#include "ast_path.hpp"
+#include "leaf_data_type.hpp"
using ModuleValuePair = std::pair<boost::optional<std::string>, std::string>;
namespace yang {
-enum class LeafDataTypes {
- String,
- Decimal,
- Bool,
- Int8,
- Uint8,
- Int16,
- Uint16,
- Int32,
- Uint32,
- Int64,
- Uint64,
- Enum,
- Binary,
- IdentityRef,
- LeafRef,
-};
-
enum class NodeTypes {
Container,
PresenceContainer,
@@ -70,22 +52,16 @@
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 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;
virtual bool leafIsKey(const std::string& leafPath) const = 0;
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 leafType(const std::string& path) const = 0;
+ virtual yang::LeafDataType leafType(const schemaPath_& location, const ModuleNodePair& node) const = 0;
+ virtual yang::LeafDataType leafType(const std::string& path) const = 0;
virtual std::optional<std::string> leafTypeName(const std::string& path) const = 0;
- virtual yang::LeafDataTypes leafrefBaseType(const schemaPath_& location, const ModuleNodePair& node) const = 0;
- virtual yang::LeafDataTypes leafrefBaseType(const std::string& path) const = 0;
virtual std::string leafrefPath(const std::string& leafrefPath) 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;
virtual std::set<std::string> childNodes(const schemaPath_& path, const Recursion recursion) const = 0;
virtual std::set<std::string> moduleNodes(const module_& module, const Recursion recursion) const = 0;
};
diff --git a/src/static_schema.cpp b/src/static_schema.cpp
index 87d190a..3eb42f6 100644
--- a/src/static_schema.cpp
+++ b/src/static_schema.cpp
@@ -71,40 +71,22 @@
m_nodes.emplace(key, std::unordered_map<std::string, NodeType>());
}
-void StaticSchema::addLeaf(const std::string& location, const std::string& name, const yang::LeafDataTypes& type)
+std::set<identityRef_> StaticSchema::validIdentities(std::string_view module, std::string_view value)
{
- m_nodes.at(location).emplace(name, yang::leaf{type, {}, {}, {}});
- std::string key = joinPaths(location, name);
- m_nodes.emplace(key, std::unordered_map<std::string, NodeType>());
+ std::set<ModuleValuePair> identities;
+ getIdentSet(ModuleNodePair{boost::optional<std::string>{module}, value}, identities);
+ std::set<identityRef_> res;
+
+ std::transform(identities.begin(), identities.end(), std::inserter(res, res.end()), [](const auto& identity) {
+ return identityRef_{*identity.first, identity.second};
+ });
+
+ return res;
}
-void StaticSchema::addLeafEnum(const std::string& location, const std::string& name, std::set<std::string> enumValues)
+void StaticSchema::addLeaf(const std::string& location, const std::string& name, const yang::LeafDataType& type)
{
- yang::leaf toAdd;
- toAdd.m_type = yang::LeafDataTypes::Enum;
- toAdd.m_enumValues = enumValues;
- m_nodes.at(location).emplace(name, toAdd);
- std::string key = joinPaths(location, name);
- m_nodes.emplace(key, std::unordered_map<std::string, NodeType>());
-}
-
-void StaticSchema::addLeafIdentityRef(const std::string& location, const std::string& name, const ModuleValuePair& base)
-{
- assert(base.first); // base identity cannot have an empty module
- yang::leaf toAdd;
- toAdd.m_type = yang::LeafDataTypes::IdentityRef;
- toAdd.m_identBase = base;
- m_nodes.at(location).emplace(name, toAdd);
- std::string key = joinPaths(location, name);
- m_nodes.emplace(key, std::unordered_map<std::string, NodeType>());
-}
-
-void StaticSchema::addLeafRef(const std::string& location, const std::string& name, const std::string& source)
-{
- yang::leaf toAdd;
- toAdd.m_type = yang::LeafDataTypes::LeafRef;
- toAdd.m_leafRefSource = source;
- m_nodes.at(location).emplace(name, toAdd);
+ m_nodes.at(location).emplace(name, yang::leaf{type});
std::string key = joinPaths(location, name);
m_nodes.emplace(key, std::unordered_map<std::string, NodeType>());
}
@@ -122,12 +104,6 @@
m_identities.emplace(name, std::set<ModuleValuePair>());
}
-bool StaticSchema::leafEnumHasValue(const schemaPath_& location, const ModuleNodePair& node, const std::string& value) const
-{
- auto enums = enumValues(location, node);
- return enums.find(value) != enums.end();
-}
-
void StaticSchema::getIdentSet(const ModuleValuePair& ident, std::set<ModuleValuePair>& res) const
{
res.insert(ident);
@@ -137,86 +113,26 @@
}
}
-const std::set<std::string> StaticSchema::validIdentities(const schemaPath_& location, const ModuleNodePair& node, const Prefixes prefixes) const
-{
- std::string locationString = pathToSchemaString(location, Prefixes::Always);
- assert(isLeaf(location, node));
-
- const auto& child = children(locationString).at(fullNodeName(location, node));
- const auto& leaf = boost::get<yang::leaf>(child);
-
- std::set<ModuleValuePair> identSet;
- getIdentSet(leaf.m_identBase, identSet);
-
- std::set<std::string> res;
- std::transform(identSet.begin(), identSet.end(), std::inserter(res, res.end()), [location, node, prefixes](const auto& it) {
- auto topLevelModule = location.m_nodes.empty() ? node.first.get() : location.m_nodes.front().m_prefix.get().m_name;
- std::string stringIdent;
- if (prefixes == Prefixes::Always || (it.first && it.first.value() != topLevelModule)) {
- stringIdent += it.first ? it.first.value() : topLevelModule;
- stringIdent += ":";
- }
- stringIdent += it.second;
- return stringIdent;
- });
-
- return res;
-}
-
-bool StaticSchema::leafIdentityIsValid(const schemaPath_& location, const ModuleNodePair& node, const ModuleValuePair& value) const
-{
- auto identities = validIdentities(location, node, Prefixes::Always);
-
- auto topLevelModule = location.m_nodes.empty() ? node.first.get() : location.m_nodes.front().m_prefix.get().m_name;
- auto identModule = value.first ? value.first.value() : topLevelModule;
- return std::any_of(identities.begin(), identities.end(), [toFind = identModule + ":" + value.second](const auto& x) { return x == toFind; });
-}
-
std::string lastNodeOfSchemaPath(const std::string& path)
{
std::string res = path;
- auto pos = res.find_last_of('/');
- if (pos == 0) { // path had only one path fragment - "/something:something"
- res.erase(0, 1);
- return res;
+ if (auto pos = res.find_last_of('/'); pos != res.npos) {
+ res.erase(0, pos + 1);
}
- if (pos != res.npos) { // path had more fragments
- res.erase(0, pos);
- return res;
- }
-
- // path was empty
return res;
}
-yang::LeafDataTypes StaticSchema::leafrefBaseType(const schemaPath_& location, const ModuleNodePair& node) const
-{
- std::string locationString = pathToSchemaString(location, Prefixes::Always);
- auto leaf{boost::get<yang::leaf>(children(locationString).at(fullNodeName(location, node)))};
- auto locationOfSource = stripLastNodeFromPath(leaf.m_leafRefSource);
- auto nameOfSource = lastNodeOfSchemaPath(leaf.m_leafRefSource);
- return boost::get<yang::leaf>(children(locationOfSource).at(nameOfSource)).m_type;
-}
-
-yang::LeafDataTypes StaticSchema::leafType(const schemaPath_& location, const ModuleNodePair& node) const
+yang::LeafDataType StaticSchema::leafType(const schemaPath_& location, const ModuleNodePair& node) const
{
std::string locationString = pathToSchemaString(location, Prefixes::Always);
return boost::get<yang::leaf>(children(locationString).at(fullNodeName(location, node))).m_type;
}
-yang::LeafDataTypes StaticSchema::leafType([[maybe_unused]] const std::string& path) const
+yang::LeafDataType StaticSchema::leafType(const std::string& path) const
{
- throw std::runtime_error{"StaticSchema::leafType not implemented"};
-}
-
-const std::set<std::string> StaticSchema::enumValues(const schemaPath_& location, const ModuleNodePair& node) const
-{
- std::string locationString = pathToSchemaString(location, Prefixes::Always);
- assert(isLeaf(location, node));
-
- const auto& child = children(locationString).at(fullNodeName(location, node));
- const auto& leaf = boost::get<yang::leaf>(child);
- return leaf.m_enumValues;
+ auto locationString = stripLastNodeFromPath(path);
+ auto node = lastNodeOfSchemaPath(path);
+ return boost::get<yang::leaf>(children(locationString).at(node)).m_type;
}
// We do not test StaticSchema, so we don't need to implement recursive childNodes
@@ -291,11 +207,6 @@
throw std::runtime_error{"Internal error: StaticSchema::nodeType(std::string) not implemented. The tests should not have called this overload."};
}
-yang::LeafDataTypes StaticSchema::leafrefBaseType([[maybe_unused]] const std::string& path) const
-{
- throw std::runtime_error{"Internal error: StaticSchema::leafrefBaseType(std::string) not implemented. The tests should not have called this overload."};
-}
-
std::string StaticSchema::leafrefPath([[maybe_unused]] const std::string& leafrefPath) const
{
throw std::runtime_error{"Internal error: StaticSchema::leafrefPath(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 97f1e7e..a94c78d 100644
--- a/src/static_schema.hpp
+++ b/src/static_schema.hpp
@@ -27,10 +27,7 @@
};
struct leaf {
- yang::LeafDataTypes m_type;
- std::set<std::string> m_enumValues;
- ModuleValuePair m_identBase;
- std::string m_leafRefSource;
+ yang::LeafDataType m_type;
};
struct module {
@@ -51,29 +48,24 @@
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 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;
bool leafIsKey(const std::string& leafPath) const override;
const std::set<std::string> listKeys(const schemaPath_& location, const ModuleNodePair& node) const override;
- yang::LeafDataTypes leafType(const schemaPath_& location, const ModuleNodePair& node) const override;
- yang::LeafDataTypes leafType(const std::string& path) const override;
+ yang::LeafDataType leafType(const schemaPath_& location, const ModuleNodePair& node) const override;
+ yang::LeafDataType leafType(const std::string& path) const override;
std::optional<std::string> leafTypeName(const std::string& path) const override;
- yang::LeafDataTypes leafrefBaseType(const schemaPath_& location, const ModuleNodePair& node) const override;
- yang::LeafDataTypes leafrefBaseType(const std::string& path) const override;
std::string leafrefPath(const std::string& leafrefPath) const override;
- const std::set<std::string> enumValues(const schemaPath_& location, const ModuleNodePair& node) const override;
- 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;
+ /** A helper for making tests a little bit easier. It returns all
+ * identities which are based on the argument passed and which can then be
+ * used in addLeaf for the `type` argument */
+ std::set<identityRef_> validIdentities(std::string_view module, std::string_view value);
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);
- void addLeafEnum(const std::string& location, const std::string& name, std::set<std::string> enumValues);
- void addLeafIdentityRef(const std::string& location, const std::string& name, const ModuleValuePair& base);
- void addLeafRef(const std::string& location, const std::string& name, const std::string& source);
+ 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);
@@ -85,5 +77,7 @@
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;
};
diff --git a/src/utils.cpp b/src/utils.cpp
index fcbe0d0..31854b2 100644
--- a/src/utils.cpp
+++ b/src/utils.cpp
@@ -5,6 +5,7 @@
* Written by Václav Kubernát <kubervac@fit.cvut.cz>
*
*/
+#include <experimental/iterator>
#include <sstream>
#include "completion.hpp"
#include "utils.hpp"
@@ -52,42 +53,80 @@
return schemaPath_{path.m_scope, decltype(schemaPath_::m_nodes)(path.m_nodes.begin(), path.m_nodes.end() - 1)};
}
-std::string leafDataTypeToString(yang::LeafDataTypes type)
-{
- switch (type) {
- case yang::LeafDataTypes::String:
+struct impl_leafDataTypeToString {
+ std::string operator()(const yang::String)
+ {
return "a string";
- case yang::LeafDataTypes::Decimal:
- return "a decimal";
- case yang::LeafDataTypes::Bool:
- return "a boolean";
- case yang::LeafDataTypes::Int8:
- return "an 8-bit integer";
- case yang::LeafDataTypes::Uint8:
- return "an 8-bit unsigned integer";
- case yang::LeafDataTypes::Int16:
- return "a 16-bit integer";
- case yang::LeafDataTypes::Uint16:
- return "a 16-bit unsigned integer";
- case yang::LeafDataTypes::Int32:
- return "a 32-bit integer";
- case yang::LeafDataTypes::Uint32:
- return "a 32-bit unsigned integer";
- case yang::LeafDataTypes::Int64:
- return "a 64-bit integer";
- case yang::LeafDataTypes::Uint64:
- return "a 64-bit unsigned integer";
- case yang::LeafDataTypes::Enum:
- return "an enum";
- case yang::LeafDataTypes::IdentityRef:
- return "an identity";
- case yang::LeafDataTypes::LeafRef:
- return "a leafref";
- case yang::LeafDataTypes::Binary:
- return "a base64-encoded binary value";
- default:
- throw std::runtime_error("leafDataTypeToString: unsupported leaf data type");
}
+ std::string operator()(const yang::Decimal)
+ {
+ return "a decimal";
+ }
+ std::string operator()(const yang::Bool)
+ {
+ return "a boolean";
+ }
+ std::string operator()(const yang::Int8)
+ {
+ return "an 8-bit integer";
+ }
+ std::string operator()(const yang::Uint8)
+ {
+ return "an 8-bit unsigned integer";
+ }
+ std::string operator()(const yang::Int16)
+ {
+ return "a 16-bit integer";
+ }
+ std::string operator()(const yang::Uint16)
+ {
+ return "a 16-bit unsigned integer";
+ }
+ std::string operator()(const yang::Int32)
+ {
+ return "a 32-bit integer";
+ }
+ std::string operator()(const yang::Uint32)
+ {
+ return "a 32-bit unsigned integer";
+ }
+ std::string operator()(const yang::Int64)
+ {
+ return "a 64-bit integer";
+ }
+ std::string operator()(const yang::Uint64)
+ {
+ return "a 64-bit unsigned integer";
+ }
+ std::string operator()(const yang::Binary)
+ {
+ return "a base64-encoded binary value";
+ }
+ std::string operator()(const yang::Enum&)
+ {
+ return "an enum";
+ }
+ std::string operator()(const yang::IdentityRef&)
+ {
+ return "an identity";
+ }
+ std::string operator()(const yang::LeafRef&)
+ {
+ return "a leafref";
+ }
+ std::string operator()(const yang::Union& type)
+ {
+ std::ostringstream ss;
+ std::transform(type.m_unionTypes.begin(), type.m_unionTypes.end(), std::experimental::make_ostream_joiner(ss, ", "), [this](const auto& unionType) {
+ return std::visit(*this, unionType);
+ });
+ return ss.str();
+ }
+};
+
+std::string leafDataTypeToString(const yang::LeafDataType& type)
+{
+ return std::visit(impl_leafDataTypeToString{}, type);
}
std::string fullNodeName(const schemaPath_& location, const ModuleNodePair& pair)
diff --git a/src/utils.hpp b/src/utils.hpp
index f0f7ae5..2f93bfb 100644
--- a/src/utils.hpp
+++ b/src/utils.hpp
@@ -17,7 +17,7 @@
std::string stripLastNodeFromPath(const std::string& path);
schemaPath_ pathWithoutLastNode(const schemaPath_& path);
dataPath_ pathWithoutLastNode(const dataPath_& path);
-std::string leafDataTypeToString(yang::LeafDataTypes type);
+std::string leafDataTypeToString(const yang::LeafDataType& type);
std::string fullNodeName(const schemaPath_& location, const ModuleNodePair& pair);
std::string fullNodeName(const dataPath_& location, const ModuleNodePair& pair);
std::string leafDataToString(const leaf_data_ value);
diff --git a/src/yang_schema.cpp b/src/yang_schema.cpp
index e18c780..a453b50 100644
--- a/src/yang_schema.cpp
+++ b/src/yang_schema.cpp
@@ -93,80 +93,6 @@
return set.find(name) != set.end();
}
-bool YangSchema::leafEnumHasValue(const schemaPath_& location, const ModuleNodePair& node, const std::string& value) const
-{
- auto enums = enumValues(location, node);
-
- return std::any_of(enums.begin(), enums.end(), [=](const auto& x) { return x == value; });
-}
-
-const std::set<std::string> YangSchema::enumValues(const schemaPath_& location, const ModuleNodePair& node) const
-{
- if (!isLeaf(location, node) || leafType(location, node) != yang::LeafDataTypes::Enum)
- return {};
-
- libyang::Schema_Node_Leaf leaf(getSchemaNode(location, node));
- auto type = leaf.type();
- auto enm = type->info()->enums()->enm();
- // The enum can be a derived type and enm() only returns values,
- // if that specific typedef changed the possible values. So we go
- // up the hierarchy until we find a typedef that defined these values.
- while (enm.empty()) {
- type = type->der()->type();
- enm = type->info()->enums()->enm();
- }
-
- std::vector<libyang::S_Type_Enum> enabled;
- std::copy_if(enm.begin(), enm.end(), std::back_inserter(enabled), [](const libyang::S_Type_Enum& it) {
- auto iffeatures = it->iffeature();
- return std::all_of(iffeatures.begin(), iffeatures.end(), [](auto it) { return it->value(); });
- });
-
- std::set<std::string> enumSet;
- std::transform(enabled.begin(), enabled.end(), std::inserter(enumSet, enumSet.end()), [](auto it) { return it->name(); });
- return enumSet;
-}
-
-const std::set<std::string> YangSchema::validIdentities(const schemaPath_& location, const ModuleNodePair& node, const Prefixes prefixes) const
-{
- if (!isLeaf(location, node) || leafType(location, node) != yang::LeafDataTypes::IdentityRef)
- return {};
-
- std::set<std::string> identSet;
-
- auto topLevelModule = location.m_nodes.empty() ? node.first.get() : location.m_nodes.front().m_prefix.get().m_name;
- auto insertToSet = [&identSet, prefixes, topLevelModule](auto module, auto name) {
- std::string stringIdent;
- if (prefixes == Prefixes::Always || topLevelModule != module) {
- stringIdent += module;
- stringIdent += ":";
- }
- stringIdent += name;
- identSet.emplace(stringIdent);
- };
-
- auto leaf = std::make_shared<libyang::Schema_Node_Leaf>(getSchemaNode(location, node));
- auto info = leaf->type()->info();
- for (auto base : info->ident()->ref()) { // Iterate over all bases
- insertToSet(base->module()->name(), base->name());
- // Iterate over derived identities (this is recursive!)
- for (auto derived : base->der()->schema()) {
- insertToSet(derived->module()->name(), derived->name());
- }
- }
-
- return identSet;
-}
-
-bool YangSchema::leafIdentityIsValid(const schemaPath_& location, const ModuleNodePair& node, const ModuleValuePair& value) const
-{
- auto identities = validIdentities(location, node, Prefixes::Always);
-
- auto topLevelModule = location.m_nodes.empty() ? node.first.get() : location.m_nodes.front().m_prefix.get().m_name;
- auto identModule = value.first ? value.first.value() : topLevelModule;
- return std::any_of(identities.begin(), identities.end(), [toFind = identModule + ":" + value.second](const auto& x) { return x == toFind; });
-}
-
bool YangSchema::listHasKey(const schemaPath_& location, const ModuleNodePair& node, const std::string& key) const
{
if (!isList(location, node))
@@ -227,65 +153,113 @@
return keys;
}
-yang::LeafDataTypes lyTypeToLeafDataTypes(LY_DATA_TYPE type)
+namespace {
+std::set<enum_> enumValues(const libyang::S_Type& typeArg)
{
- switch (type) {
- case LY_TYPE_STRING:
- return yang::LeafDataTypes::String;
- case LY_TYPE_DEC64:
- return yang::LeafDataTypes::Decimal;
- case LY_TYPE_BOOL:
- return yang::LeafDataTypes::Bool;
- case LY_TYPE_INT8:
- return yang::LeafDataTypes::Int8;
- case LY_TYPE_INT16:
- return yang::LeafDataTypes::Int16;
- case LY_TYPE_INT32:
- return yang::LeafDataTypes::Int32;
- case LY_TYPE_INT64:
- return yang::LeafDataTypes::Int64;
- case LY_TYPE_UINT8:
- return yang::LeafDataTypes::Uint8;
- case LY_TYPE_UINT16:
- return yang::LeafDataTypes::Uint16;
- case LY_TYPE_UINT32:
- return yang::LeafDataTypes::Uint32;
- case LY_TYPE_UINT64:
- return yang::LeafDataTypes::Uint64;
- case LY_TYPE_ENUM:
- return yang::LeafDataTypes::Enum;
- case LY_TYPE_BINARY:
- return yang::LeafDataTypes::Binary;
- case LY_TYPE_IDENT:
- return yang::LeafDataTypes::IdentityRef;
- case LY_TYPE_LEAFREF:
- return yang::LeafDataTypes::LeafRef;
- default:
- using namespace std::string_literals;
- throw std::logic_error{"internal error: unsupported libyang data type "s + std::to_string(type)};
+ auto type = typeArg;
+ auto enm = type->info()->enums()->enm();
+ // The enum can be a derived type and enm() only returns values,
+ // if that specific typedef changed the possible values. So we go
+ // up the hierarchy until we find a typedef that defined these values.
+ while (enm.empty()) {
+ type = type->der()->type();
+ enm = type->info()->enums()->enm();
}
+
+ std::vector<libyang::S_Type_Enum> enabled;
+ std::copy_if(enm.begin(), enm.end(), std::back_inserter(enabled), [](const libyang::S_Type_Enum& it) {
+ auto iffeatures = it->iffeature();
+ return std::all_of(iffeatures.begin(), iffeatures.end(), [](auto it) { return it->value(); });
+ });
+
+ std::set<enum_> enumSet;
+ std::transform(enabled.begin(), enabled.end(), std::inserter(enumSet, enumSet.end()), [](auto it) { return enum_{it->name()}; });
+ return enumSet;
}
-namespace {
-yang::LeafDataTypes impl_leafType(const libyang::S_Schema_Node& node)
+std::set<identityRef_> validIdentities(const libyang::S_Type& type)
+{
+ std::set<identityRef_> identSet;
+
+ // auto topLevelModule = leaf->module();
+
+ auto info = type->info();
+ for (auto base : info->ident()->ref()) { // Iterate over all bases
+ identSet.emplace(base->module()->name(), base->name());
+ // Iterate over derived identities (this is recursive!)
+ for (auto derived : base->der()->schema()) {
+ identSet.emplace(derived->module()->name(), derived->name());
+ }
+ }
+
+ return identSet;
+}
+
+std::string leafrefPath(const libyang::S_Type& type)
+{
+ return type->info()->lref()->target()->path(LYS_PATH_FIRST_PREFIX);
+}
+}
+
+yang::LeafDataType YangSchema::impl_leafType(const libyang::S_Schema_Node& node) const
{
using namespace std::string_literals;
- libyang::Schema_Node_Leaf leaf(node);
- auto baseType{leaf.type()->base()};
- try {
- return lyTypeToLeafDataTypes(baseType);
- } catch (std::logic_error& ex) {
- throw UnsupportedYangTypeException("the type of "s + node->name() + " is not supported: " + ex.what());
- }
-}
+ auto leaf = std::make_shared<libyang::Schema_Node_Leaf>(node);
+ std::function<yang::LeafDataType(std::shared_ptr<libyang::Type>)> resolveType;
+ resolveType = [this, &resolveType, leaf] (auto type) -> yang::LeafDataType {
+ switch (type->base()) {
+ case LY_TYPE_STRING:
+ return yang::String{};
+ case LY_TYPE_DEC64:
+ return yang::Decimal{};
+ case LY_TYPE_BOOL:
+ return yang::Bool{};
+ case LY_TYPE_INT8:
+ return yang::Int8{};
+ case LY_TYPE_INT16:
+ return yang::Int16{};
+ case LY_TYPE_INT32:
+ return yang::Int32{};
+ case LY_TYPE_INT64:
+ return yang::Int64{};
+ case LY_TYPE_UINT8:
+ return yang::Uint8{};
+ case LY_TYPE_UINT16:
+ return yang::Uint16{};
+ case LY_TYPE_UINT32:
+ return yang::Uint32{};
+ case LY_TYPE_UINT64:
+ return yang::Uint64{};
+ case LY_TYPE_BINARY:
+ return yang::Binary{};
+ case LY_TYPE_ENUM:
+ return yang::Enum{enumValues(type)};
+ case LY_TYPE_IDENT:
+ return yang::IdentityRef{validIdentities(type)};
+ case LY_TYPE_LEAFREF:
+ return yang::LeafRef{::leafrefPath(type), std::make_unique<yang::LeafDataType>(leafType(::leafrefPath(type)))};
+ case LY_TYPE_UNION:
+ {
+ auto res = yang::Union{};
+ for (auto unionType : type->info()->uni()->types()) {
+ res.m_unionTypes.push_back(resolveType(unionType));
+ }
+ return res;
+ }
+ default:
+ using namespace std::string_literals;
+ throw UnsupportedYangTypeException("the type of "s + leaf->name() + " is not supported: " + std::to_string(leaf->type()->base()));
+ }
+ };
+ return resolveType(leaf->type());
}
-yang::LeafDataTypes YangSchema::leafType(const schemaPath_& location, const ModuleNodePair& node) const
+yang::LeafDataType YangSchema::leafType(const schemaPath_& location, const ModuleNodePair& node) const
{
return impl_leafType(getSchemaNode(location, node));
}
-yang::LeafDataTypes YangSchema::leafType(const std::string& path) const
+yang::LeafDataType YangSchema::leafType(const std::string& path) const
{
return impl_leafType(getSchemaNode(path));
}
@@ -296,29 +270,6 @@
return leaf.type()->der().get() ? std::optional{leaf.type()->der()->name()} : std::nullopt;
}
-namespace {
-yang::LeafDataTypes impl_leafrefBaseType(const libyang::S_Schema_Node& node)
-{
- using namespace std::string_literals;
- libyang::Schema_Node_Leaf leaf(node);
- try {
- return lyTypeToLeafDataTypes(leaf.type()->info()->lref()->target()->type()->base());
- } catch (std::logic_error& ex) {
- throw UnsupportedYangTypeException("the type of "s + node->name() + " is not supported: " + ex.what());
- }
-}
-}
-
-yang::LeafDataTypes YangSchema::leafrefBaseType(const schemaPath_& location, const ModuleNodePair& node) const
-{
- return impl_leafrefBaseType(getSchemaNode(location, node));
-}
-
-yang::LeafDataTypes YangSchema::leafrefBaseType(const std::string& path) const
-{
- return impl_leafrefBaseType(getSchemaNode(path));
-}
-
std::string YangSchema::leafrefPath(const std::string& leafrefPath) const
{
using namespace std::string_literals;
diff --git a/src/yang_schema.hpp b/src/yang_schema.hpp
index c763ea6..e3a9025 100644
--- a/src/yang_schema.hpp
+++ b/src/yang_schema.hpp
@@ -17,6 +17,7 @@
namespace libyang {
class Context;
class Schema_Node;
+class Schema_Node_Leaf;
class Data_Node;
class Module;
}
@@ -33,19 +34,13 @@
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 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;
bool leafIsKey(const std::string& leafPath) const override;
const std::set<std::string> listKeys(const schemaPath_& location, const ModuleNodePair& node) const override;
- yang::LeafDataTypes leafType(const schemaPath_& location, const ModuleNodePair& node) const override;
- yang::LeafDataTypes leafType(const std::string& path) const override;
+ yang::LeafDataType leafType(const schemaPath_& location, const ModuleNodePair& node) const override;
+ yang::LeafDataType leafType(const std::string& path) const override;
std::optional<std::string> leafTypeName(const std::string& path) const override;
- yang::LeafDataTypes leafrefBaseType(const schemaPath_& location, const ModuleNodePair& node) const override;
- yang::LeafDataTypes leafrefBaseType(const std::string& path) const override;
std::string leafrefPath(const std::string& leafrefPath) const override;
- const std::set<std::string> validIdentities(const schemaPath_& location, const ModuleNodePair& node, const Prefixes prefixes) const override;
- 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;
@@ -73,6 +68,7 @@
std::shared_ptr<libyang::Module> getYangModule(const std::string& name);
private:
+ yang::LeafDataType impl_leafType(const std::shared_ptr<libyang::Schema_Node>& node) const;
std::set<std::string> modules() const;
/** @short Returns a set of nodes, that match the location and name criteria. */
diff --git a/tests/cd.cpp b/tests/cd.cpp
index def2bdd..32d7230 100644
--- a/tests/cd.cpp
+++ b/tests/cd.cpp
@@ -24,11 +24,11 @@
schema->addContainer("/example:a/example:a2", "example:a3");
schema->addContainer("/example:b/example:b2", "example:b3");
schema->addList("/", "example:list", {"number"});
- schema->addLeaf("/example:list", "example:number", yang::LeafDataTypes::Int32);
+ schema->addLeaf("/example:list", "example:number", yang::Int32{});
schema->addContainer("/example:list", "example:contInList");
schema->addList("/", "example:twoKeyList", {"number", "name"});
- schema->addLeaf("/example:twoKeyList", "example:number", yang::LeafDataTypes::Int32);
- schema->addLeaf("/example:twoKeyList", "example:name", yang::LeafDataTypes::String);
+ schema->addLeaf("/example:twoKeyList", "example:number", yang::Int32{});
+ schema->addLeaf("/example:twoKeyList", "example:name", yang::String{});
Parser parser(schema);
std::string input;
std::ostringstream errorStream;
diff --git a/tests/enum_completion.cpp b/tests/enum_completion.cpp
index 939243f..07ea32c 100644
--- a/tests/enum_completion.cpp
+++ b/tests/enum_completion.cpp
@@ -9,6 +9,7 @@
#include "trompeloeil_doctest.hpp"
#include "datastoreaccess_mock.hpp"
+#include "leaf_data_helpers.hpp"
#include "parser.hpp"
#include "pretty_printers.hpp"
#include "static_schema.hpp"
@@ -18,11 +19,11 @@
auto schema = std::make_shared<StaticSchema>();
schema->addModule("mod");
schema->addContainer("/", "mod:contA");
- schema->addLeafEnum("/", "mod:leafEnum", {"lala", "lol", "data", "coze"});
- schema->addLeafEnum("/mod:contA", "mod:leafInCont", {"abc", "def"});
+ schema->addLeaf("/", "mod:leafEnum", createEnum({"lala", "lol", "data", "coze"}));
+ schema->addLeaf("/mod:contA", "mod:leafInCont", createEnum({"abc", "def"}));
schema->addList("/", "mod:list", {"number"});
- schema->addLeaf("/mod:list", "mod:number", yang::LeafDataTypes::Int32);
- schema->addLeafEnum("/mod:list", "mod:leafInList", {"ano", "anoda", "ne", "katoda"});
+ schema->addLeaf("/mod:list", "mod:number", yang::Int32{});
+ schema->addLeaf("/mod:list", "mod:leafInList", createEnum({"ano", "anoda", "ne", "katoda"}));
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"))
diff --git a/tests/example-schema.yang b/tests/example-schema.yang
index f876779..5ef67d5 100644
--- a/tests/example-schema.yang
+++ b/tests/example-schema.yang
@@ -80,6 +80,13 @@
}
}
+ leaf unionIntString {
+ type union {
+ type int32;
+ type string;
+ }
+ }
+
grouping upAndDown {
leaf up {
type boolean;
diff --git a/tests/keyvalue_completion.cpp b/tests/keyvalue_completion.cpp
index c6a2350..61e90cd 100644
--- a/tests/keyvalue_completion.cpp
+++ b/tests/keyvalue_completion.cpp
@@ -30,10 +30,10 @@
schema->addContainer("/", "example:a");
schema->addContainer("/", "example:b");
schema->addList("/", "example:list", {"number"});
- schema->addLeaf("/example:list", "example:number", yang::LeafDataTypes::Int32);
+ schema->addLeaf("/example:list", "example:number", yang::Int32{});
schema->addList("/", "example:twoKeyList", {"number", "name"});
- schema->addLeaf("/example:twoKeyList", "example:number", yang::LeafDataTypes::Int32);
- schema->addLeaf("/example:twoKeyList", "example:name", yang::LeafDataTypes::String);
+ schema->addLeaf("/example:twoKeyList", "example:number", yang::Int32{});
+ schema->addLeaf("/example:twoKeyList", "example:name", yang::String{});
auto mockDatastore = std::make_shared<MockDatastoreAccess>();
// DataQuery gets the schema from DatastoreAccess once
diff --git a/tests/leaf_data_helpers.hpp b/tests/leaf_data_helpers.hpp
new file mode 100644
index 0000000..0a28ae3
--- /dev/null
+++ b/tests/leaf_data_helpers.hpp
@@ -0,0 +1,10 @@
+#include <algorithm>
+#include "leaf_data_type.hpp"
+yang::Enum createEnum(const std::initializer_list<const char*>& list)
+{
+ std::set<enum_> enums;
+ std::transform(list.begin(), list.end(), std::inserter(enums, enums.end()), [](const auto& value) {
+ return enum_{value};
+ });
+ return yang::Enum(std::move(enums));
+}
diff --git a/tests/leaf_editing.cpp b/tests/leaf_editing.cpp
index 655f269..ad88a99 100644
--- a/tests/leaf_editing.cpp
+++ b/tests/leaf_editing.cpp
@@ -9,6 +9,7 @@
#include "trompeloeil_doctest.hpp"
#include <boost/core/demangle.hpp>
#include "ast_commands.hpp"
+#include "leaf_data_helpers.hpp"
#include "parser.hpp"
#include "static_schema.hpp"
#include "utils.hpp"
@@ -24,33 +25,53 @@
schema->addModule("mod");
schema->addModule("pizza-module");
schema->addContainer("/", "mod:contA");
- schema->addLeaf("/", "mod:leafString", yang::LeafDataTypes::String);
- schema->addLeaf("/", "mod:leafDecimal", yang::LeafDataTypes::Decimal);
- schema->addLeaf("/", "mod:leafBool", yang::LeafDataTypes::Bool);
- schema->addLeaf("/", "mod:leafInt8", yang::LeafDataTypes::Int8);
- schema->addLeaf("/", "mod:leafInt16", yang::LeafDataTypes::Int16);
- schema->addLeaf("/", "mod:leafInt32", yang::LeafDataTypes::Int32);
- schema->addLeaf("/", "mod:leafInt64", yang::LeafDataTypes::Int64);
- schema->addLeaf("/", "mod:leafUint8", yang::LeafDataTypes::Uint8);
- schema->addLeaf("/", "mod:leafUint16", yang::LeafDataTypes::Uint16);
- schema->addLeaf("/", "mod:leafUint32", yang::LeafDataTypes::Uint32);
- schema->addLeaf("/", "mod:leafUint64", yang::LeafDataTypes::Uint64);
- schema->addLeaf("/", "mod:leafBinary", yang::LeafDataTypes::Binary);
+ schema->addLeaf("/", "mod:leafString", yang::String{});
+ schema->addLeaf("/", "mod:leafDecimal", yang::Decimal{});
+ schema->addLeaf("/", "mod:leafBool", yang::Bool{});
+ schema->addLeaf("/", "mod:leafInt8", yang::Int8{});
+ schema->addLeaf("/", "mod:leafInt16", yang::Int16{});
+ schema->addLeaf("/", "mod:leafInt32", yang::Int32{});
+ schema->addLeaf("/", "mod:leafInt64", yang::Int64{});
+ schema->addLeaf("/", "mod:leafUint8", yang::Uint8{});
+ schema->addLeaf("/", "mod:leafUint16", yang::Uint16{});
+ 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->addLeafIdentityRef("/", "mod:foodIdentRef", ModuleValuePair{"mod", "food"});
- schema->addLeafIdentityRef("/", "mod:pizzaIdentRef", ModuleValuePair{"mod", "pizza"});
- schema->addLeafIdentityRef("/mod:contA", "mod:identInCont", ModuleValuePair{"mod", "pizza"});
- schema->addLeafEnum("/", "mod:leafEnum", {"lol", "data", "coze"});
- schema->addLeaf("/mod:contA", "mod:leafInCont", yang::LeafDataTypes::String);
+ 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")});
+ schema->addLeaf("/", "mod:leafEnum", createEnum({"lol", "data", "coze"}));
+ schema->addLeaf("/mod:contA", "mod:leafInCont", yang::String{});
schema->addList("/", "mod:list", {"number"});
- schema->addLeaf("/mod:list", "mod:number", yang::LeafDataTypes::Int32);
- schema->addLeaf("/mod:list", "mod:leafInList", yang::LeafDataTypes::String);
- schema->addLeafRef("/", "mod:refToString", "/mod:leafString");
- schema->addLeafRef("/", "mod:refToInt8", "/mod:leafInt8");
+ schema->addLeaf("/mod:list", "mod:number", yang::Int32{});
+ schema->addLeaf("/mod:list", "mod:leafInList", yang::String{});
+ schema->addLeaf("/", "mod:refToString", yang::LeafRef{"/mod:leafString", std::make_unique<yang::LeafDataType>(schema->leafType("/mod:leafString"))});
+ schema->addLeaf("/", "mod:refToInt8", yang::LeafRef{"/mod:leafInt8", std::make_unique<yang::LeafDataType>(schema->leafType("/mod:leafInt8"))});
+ schema->addLeaf("/", "mod:refToLeafInCont", yang::LeafRef{"/mod:contA/identInCont", std::make_unique<yang::LeafDataType>(schema->leafType("/mod:contA/mod:identInCont"))});
+ schema->addLeaf("/", "mod:intOrString", yang::Union{{yang::Int32{}, yang::String{}}});
+ schema->addLeaf("/", "mod:twoInts", yang::Union{{yang::Uint8{}, yang::Int16{}}});
+ schema->addLeaf("/", "mod:unionStringEnumLeafref", yang::Union{{
+ yang::String{},
+ createEnum({"foo", "bar"}),
+ yang::LeafRef{"/mod:leafEnum", std::make_unique<yang::LeafDataType>(schema->leafType("/mod:leafEnum"))}
+ }});
+
+ schema->addList("/", "mod:portSettings", {"port"});
+ schema->addLeaf("/mod:portSettings", "mod:port", createEnum({"eth0", "eth1", "eth2"}));
+ schema->addList("/", "mod:portMapping", {"port"});
+ schema->addLeaf("/mod:portMapping", "mod:port", createEnum({"utf1", "utf2", "utf3"}));
+ schema->addLeaf("/", "mod:activeMappedPort", yang::LeafRef{"/mod:portMapping/mod:port", std::make_unique<yang::LeafDataType>(schema->leafType("/mod:portMapping/mod:port"))});
+ schema->addLeaf("/", "mod:activePort", yang::Union{{
+ createEnum({"wlan0", "wlan1"}),
+ yang::LeafRef{"/mod:portSettings/mod:port", std::make_unique<yang::LeafDataType>(schema->leafType("/mod:portSettings/mod:port"))},
+ yang::LeafRef{"/mod:activeMappedPort", std::make_unique<yang::LeafDataType>(schema->leafType("/mod:activeMappedPort"))},
+ }});
+
Parser parser(schema);
std::string input;
std::ostringstream errorStream;
@@ -201,6 +222,112 @@
expected.m_data = true;
}
+ SECTION("union")
+ {
+ SECTION("int")
+ {
+ expected.m_path.m_nodes.push_back(dataNode_{module_{"mod"}, leaf_("intOrString")});
+ input = "set mod:intOrString 90";
+ expected.m_data = int32_t{90};
+ }
+ SECTION("string")
+ {
+ expected.m_path.m_nodes.push_back(dataNode_{module_{"mod"}, leaf_("intOrString")});
+ input = "set mod:intOrString \"test\"";
+ expected.m_data = std::string{"test"};
+ }
+
+ SECTION("union with two integral types")
+ {
+ expected.m_path.m_nodes.push_back(dataNode_{module_{"mod"}, leaf_("twoInts")});
+ SECTION("uint8")
+ {
+ input = "set mod:twoInts 100";
+ expected.m_data = uint8_t{100};
+ }
+ SECTION("int16")
+ {
+ input = "set mod:twoInts 6666";
+ expected.m_data = int16_t{6666};
+ }
+ }
+
+ SECTION("union with enum and leafref to enum")
+ {
+ expected.m_path.m_nodes.push_back(dataNode_{module_{"mod"}, leaf_("unionStringEnumLeafref")});
+ SECTION("string")
+ {
+ input = "set mod:unionStringEnumLeafref \"AHOJ\"";
+ expected.m_data = std::string{"AHOJ"};
+ }
+ SECTION("enum")
+ {
+ input = "set mod:unionStringEnumLeafref bar";
+ expected.m_data = enum_("bar");
+ }
+ SECTION("enum leafref")
+ {
+ input = "set mod:unionStringEnumLeafref coze";
+ expected.m_data = enum_("coze");
+ }
+ }
+
+ SECTION("activePort")
+ {
+ expected.m_path.m_nodes.push_back(dataNode_{module_{"mod"}, leaf_("activePort")});
+ input = "set mod:activePort ";
+ SECTION("1. anonymous enum")
+ {
+ SECTION("wlan0")
+ {
+ input += "wlan0";
+ expected.m_data = enum_("wlan0");
+ }
+ SECTION("wlan1")
+ {
+ input += "wlan1";
+ expected.m_data = enum_("wlan1");
+ }
+ }
+ SECTION("2. leafref to enum")
+ {
+ SECTION("eth0")
+ {
+ input += "eth0";
+ expected.m_data = enum_("eth0");
+ }
+ SECTION("eth1")
+ {
+ input += "eth1";
+ expected.m_data = enum_("eth1");
+ }
+ SECTION("eth2")
+ {
+ input += "eth2";
+ expected.m_data = enum_("eth2");
+ }
+ }
+ SECTION("3. leafref to leafref")
+ {
+ SECTION("utf1")
+ {
+ input += "utf1";
+ expected.m_data = enum_("utf1");
+ }
+ SECTION("utf2")
+ {
+ input += "utf2";
+ expected.m_data = enum_("utf2");
+ }
+ SECTION("utf3")
+ {
+ input += "utf3";
+ expected.m_data = enum_("utf3");
+ }
+ }
+ }
+ }
+
SECTION("binary")
{
SECTION("zero ending '='")
@@ -313,6 +440,13 @@
expected.m_path.m_nodes.push_back(dataNode_{module_{"mod"}, leaf_("refToInt8")});
expected.m_data = int8_t{42};
}
+
+ SECTION("refToLeafInCont")
+ {
+ input = "set mod:refToLeafInCont pizza";
+ expected.m_path.m_nodes.push_back(dataNode_{module_{"mod"}, leaf_("refToLeafInCont")});
+ expected.m_data = identityRef_{"pizza"};
+ }
}
}
@@ -445,6 +579,11 @@
input = "set mod:contA/identInCont pizza-module:";
}
+ SECTION("set a union path to a wrong type")
+ {
+ input = "set mod:intOrString true";
+ }
+
REQUIRE_THROWS_AS(parser.parseCommand(input, errorStream), InvalidCommandException);
REQUIRE(errorStream.str().find(expectedError) != std::string::npos);
}
diff --git a/tests/list_manipulation.cpp b/tests/list_manipulation.cpp
index b71ee7b..15f2f04 100644
--- a/tests/list_manipulation.cpp
+++ b/tests/list_manipulation.cpp
@@ -14,8 +14,8 @@
auto schema = std::make_shared<StaticSchema>();
schema->addModule("mod");
schema->addList("/", "mod:list", {"number"});
- schema->addLeaf("/mod:list", "mod:number", yang::LeafDataTypes::Int32);
- schema->addLeaf("/mod:list", "mod:leafInList", yang::LeafDataTypes::String);
+ schema->addLeaf("/mod:list", "mod:number", yang::Int32{});
+ schema->addLeaf("/mod:list", "mod:leafInList", yang::String{});
Parser parser(schema);
std::string input;
std::ostringstream errorStream;
diff --git a/tests/ls.cpp b/tests/ls.cpp
index 2c72041..66c2aaa 100644
--- a/tests/ls.cpp
+++ b/tests/ls.cpp
@@ -25,11 +25,11 @@
schema->addContainer("/example:a/example:a2", "example:a3");
schema->addContainer("/example:b/example:b2", "example:b3");
schema->addList("/", "example:list", {"number"});
- schema->addLeaf("/example:list", "example:number", yang::LeafDataTypes::Int32);
+ schema->addLeaf("/example:list", "example:number", yang::Int32{});
schema->addContainer("/example:list", "example:contInList");
schema->addList("/", "example:twoKeyList", {"number", "name"});
- schema->addLeaf("/example:twoKeyList", "example:number", yang::LeafDataTypes::Int32);
- schema->addLeaf("/example:twoKeyList", "example:name", yang::LeafDataTypes::String);
+ schema->addLeaf("/example:twoKeyList", "example:number", yang::Int32{});
+ schema->addLeaf("/example:twoKeyList", "example:name", yang::String{});
Parser parser(schema);
std::string input;
std::ostringstream errorStream;
diff --git a/tests/path_completion.cpp b/tests/path_completion.cpp
index 2403f9d..c00a26c 100644
--- a/tests/path_completion.cpp
+++ b/tests/path_completion.cpp
@@ -27,16 +27,16 @@
schema->addContainer("/example:ano/example:a2", "example:a3");
schema->addContainer("/example:bota/example:b2", "example:b3");
schema->addList("/", "example:list", {"number"});
- schema->addLeaf("/example:list", "example:number", yang::LeafDataTypes::Int32);
+ schema->addLeaf("/example:list", "example:number", yang::Int32{});
schema->addContainer("/example:list", "example:contInList");
schema->addList("/", "example:ovoce", {"name"});
- schema->addLeaf("/example:ovoce", "example:name", yang::LeafDataTypes::String);
+ schema->addLeaf("/example:ovoce", "example:name", yang::String{});
schema->addList("/", "example:ovocezelenina", {"name"});
- schema->addLeaf("/example:ovocezelenina", "example:name", yang::LeafDataTypes::String);
+ schema->addLeaf("/example:ovocezelenina", "example:name", yang::String{});
schema->addList("/", "example:twoKeyList", {"number", "name"});
- schema->addLeaf("/example:twoKeyList", "example:name", yang::LeafDataTypes::String);
- schema->addLeaf("/example:twoKeyList", "example:number", yang::LeafDataTypes::Int32);
- schema->addLeaf("/", "example:leafInt", yang::LeafDataTypes::Int32);
+ schema->addLeaf("/example:twoKeyList", "example:name", yang::String{});
+ schema->addLeaf("/example:twoKeyList", "example:number", yang::Int32{});
+ schema->addLeaf("/", "example:leafInt", yang::Int32{});
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.
diff --git a/tests/presence_containers.cpp b/tests/presence_containers.cpp
index af79d00..7c6397d 100644
--- a/tests/presence_containers.cpp
+++ b/tests/presence_containers.cpp
@@ -22,7 +22,7 @@
schema->addContainer("/mod:a/mod:a2", "mod:a3", yang::ContainerTraits::Presence);
schema->addContainer("/mod:b", "mod:b2", yang::ContainerTraits::Presence);
schema->addList("/", "mod:list", {"quote"});
- schema->addLeaf("/mod:list", "mod:quote", yang::LeafDataTypes::String);
+ schema->addLeaf("/mod:list", "mod:quote", yang::String{});
schema->addContainer("/mod:list", "mod:contInList", yang::ContainerTraits::Presence);
Parser parser(schema);
std::string input;
diff --git a/tests/pretty_printers.hpp b/tests/pretty_printers.hpp
index 86bd20d..e5b6659 100644
--- a/tests/pretty_printers.hpp
+++ b/tests/pretty_printers.hpp
@@ -36,4 +36,42 @@
s << "}" << std::endl;
return s;
}
+
+std::ostream& operator<<(std::ostream& s, const yang::LeafDataType& type)
+{
+ s << std::endl
+ << leafDataTypeToString(type);
+ if (std::holds_alternative<yang::Enum>(type)) {
+ s << "{";
+ auto values = std::get<yang::Enum>(type).m_allowedValues;
+ std::transform(values.begin(), values.end(), std::experimental::make_ostream_joiner(s, ", "), [](const auto& value) {
+ return value.m_value;
+ });
+ s << "}";
+ }
+ if (std::holds_alternative<yang::IdentityRef>(type)) {
+ s << "{";
+ auto values = std::get<yang::IdentityRef>(type).m_allowedValues;
+ std::transform(values.begin(), values.end(), std::experimental::make_ostream_joiner(s, ", "), [](const auto& value) {
+ std::string res;
+ if (value.m_prefix) {
+ res += value.m_prefix->m_name;
+ res += ":";
+ }
+ res += value.m_value;
+ return res;
+ });
+ s << "}";
+ }
+ if (std::holds_alternative<yang::LeafRef>(type)) {
+ s << "{" << std::get<yang::LeafRef>(type).m_targetXPath << "," << *std::get<yang::LeafRef>(type).m_targetType << "}";
+ }
+ if (std::holds_alternative<yang::Union>(type)) {
+ s << "{" << std::endl;
+ auto types = std::get<yang::Union>(type).m_unionTypes;
+ std::copy(types.begin(), types.end(), std::experimental::make_ostream_joiner(s, ",\n"));
+ }
+ s << std::endl;
+ return s;
+}
}
diff --git a/tests/utils.cpp b/tests/utils.cpp
index 91c61cb..cea698b 100644
--- a/tests/utils.cpp
+++ b/tests/utils.cpp
@@ -8,6 +8,7 @@
#include "trompeloeil_doctest.hpp"
#include "completion.hpp"
+#include "leaf_data_helpers.hpp"
#include "utils.hpp"
TEST_CASE("utils")
@@ -80,4 +81,24 @@
REQUIRE(joinPaths(prefix, suffix) == result);
}
+
+ SECTION("leafDataTypeToString")
+ {
+ yang::LeafDataType type;
+ std::string expected;
+ SECTION("union")
+ {
+ type = yang::Union{{
+ yang::String{},
+ createEnum({"foo", "bar"}),
+ yang::Int8{},
+ yang::Int64{},
+ }};
+ expected = "a string, an enum, an 8-bit integer, a 64-bit integer";
+ }
+
+ REQUIRE(leafDataTypeToString(type) == expected);
+
+ }
+
}
diff --git a/tests/yang.cpp b/tests/yang.cpp
index d189f50..a9fb65e 100644
--- a/tests/yang.cpp
+++ b/tests/yang.cpp
@@ -7,6 +7,7 @@
*/
#include <experimental/iterator>
+#include "leaf_data_helpers.hpp"
#include "pretty_printers.hpp"
#include "trompeloeil_doctest.hpp"
#include "yang_schema.hpp"
@@ -298,6 +299,61 @@
rpc myRpc {}
+ leaf numberOrString {
+ type union {
+ type int32;
+ type string;
+ }
+ description "Can be an int32 or a string.";
+ }
+
+ list portSettings {
+ key "port";
+ leaf port {
+ type enumeration {
+ enum eth0;
+ enum eth1;
+ enum eth2;
+ }
+ }
+ }
+
+ feature weirdPortNames;
+
+ list portMapping {
+ key "port";
+ leaf port {
+ type enumeration {
+ enum WEIRD {
+ if-feature "weirdPortNames";
+ }
+ enum utf2;
+ enum utf3;
+ }
+ }
+ }
+
+ leaf activeMappedPort {
+ type leafref {
+ path "../portMapping/port";
+ }
+ }
+
+ leaf activePort {
+ type union {
+ type enumeration {
+ enum wlan0;
+ enum wlan1;
+ }
+ type leafref {
+ path "../portSettings/port";
+ }
+ type leafref {
+ path "../activeMappedPort";
+ }
+ }
+ }
+
})";
namespace std {
@@ -425,189 +481,6 @@
REQUIRE(ys.isPresenceContainer(path, node));
}
- SECTION("leafEnumHasValue")
- {
- std::string value;
- SECTION("leafEnum")
- {
- node.first = "example-schema";
- node.second = "leafEnum";
-
- SECTION("lol")
- value = "lol";
-
- SECTION("data")
- value = "data";
-
- SECTION("coze")
- value = "coze";
- }
-
- SECTION("leafEnumTypedef")
- {
- node.first = "example-schema";
- node.second = "leafEnumTypedef";
-
- SECTION("lol")
- value = "lol";
-
- SECTION("data")
- value = "data";
-
- SECTION("coze")
- value = "coze";
- }
-
- SECTION("leafEnumTypedefRestricted")
- {
- node.first = "example-schema";
- node.second = "leafEnumTypedefRestricted";
-
- SECTION("data")
- value = "data";
-
- SECTION("coze")
- value = "coze";
- }
-
- SECTION("leafEnumTypedefRestricted2")
- {
- node.first = "example-schema";
- node.second = "leafEnumTypedefRestricted2";
-
- SECTION("lol")
- value = "lol";
-
- SECTION("data")
- value = "data";
- }
-
- SECTION("pizzaSize")
- {
- node.first = "example-schema";
- node.second = "pizzaSize";
-
- SECTION("small")
- {
- value = "small";
- }
- SECTION("medium")
- {
- value = "medium";
- }
-
- SECTION("large")
- {
- ys.enableFeature("example-schema", "bigPizzas");
- value = "large";
- }
- }
-
- REQUIRE(ys.leafEnumHasValue(path, node, value));
- }
- SECTION("leafIdentityIsValid")
- {
- ModuleValuePair value;
-
- SECTION("foodIdentLeaf")
- {
- node.first = "example-schema";
- node.second = "foodIdentLeaf";
-
- SECTION("food")
- {
- value.second = "food";
- }
- SECTION("example-schema:food")
- {
- value.first = "example-schema";
- value.second = "food";
- }
- SECTION("pizza")
- {
- value.second = "pizza";
- }
- SECTION("example-schema:pizza")
- {
- value.first = "example-schema";
- value.second = "pizza";
- }
- SECTION("hawaii")
- {
- value.second = "hawaii";
- }
- SECTION("example-schema:hawaii")
- {
- value.first = "example-schema";
- value.second = "hawaii";
- }
- SECTION("fruit")
- {
- value.second = "fruit";
- }
- SECTION("example-schema:fruit")
- {
- value.first = "example-schema";
- value.second = "fruit";
- }
- SECTION("second-schema:pineapple")
- {
- value.first = "second-schema";
- value.second = "pineapple";
- }
- }
-
- SECTION("pizzaIdentLeaf")
- {
- node.first = "example-schema";
- node.second = "pizzaIdentLeaf";
-
- SECTION("pizza")
- {
- value.second = "pizza";
- }
- SECTION("example-schema:pizza")
- {
- value.first = "example-schema";
- value.second = "pizza";
- }
- SECTION("hawaii")
- {
- value.second = "hawaii";
- }
- SECTION("example-schema:hawaii")
- {
- value.first = "example-schema";
- value.second = "hawaii";
- }
- }
-
- SECTION("foodDrinkIdentLeaf")
- {
- node.first = "example-schema";
- node.second = "foodDrinkIdentLeaf";
-
- SECTION("food")
- {
- value.second = "food";
- }
- SECTION("example-schema:food")
- {
- value.first = "example-schema";
- value.second = "food";
- }
- SECTION("drink")
- {
- value.second = "drink";
- }
- SECTION("example-schema:drink")
- {
- value.first = "example-schema";
- value.second = "drink";
- }
- }
- REQUIRE(ys.leafIdentityIsValid(path, node, value));
- }
SECTION("listHasKey")
{
@@ -655,90 +528,208 @@
}
SECTION("leafType")
{
- yang::LeafDataTypes type;
+ yang::LeafDataType type;
SECTION("leafString")
{
node.first = "example-schema";
node.second = "leafString";
- type = yang::LeafDataTypes::String;
+ type = yang::String{};
}
SECTION("leafDecimal")
{
node.first = "example-schema";
node.second = "leafDecimal";
- type = yang::LeafDataTypes::Decimal;
+ type = yang::Decimal{};
}
SECTION("leafBool")
{
node.first = "example-schema";
node.second = "leafBool";
- type = yang::LeafDataTypes::Bool;
+ type = yang::Bool{};
}
SECTION("leafInt8")
{
node.first = "example-schema";
node.second = "leafInt8";
- type = yang::LeafDataTypes::Int8;
+ type = yang::Int8{};
}
SECTION("leafUint8")
{
node.first = "example-schema";
node.second = "leafUint8";
- type = yang::LeafDataTypes::Uint8;
+ type = yang::Uint8{};
}
- SECTION("leafInt15")
+ SECTION("leafInt16")
{
node.first = "example-schema";
node.second = "leafInt16";
- type = yang::LeafDataTypes::Int16;
+ type = yang::Int16{};
}
SECTION("leafUint16")
{
node.first = "example-schema";
node.second = "leafUint16";
- type = yang::LeafDataTypes::Uint16;
+ type = yang::Uint16{};
}
SECTION("leafInt32")
{
node.first = "example-schema";
node.second = "leafInt32";
- type = yang::LeafDataTypes::Int32;
+ type = yang::Int32{};
}
SECTION("leafUint32")
{
node.first = "example-schema";
node.second = "leafUint32";
- type = yang::LeafDataTypes::Uint32;
+ type = yang::Uint32{};
}
SECTION("leafInt64")
{
node.first = "example-schema";
node.second = "leafInt64";
- type = yang::LeafDataTypes::Int64;
+ type = yang::Int64{};
}
SECTION("leafUint64")
{
node.first = "example-schema";
node.second = "leafUint64";
- type = yang::LeafDataTypes::Uint64;
+ type = yang::Uint64{};
}
SECTION("leafEnum")
{
node.first = "example-schema";
node.second = "leafEnum";
- type = yang::LeafDataTypes::Enum;
+ type = createEnum({"lol", "data", "coze"});
+ }
+
+ SECTION("leafEnumTypedef")
+ {
+ node.first = "example-schema";
+ node.second = "leafEnumTypedef";
+ type = createEnum({"lol", "data", "coze"});
+ }
+
+ SECTION("leafEnumTypedefRestricted")
+ {
+ node.first = "example-schema";
+ node.second = "leafEnumTypedefRestricted";
+ type = createEnum({"data", "coze"});
+ }
+
+ SECTION("leafEnumTypedefRestricted2")
+ {
+ node.first = "example-schema";
+ node.second = "leafEnumTypedefRestricted2";
+ type = createEnum({"lol", "data"});
+ }
+
+ SECTION("pizzaSize")
+ {
+ node.first = "example-schema";
+ node.second = "pizzaSize";
+
+ SECTION("bigPizzas disabled")
+ {
+ type = createEnum({"small", "medium"});
+ }
+ SECTION("bigPizzas enabled")
+ {
+ ys.enableFeature("example-schema", "bigPizzas");
+ type = createEnum({"small", "medium", "large"});
+ }
+ }
+
+ SECTION("foodIdentLeaf")
+ {
+ node.first = "example-schema";
+ node.second = "foodIdentLeaf";
+ type = yang::IdentityRef{{{"second-schema", "pineapple"},
+ {"example-schema", "food"},
+ {"example-schema", "pizza"},
+ {"example-schema", "hawaii"},
+ {"example-schema", "fruit"}}};
+ }
+
+ SECTION("pizzaIdentLeaf")
+ {
+ node.first = "example-schema";
+ node.second = "pizzaIdentLeaf";
+
+ type = yang::IdentityRef{{
+ {"example-schema", "pizza"},
+ {"example-schema", "hawaii"},
+ }};
+ }
+
+ SECTION("foodDrinkIdentLeaf")
+ {
+ node.first = "example-schema";
+ node.second = "foodDrinkIdentLeaf";
+
+ type = yang::IdentityRef{{
+ {"example-schema", "food"},
+ {"example-schema", "drink"},
+ {"example-schema", "fruit"},
+ {"example-schema", "hawaii"},
+ {"example-schema", "pizza"},
+ {"example-schema", "voda"},
+ {"second-schema", "pineapple"},
+ }};
+ }
+
+ SECTION("activeNumber")
+ {
+ node.first = "example-schema";
+ node.second = "activeNumber";
+ type.emplace<yang::LeafRef>(
+ "/example-schema:_list/number",
+ std::make_unique<yang::LeafDataType>(ys.leafType("/example-schema:_list/number"))
+ );
+ }
+
+ SECTION("activePort")
+ {
+ node.first = "example-schema";
+ node.second = "activePort";
+
+ yang::Enum enums = [&ys]() {
+ SECTION("weird ports disabled")
+ {
+ return createEnum({"utf2", "utf3"});
+ }
+ SECTION("weird ports enabled")
+ {
+ ys.enableFeature("example-schema", "weirdPortNames");
+ return createEnum({"WEIRD", "utf2", "utf3"});
+ }
+ __builtin_unreachable();
+ }();
+
+ type = yang::Union{{
+ createEnum({"wlan0", "wlan1"}),
+ yang::LeafRef{
+ "/example-schema:portSettings/port",
+ std::make_unique<yang::LeafDataType>(createEnum({"eth0", "eth1", "eth2"}))
+ },
+ yang::LeafRef{
+ "/example-schema:activeMappedPort",
+ std::make_unique<yang::LeafDataType>(yang::LeafRef{
+ "/example-schema:portMapping/port",
+ std::make_unique<yang::LeafDataType>(enums)
+ })},
+ }};
}
REQUIRE(ys.leafType(path, node) == type);
@@ -765,7 +756,12 @@
"example-schema:pizzaSize",
"example-schema:length", "example-schema:wavelength",
"example-schema:duration", "example-schema:another-duration",
- "example-schema:activeNumber"};
+ "example-schema:activeNumber",
+ "example-schema:numberOrString",
+ "example-schema:portSettings",
+ "example-schema:portMapping",
+ "example-schema:activeMappedPort",
+ "example-schema:activePort"};
}
SECTION("example-schema:a")
@@ -834,6 +830,12 @@
path.m_nodes.push_back(schemaNode_(module_{"example-schema"}, leaf_("leafString")));
}
+ SECTION("numberOrString")
+ {
+ path.m_nodes.push_back(schemaNode_(module_{"example-schema"}, leaf_("numberOrString")));
+ expected = "Can be an int32 or a string.";
+ }
+
REQUIRE(ys.description(pathToSchemaString(path, Prefixes::WhenNeeded)) == expected);
}
@@ -962,7 +964,6 @@
path.m_nodes.push_back(schemaNode_(module_{"example-schema"}, container_("a")));
node.second = "a2";
- REQUIRE(!ys.leafEnumHasValue(path, node, "haha"));
REQUIRE(!ys.listHasKey(path, node, "chacha"));
}
@@ -971,44 +972,6 @@
REQUIRE(!ys.isModule("notAModule"));
}
- SECTION("leafIdentityIsValid")
- {
- ModuleValuePair value;
- SECTION("pizzaIdentLeaf")
- {
- node.first = "example-schema";
- node.second = "pizzaIdentLeaf";
-
- SECTION("wrong base ident")
- {
- SECTION("food")
- {
- value.second = "food";
- }
- SECTION("fruit")
- {
- value.second = "fruit";
- }
- }
- SECTION("non-existent identity")
- {
- value.second = "nonexistent";
- }
- SECTION("weird module")
- {
- value.first = "ahahaha";
- value.second = "pizza";
- }
- }
- SECTION("different module identity, but withotu prefix")
- {
- node.first = "example-schema";
- node.second = "foodIdentLeaf";
- value.second = "pineapple";
- }
- REQUIRE_FALSE(ys.leafIdentityIsValid(path, node, value));
- }
-
SECTION("grouping is not a node")
{
SECTION("example-schema:arithmeticFlags")
@@ -1062,15 +1025,5 @@
REQUIRE(!ys.isLeaf(path, node));
REQUIRE(!ys.isContainer(path, node));
}
-
- SECTION("enum is disabled by if-feature if feature is not enabled")
- {
- node.first = "example-schema";
- node.second = "pizzaSize";
-
- std::string value = "large";
-
- REQUIRE(!ys.leafEnumHasValue(path, node, value));
- }
}
}