From d8bf2a8c80e912e3e2ed312ad1ede22b7f03fb18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pecka?= Date: Mon, 3 Jun 2024 12:49:53 +0200 Subject: [PATCH] Wrap lyd_meta_is_internal to check if meta is internal There are some internal meta attributes that libyang uses for internal stuff and they are ignored when printing the meta collections. One (and now also the only) example of such node is yang:lyds_tree attribute. It can be useful to check if the meta attribute is internal. For instance, when we want to be sure that our parsed data did not contain any meta attributes from user. However, sometimes, libyang silently inserts these internal attributes while parsing. We asked upstream if there could be a function that checks for us if the attribute is internal and therefore we should ignore it. They kindly provided us with such function (`lyd_meta_is_internal`) [1]. This commit wraps the function. Unfortunately, our Meta class does not wrap lyd_meta, only copies data from the structure so we can't just call this function when requested but we call it in Meta object construction which creates a little overhead in both time and memory. [1] https://github.com/CESNET/libyang/commit/f77ca9cf807eeb11c8f806b2c32fb0a21fb4a22f Change-Id: Id772ded765569089525cf4fd5dba8a64efe87d02 --- CMakeLists.txt | 2 +- include/libyang-cpp/DataNode.hpp | 2 ++ src/DataNode.cpp | 7 +++++++ tests/data_node.cpp | 23 +++++++++++++++++++++++ tests/example_schema.hpp | 4 ++++ 5 files changed, 37 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b286db1..d1003d25 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,7 +28,7 @@ option(WITH_DOCS "Create and install internal documentation (needs Doxygen)" ${D option(BUILD_SHARED_LIBS "By default, shared libs are enabled. Turn off for a static build." ON) find_package(PkgConfig REQUIRED) -pkg_check_modules(LIBYANG REQUIRED libyang>=3.0.1 IMPORTED_TARGET) +pkg_check_modules(LIBYANG REQUIRED libyang>=3.0.11 IMPORTED_TARGET) set(LIBYANG_CPP_PKG_VERSION "2") include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) diff --git a/include/libyang-cpp/DataNode.hpp b/include/libyang-cpp/DataNode.hpp index 8f9d087f..839c33f5 100644 --- a/include/libyang-cpp/DataNode.hpp +++ b/include/libyang-cpp/DataNode.hpp @@ -183,6 +183,7 @@ class LIBYANG_CPP_EXPORT Meta { std::string name() const; std::string valueStr() const; Module module() const; + bool isInternal() const; private: friend Iterator; @@ -191,6 +192,7 @@ class LIBYANG_CPP_EXPORT Meta { std::string m_name; std::string m_value; Module m_mod; + bool m_isInternal; }; diff --git a/src/DataNode.cpp b/src/DataNode.cpp index b24a4ed6..bcad13eb 100644 --- a/src/DataNode.cpp +++ b/src/DataNode.cpp @@ -981,6 +981,7 @@ Meta::Meta(lyd_meta* meta, std::shared_ptr ctx) : m_name(meta->name) , m_value(lyd_get_meta_value(meta)) , m_mod(meta->annotation->module, ctx) + , m_isInternal(lyd_meta_is_internal(meta)) { } @@ -999,6 +1000,12 @@ Module Meta::module() const return m_mod; } +/** @brief Checks if the meta attribute is considered internal for libyang, see `lyd_meta_is_internal` */ +bool Meta::isInternal() const +{ + return m_isInternal; +} + /** * Creates a JSON attribute for an opaque data node. * Wraps `lyd_new_attr`. diff --git a/tests/data_node.cpp b/tests/data_node.cpp index a398fed8..e3350e1d 100644 --- a/tests/data_node.cpp +++ b/tests/data_node.cpp @@ -1899,6 +1899,7 @@ TEST_CASE("Data Node manipulation") } auto meta = netconfDeletePresenceCont.meta(); + REQUIRE(std::none_of(meta.begin(), meta.end(), [](const auto& meta) { return meta.isInternal(); })); std::transform(meta.begin(), meta.end(), std::back_inserter(actual), [] (const auto& it) { return std::pair{it.name(), it.valueStr()}; }); REQUIRE(actual == expected); } @@ -1976,6 +1977,28 @@ TEST_CASE("Data Node manipulation") REQUIRE(*out->printStr(libyang::DataFormat::JSON, libyang::PrintFlags::WithSiblings) == expectedJson); REQUIRE(*out->printStr(libyang::DataFormat::XML, libyang::PrintFlags::WithSiblings) == expectedXml); } + + DOCTEST_SUBCASE("libyang internal metadata") + { + /* + * - currently, libyang creates an internal meta node yang:lyds_tree representing a RB-tree for ordering of data in lists + * - this test depends on internal libyang implementation which can of course change anytime + * - but it seems that yang:lyds_tree can't be created manually (there is no valid value for it?) and I don't know how to test this otherwise + */ + DOCTEST_SUBCASE("leaf-list ordered by system") + { + auto node = ctx.parseData(R"({"example-schema3:valuesOrderedBySystem": [1,2,3]})"s, libyang::DataFormat::JSON, libyang::ParseOptions::Strict | libyang::ParseOptions::NoState | libyang::ParseOptions::ParseOnly); + const auto metaColl = node->meta(); + REQUIRE(std::find_if(metaColl.begin(), metaColl.end(), [](const auto& meta) { return meta.isInternal(); }) != metaColl.end()); + } + + DOCTEST_SUBCASE("leaf-list ordered by user") + { + auto node = ctx.parseData(R"({"example-schema3:values": [1,2,3]})"s, libyang::DataFormat::JSON, libyang::ParseOptions::Strict | libyang::ParseOptions::NoState | libyang::ParseOptions::ParseOnly); + const auto metaColl = node->meta(); + REQUIRE(std::find_if(metaColl.begin(), metaColl.end(), [](const auto& meta) { return meta.isInternal(); }) == metaColl.end()); + } + } } DOCTEST_SUBCASE("Extension nodes") diff --git a/tests/example_schema.hpp b/tests/example_schema.hpp index 52a316c9..c3892550 100644 --- a/tests/example_schema.hpp +++ b/tests/example_schema.hpp @@ -293,6 +293,10 @@ module example-schema3 { type int32; } + leaf-list valuesOrderedBySystem { + type int32; + } + list person { key 'name'; leaf name {