diff --git a/.gitignore b/.gitignore index d666beed9..9e75015b6 100644 --- a/.gitignore +++ b/.gitignore @@ -42,8 +42,6 @@ Session.vim # temporary .netrwhist *~ -# auto-generated tag files -tags build/ install/ diff --git a/ddspipe_yaml/include/ddspipe_yaml/Yaml.hpp b/ddspipe_core/include/ddspipe_core/testing/arbitrary_values.hpp similarity index 53% rename from ddspipe_yaml/include/ddspipe_yaml/Yaml.hpp rename to ddspipe_core/include/ddspipe_core/testing/arbitrary_values.hpp index 19f86756d..6d928ad9f 100644 --- a/ddspipe_yaml/include/ddspipe_yaml/Yaml.hpp +++ b/ddspipe_core/include/ddspipe_core/testing/arbitrary_values.hpp @@ -1,4 +1,4 @@ -// Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// Copyright 2021 Proyectos y Sistemas de Mantenimiento SL (eProsima). // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -10,29 +10,25 @@ // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and -// limitations under the License. +// limitations under the License\. #pragma once -#include - -#include - namespace eprosima { +namespace ddspipe { +namespace core { +namespace testing { -/** - * Configuration is in dictionary format - * - * YAML spec: https://yaml.org/spec/1.2.2/ - * - * @note It is not legal to repeat keys in a YAML - * - * @note this object contains a reference to the actual yaml object. Thus passing it by value or by reference - * makes no different. - */ -using Yaml = YAML::Node; +template +T arbitrary( + unsigned int seed = 0); -//! Type of tag in the yaml -using TagType = std::string; +template +T arbitrary( + unsigned int seed, + Args... args); +} /* namespace testing */ +} /* namespace core */ +} /* namespace ddspipe */ } /* namespace eprosima */ diff --git a/ddspipe_core/src/cpp/testing/arbitrary_values.cpp b/ddspipe_core/src/cpp/testing/arbitrary_values.cpp new file mode 100644 index 000000000..0e58dc121 --- /dev/null +++ b/ddspipe_core/src/cpp/testing/arbitrary_values.cpp @@ -0,0 +1,180 @@ +// Copyright 2021 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace eprosima { +namespace ddspipe { +namespace core { +namespace testing { + +using namespace eprosima::ddspipe::core::types; + +//////////////////////////////////////////////// +// DEFAULT ARBITRARY +//////////////////////////////////////////////// + +template <> +TopicQoS arbitrary( + unsigned int seed /* = 0 */) +{ + TopicQoS object; + + if (seed % 2) + { + object.reliability_qos = ReliabilityKind::BEST_EFFORT; + } + else + { + object.reliability_qos = ReliabilityKind::RELIABLE; + } + + seed /= 2; + + switch ((seed / 2) % 4) + { + case 0: + object.durability_qos = DurabilityKind::VOLATILE; + break; + + case 1: + object.durability_qos = DurabilityKind::TRANSIENT_LOCAL; + break; + + case 2: + object.durability_qos = DurabilityKind::TRANSIENT; + break; + + case 3: + object.durability_qos = DurabilityKind::PERSISTENT; + break; + + default: + break; + } + + seed /= 4; + + if (seed % 2) + { + object.ownership_qos = OwnershipQosPolicyKind::SHARED_OWNERSHIP_QOS; + } + else + { + object.ownership_qos = OwnershipQosPolicyKind::EXCLUSIVE_OWNERSHIP_QOS; + } + + seed /= 2; + + object.use_partitions = ((seed % 2) == 0); + + seed /= 2; + + object.keyed = ((seed % 2) == 0); + + seed /= 2; + + object.downsampling = (seed % 2) + 1; + + seed /= 2; + + object.max_reception_rate = seed % 2; + + seed /= 2; + + object.history_depth = seed + 1; + + return object; +} + +template <> +DdsTopic arbitrary( + unsigned int seed /* = 0 */) +{ + DdsTopic object; + object.m_topic_name = "TopicName_" + std::to_string(seed); + object.type_name = "TopicType_" + std::to_string(seed); + object.topic_qos = arbitrary(seed); + return object; +} + +template <> +WildcardDdsFilterTopic arbitrary( + unsigned int seed /* = 0 */) +{ + WildcardDdsFilterTopic object; + + if (seed % 2) + { + object.topic_name.set_value("TopicName_" + std::to_string(seed)); + } + + seed /= 2; + + if (seed % 2) + { + object.type_name.set_value("TopicName_" + std::to_string(seed)); + } + + return object; +} + +template <> +GuidPrefix arbitrary( + unsigned int seed /* = 0 */) +{ + // TODO do it more generic and arbitrary + return GuidPrefix(static_cast(seed)); +} + +//////////////////////////////////////////////// +// SPECIFIC ARBITRARY +//////////////////////////////////////////////// + +template <> +TopicQoS arbitrary( + unsigned int seed, + bool limit_durability) +{ + TopicQoS object = arbitrary(seed); + + // Reliability + seed /= 2; + + if (seed % 2) + { + object.durability_qos = DurabilityKind::VOLATILE; + } + else + { + object.durability_qos = DurabilityKind::TRANSIENT_LOCAL; + } + + return object; +} + +} /* namespace testing */ +} /* namespace core */ +} /* namespace ddspipe */ +} /* namespace eprosima */ diff --git a/ddspipe_core/src/cpp/types/topic/dds/DdsTopic.cpp b/ddspipe_core/src/cpp/types/topic/dds/DdsTopic.cpp index aa8bbc084..e91f60c62 100644 --- a/ddspipe_core/src/cpp/types/topic/dds/DdsTopic.cpp +++ b/ddspipe_core/src/cpp/types/topic/dds/DdsTopic.cpp @@ -37,7 +37,7 @@ std::ostream& operator <<( std::ostream& os, const DdsTopic& t) { - os << "DdsTopic{" << t.topic_name() << ";" << t.type_name << t.topic_qos << "}"; + os << "DdsTopic{" << t.topic_name() << ";" << t.type_name << ";" << t.topic_qos << "}"; return os; } diff --git a/ddspipe_participants/include/ddspipe_participants/types/address/Address.hpp b/ddspipe_participants/include/ddspipe_participants/types/address/Address.hpp index 00fd09a82..889bae24e 100644 --- a/ddspipe_participants/include/ddspipe_participants/types/address/Address.hpp +++ b/ddspipe_participants/include/ddspipe_participants/types/address/Address.hpp @@ -18,6 +18,8 @@ #include +#include + #include namespace eprosima { @@ -35,18 +37,18 @@ using DomainType = std::string; using PortType = uint16_t; //! Different versions allowed for IP -enum class IpVersion : int -{ - v4 = 4, - v6 = 6, -}; +ENUMERATION_BUILDER( + IpVersion, + v4, + v6 +); //! Different Transport Protocols allowed -enum class TransportProtocol -{ +ENUMERATION_BUILDER( + TransportProtocol, udp, tcp -}; +); /** * @brief Address that works as a collection of data defining a network address. diff --git a/ddspipe_participants/include/ddspipe_participants/types/address/DiscoveryServerConnectionAddress.hpp b/ddspipe_participants/include/ddspipe_participants/types/address/DiscoveryServerConnectionAddress.hpp index b497ef041..536cfb9e8 100644 --- a/ddspipe_participants/include/ddspipe_participants/types/address/DiscoveryServerConnectionAddress.hpp +++ b/ddspipe_participants/include/ddspipe_participants/types/address/DiscoveryServerConnectionAddress.hpp @@ -33,29 +33,10 @@ namespace types { * This class has several address associated with one \c GuidPrefix in order to connect with * a remote Discovery Server. */ -class DiscoveryServerConnectionAddress +struct DiscoveryServerConnectionAddress { public: - /** - * @brief Construct a new \c DiscoveryServerConnectionAddress object with all the parameters - * - * @param discovery_server_guid_ : Guid Prefix of the remote Discovery Server - * @param addresses_ collection of addresses - */ - DDSPIPE_PARTICIPANTS_DllAPI - DiscoveryServerConnectionAddress( - core::types::GuidPrefix discovery_server_guid, - std::set
addresses); - - //! Discovery Server \c GuidPrefix Port getter - DDSPIPE_PARTICIPANTS_DllAPI - core::types::GuidPrefix discovery_server_guid_prefix() const noexcept; - - //! Addresses getter - DDSPIPE_PARTICIPANTS_DllAPI - std::set
addresses() const noexcept; - /** * @brief Whether the address is correct * @@ -75,13 +56,11 @@ class DiscoveryServerConnectionAddress bool operator ==( const DiscoveryServerConnectionAddress& other) const noexcept; -protected: - //! Internal Discovery Server Guid Prefix object - core::types::GuidPrefix discovery_server_guid_prefix_; + core::types::GuidPrefix discovery_server_guid_prefix; //! Internal Addresses object - std::set
addresses_; + std::set
addresses; }; //! \c DiscoveryServerConnectionAddress to stream serializator diff --git a/ddspipe_participants/src/cpp/participant/rtps/DiscoveryServerParticipant.cpp b/ddspipe_participants/src/cpp/participant/rtps/DiscoveryServerParticipant.cpp index 2892886de..76b7d3117 100644 --- a/ddspipe_participants/src/cpp/participant/rtps/DiscoveryServerParticipant.cpp +++ b/ddspipe_participants/src/cpp/participant/rtps/DiscoveryServerParticipant.cpp @@ -200,22 +200,22 @@ DiscoveryServerParticipant::reckon_participant_attributes_( // Invalid connection address, continue with next one logWarning(DDSPIPE_DISCOVERYSERVER_PARTICIPANT, "Discard connection address with remote server: " << - connection_address.discovery_server_guid_prefix() << + connection_address.discovery_server_guid_prefix << " in Participant " << configuration->id << " initialization."); continue; } // Set Server GUID - core::types::GuidPrefix server_prefix = connection_address.discovery_server_guid_prefix(); + core::types::GuidPrefix server_prefix = connection_address.discovery_server_guid_prefix; - for (types::Address address : connection_address.addresses()) + for (types::Address address : connection_address.addresses) { if (!address.is_valid()) { // Invalid ip address, continue with next one logWarning(DDSPIPE_DISCOVERYSERVER_PARTICIPANT, "Discard connection address with remote server: " << - connection_address.discovery_server_guid_prefix() << + connection_address.discovery_server_guid_prefix << " due to invalid ip address " << address.ip() << " in Participant " << configuration->id << " initialization."); continue; diff --git a/ddspipe_participants/src/cpp/testing/arbitrary_values.cpp b/ddspipe_participants/src/cpp/testing/arbitrary_values.cpp new file mode 100644 index 000000000..3f55eccb3 --- /dev/null +++ b/ddspipe_participants/src/cpp/testing/arbitrary_values.cpp @@ -0,0 +1,59 @@ +// Copyright 2021 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include +#include + +namespace eprosima { +namespace ddspipe { +namespace core { +namespace testing { + +using namespace eprosima::ddspipe::participants::types; + +template <> +Address arbitrary( + unsigned int seed /* = 0 */) +{ + // TODO do it more generic and arbitrary + return Address("127.0.0.1", 10000 + seed, 10000 + seed, TransportProtocol::udp); +} + +template <> +DiscoveryServerConnectionAddress arbitrary( + unsigned int seed /* = 0 */) +{ + DiscoveryServerConnectionAddress object; + + object.discovery_server_guid_prefix = arbitrary(seed); + + unsigned int size = seed % 10; + + // TODO do it more generic and arbitrary + for (unsigned int i = 0; i < size; ++i) + { + object.addresses.insert( + arbitrary
((seed + i))); + } + + return object; +} + +} /* namespace testing */ +} /* namespace core */ +} /* namespace ddspipe */ +} /* namespace eprosima */ diff --git a/ddspipe_participants/src/cpp/testing/random_values.cpp b/ddspipe_participants/src/cpp/testing/random_values.cpp index 2f535513a..f6b15a82c 100644 --- a/ddspipe_participants/src/cpp/testing/random_values.cpp +++ b/ddspipe_participants/src/cpp/testing/random_values.cpp @@ -41,10 +41,12 @@ DiscoveryServerConnectionAddress random_connection_address( random_address((seed + i))); } - return DiscoveryServerConnectionAddress( - core::testing::random_guid_prefix(seed, ros), - addresses - ); + DiscoveryServerConnectionAddress obj; + + obj.discovery_server_guid_prefix = core::testing::random_guid_prefix(seed, ros), + obj.addresses = addresses; + + return obj; } } /* namespace testing */ diff --git a/ddspipe_participants/src/cpp/types/address/DiscoveryServerConnectionAddress.cpp b/ddspipe_participants/src/cpp/types/address/DiscoveryServerConnectionAddress.cpp index d23de30cd..740661206 100644 --- a/ddspipe_participants/src/cpp/types/address/DiscoveryServerConnectionAddress.cpp +++ b/ddspipe_participants/src/cpp/types/address/DiscoveryServerConnectionAddress.cpp @@ -19,32 +19,14 @@ namespace ddspipe { namespace participants { namespace types { -DiscoveryServerConnectionAddress::DiscoveryServerConnectionAddress( - core::types::GuidPrefix discovery_server_guid, - std::set
addresses) - : discovery_server_guid_prefix_(discovery_server_guid) - , addresses_(addresses) -{ -} - -core::types::GuidPrefix DiscoveryServerConnectionAddress::discovery_server_guid_prefix() const noexcept -{ - return discovery_server_guid_prefix_; -} - -std::set
DiscoveryServerConnectionAddress::addresses() const noexcept -{ - return addresses_; -} - bool DiscoveryServerConnectionAddress::is_valid() const noexcept { - if (!discovery_server_guid_prefix_.is_valid()) + if (!discovery_server_guid_prefix.is_valid()) { return false; } - for (auto address : addresses_) + for (auto address : addresses) { if (address.is_valid()) { @@ -58,31 +40,31 @@ bool DiscoveryServerConnectionAddress::is_valid() const noexcept bool DiscoveryServerConnectionAddress::operator <( const DiscoveryServerConnectionAddress& other) const noexcept { - if (this->discovery_server_guid_prefix() == other.discovery_server_guid_prefix()) + if (this->discovery_server_guid_prefix == other.discovery_server_guid_prefix) { // Same Guid - return this->addresses() < other.addresses(); + return this->addresses < other.addresses; } else { // Different guid - return this->discovery_server_guid_prefix() < other.discovery_server_guid_prefix(); + return this->discovery_server_guid_prefix < other.discovery_server_guid_prefix; } } bool DiscoveryServerConnectionAddress::operator ==( const DiscoveryServerConnectionAddress& other) const noexcept { - return (this->discovery_server_guid_prefix() == other.discovery_server_guid_prefix()) && - (this->addresses() == other.addresses()); + return (this->discovery_server_guid_prefix == other.discovery_server_guid_prefix) && + (this->addresses == other.addresses); } std::ostream& operator <<( std::ostream& output, const DiscoveryServerConnectionAddress& address) { - output << "{{" << address.discovery_server_guid_prefix() << "}["; - for (auto a : address.addresses()) + output << "{{" << address.discovery_server_guid_prefix << "}["; + for (auto a : address.addresses) { output << a << ","; } diff --git a/ddspipe_yaml/include/ddspipe_yaml/YamlReader.hpp b/ddspipe_yaml/include/ddspipe_yaml/YamlReader.hpp deleted file mode 100644 index 0f0954e60..000000000 --- a/ddspipe_yaml/include/ddspipe_yaml/YamlReader.hpp +++ /dev/null @@ -1,268 +0,0 @@ -// Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima). -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include -#include - -#include -#include - -namespace eprosima { -namespace ddspipe { -namespace yaml { - -/** - * @brief Yaml Configuration Version - * - * With each version, the yaml format could change in different aspects - * - new fields - * - eliminate fields - * - change key words / tags - * - change requirement of field - * - etc. - * - * Each version is stored in a value of this enumeration, and each \c get method (without tag) is speciallized - * for each different versions. - * - * There is a version call \c LATEST that refers to the lates valid Yaml Configuration Versions. - * Most elemnts will not change from a version change to other. Thus, all of them must be implemented as - * the \c LATEST version, and then if a specific object changes with a specific version, implement that version - * (not latest) separately. - * This way, any new version uses \c LATEST as default implementation, and old versions that diverged from latest - * have their own implementation. As old versions will not change, those methods are definitive, and do not - * need further maintenance. - */ -enum YamlReaderVersion -{ - /** - * @brief First version. - * - * @version 0.1.0 - * @version 0.2.0 - */ - V_1_0, - - /** - * @brief Version 2.0 - * - * @version 0.3.0 - * - * - Adds builtin-topics tag. - * - Adds participants list. - * - Changes the parent of guid for DS to a new tag discovery-server-guid. - * - Adds domain tag in Address to remplace ip when DNS. - */ - V_2_0, - - /** - * @brief Latest version. - * - * @version 0.4.0 - * - * - Change wan to initial peers participant - * - Add Specs - */ - V_3_0, - - /** - * @brief Main version. - * - * This is the version used when the method is not specialized regarding the version, - * or the latest version when it does. - */ - LATEST, -}; - -/** - * @brief Class that encapsulates methods to get values from Yaml Node. - * - * Every method is implemented - */ -class - DDSPIPE_YAML_DllAPI - YamlReader -{ -public: - - /** - * @brief Whether key \c tag is present in \c yml - * - * The key \c tag must be in base level of \c yml , it will no be looked for recursively. - * - * It could only look for keys in yaml map and empty yaml. It will fail in array and scalar cases. - * In this second case, return will always be false. - * - * @param yml base yaml - * @param tag key to look for in \c yml - * @return true id \c tag is a key in \c yml - * @return false otherwise - * - * @throw \c ConfigurationException if \c yml is not a map or empty yaml - */ - static bool is_tag_present( - const Yaml& yml, - const TagType& tag); - - /** - * @brief Get the yaml inside key \c tag in \c yml - * - * \c tag must be present in \c yml . It uses \c is_tag_present to check the key is present. - * Use \c is_tag_present before calling this method in order to avoid the exception. - * - * @param yml base yaml - * @param tag key refering the value returned - * @return yaml value inside key \c tag - * - * @throw \c ConfigurationException if \c tag is not present in \c yml - */ - static Yaml get_value_in_tag( - const Yaml& yml, - const TagType& tag); - - //! TODO comment - template - static T get( - const Yaml& yml, - const YamlReaderVersion version); - - //! Get element inside \c tag - template - static T get( - const Yaml& yml, - const TagType& tag, - const YamlReaderVersion version); - - /** - * @brief Fill an element given by parameter with the values inside \c yml - * - * This method simplifies the process of retrieving an object whose parent has its own \c fill method, - * as the code is reused from one another calling parent \c fill in child. - * It is also very helpful to handle default creation values. Without this, every different default value - * must have its own if-else clause, forcing to create the respective constructor. With this method, - * the default values are initialized with the default constructor, and then are overwritten by the yaml. - * [this problem arises because C++ does not allow different order of parameters in method call] - */ - template - static void fill( - T& object, - const Yaml& yml, - const YamlReaderVersion version); - - //! Fill an element given by parameter with the values inside \c tag in \c yml - template - static void fill( - T& object, - const Yaml& yml, - const TagType& tag, - const YamlReaderVersion version); - - //! TODO comment - template - static std::list get_list( - const Yaml& yml, - const YamlReaderVersion version); - - //! Get list inside \c tag - template - static std::list get_list( - const Yaml& yml, - const TagType& tag, - const YamlReaderVersion version); - - /** - * @brief Get set inside \c tag - * - * It get a list of elements T with \c get_list and then convert it to set. - * - * @tparam T type of each object of the set - * @param yml base yaml - * @param tag key to yaml containing set - * @param version configuration version - * @return set of elements - */ - template - static std::set get_set( - const Yaml& yml, - const TagType& tag, - const YamlReaderVersion version); - - //! TODO comment - template - static T get_scalar( - const Yaml& yml); - - //! Get scalar value inside \c tag - template - static T get_scalar( - const Yaml& yml, - const TagType& tag); - - //! Get positive integer value inside \c tag - static unsigned int get_positive_int( - const Yaml& yml, - const TagType& tag); - - //! Get positive float value inside \c tag - static float get_positive_float( - const Yaml& yml, - const TagType& tag); - - //! Get positive double value inside \c tag - static double get_positive_double( - const Yaml& yml, - const TagType& tag); - - //! TODO comment - template - static T get_enumeration( - const Yaml& yml, - const std::map& enum_values); - - //! Get enumeration value inside \c tag - template - static T get_enumeration( - const Yaml& yml, - const TagType& tag, - const std::map& enum_values); - - //! TODO comment - template - static T get_enumeration_from_builder( - const Yaml& yml, - const utils::EnumBuilder& enum_builder); - - //! Get enumeration value inside \c tag - template - static T get_enumeration_from_builder( - const Yaml& yml, - const TagType& tag, - const utils::EnumBuilder& enum_builder); -}; - -/** - * @brief \c YamlReaderVersion to stream serialization - */ -DDSPIPE_YAML_DllAPI -std::ostream& operator <<( - std::ostream& os, - const YamlReaderVersion& version); - -} /* namespace yaml */ -} /* namespace ddspipe */ -} /* namespace eprosima */ - -// Include implementation template file -#include diff --git a/ddspipe_yaml/include/ddspipe_yaml/YamlWriter.hpp b/ddspipe_yaml/include/ddspipe_yaml/core/Yaml.hpp similarity index 51% rename from ddspipe_yaml/include/ddspipe_yaml/YamlWriter.hpp rename to ddspipe_yaml/include/ddspipe_yaml/core/Yaml.hpp index b88d37b0f..5b93ca25a 100644 --- a/ddspipe_yaml/include/ddspipe_yaml/YamlWriter.hpp +++ b/ddspipe_yaml/include/ddspipe_yaml/core/Yaml.hpp @@ -1,4 +1,4 @@ -// Copyright 2023 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima). // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -14,13 +14,68 @@ #pragma once +#include + +#include + #include -#include namespace eprosima { namespace ddspipe { namespace yaml { +/** + * Configuration is in dictionary format + * + * YAML spec: https://yaml.org/spec/1.2.2/ + * + * @note It is not legal to repeat keys in a YAML + * + * @note this object contains a reference to the actual yaml object. Thus passing it by value or by reference + * makes no different. + */ +using Yaml = YAML::Node; + +//! Type of tag in the yaml +using TagType = std::string; + +/** + * @brief Whether key \c tag is present in \c yml + * + * The key \c tag must be in base level of \c yml , it will no be looked for recursively. + * + * It could only look for keys in yaml map and empty yaml. It will fail in array and scalar cases. + * In this second case, return will always be false. + * + * @param yml base yaml + * @param tag key to look for in \c yml + * @return true id \c tag is a key in \c yml + * @return false otherwise + * + * @throw \c ConfigurationException if \c yml is not a map or empty yaml + */ +DDSPIPE_YAML_DllAPI +bool is_tag_present( + const Yaml& yml, + const TagType& tag); + +/** + * @brief Get the yaml inside key \c tag in \c yml + * + * \c tag must be present in \c yml . It uses \c is_tag_present to check the key is present. + * Use \c is_tag_present before calling this method in order to avoid the exception. + * + * @param yml base yaml + * @param tag key refering the value returned + * @return yaml value inside key \c tag + * + * @throw \c ConfigurationException if \c tag is not present in \c yml + */ +DDSPIPE_YAML_DllAPI +Yaml get_value_in_tag( + const Yaml& yml, + const TagType& tag); + /** * @brief Add a new yaml under tag \c tag . * @@ -46,35 +101,6 @@ Yaml add_tag( bool initialize = false, bool overwrite = true); -/** - * @brief Set a new value in \c yml . - * - * This method is thought to be specialized for each different type coding the serialization method to a yaml. - * - * @param yml base yaml where to write the value - * @param value value to write - * - * @tparam T type of the value to set in the yaml. - * - * @note some specializations are already implemented: - * - native types (int, string, boolean) - * - collections (vector, set, map) - */ -template -void set( - Yaml& yml, - const T& value); - -//! Set the \c value in a new yaml in \c yml under \c tag . -template -void set( - Yaml& yml, - const TagType& tag, - const T& value); - } /* namespace yaml */ } /* namespace ddspipe */ } /* namespace eprosima */ - -// Include implementation template file -#include diff --git a/ddspipe_yaml/include/ddspipe_yaml/YamlManager.hpp b/ddspipe_yaml/include/ddspipe_yaml/core/YamlFileManager.hpp similarity index 92% rename from ddspipe_yaml/include/ddspipe_yaml/YamlManager.hpp rename to ddspipe_yaml/include/ddspipe_yaml/core/YamlFileManager.hpp index a74f0a205..7e55d80f4 100644 --- a/ddspipe_yaml/include/ddspipe_yaml/YamlManager.hpp +++ b/ddspipe_yaml/include/ddspipe_yaml/core/YamlFileManager.hpp @@ -15,7 +15,7 @@ #pragma once #include -#include +#include namespace eprosima { namespace ddspipe { @@ -24,7 +24,7 @@ namespace yaml { /** * Class that manages generic methods related with yaml load and yaml validation. */ -class DDSPIPE_YAML_DllAPI YamlManager +class DDSPIPE_YAML_DllAPI YamlFileManager { public: diff --git a/ddspipe_yaml/include/ddspipe_yaml/field/YamlObjectField.hpp b/ddspipe_yaml/include/ddspipe_yaml/field/YamlObjectField.hpp new file mode 100644 index 000000000..bd87fd101 --- /dev/null +++ b/ddspipe_yaml/include/ddspipe_yaml/field/YamlObjectField.hpp @@ -0,0 +1,71 @@ +// Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// !! WARNING !! +// NO RESPONSIBILITY SHALL BE TAKEN FOR ANY ISSUES CAUSED BY THE MISUSE OF THIS FILE +// This file is meant for developers only, and must not be used from any non expert. +// Only classes and methods in this file should be used, and not the ones in .ipp, +// and only inside read and write YAML methods + +#pragma once + +#include + +#include +#include + +#include +#include + +namespace eprosima { +namespace ddspipe { +namespace yaml { + +ENUMERATION_BUILDER +( + OptionalKind, + required, + optional, + advisable, + extra +); + +// Forward declaration +class IYamlObjectField; + +template +utils::Heritable create_object_field( + const std::string& tag, + const OptionalKind& kind, + const T& vessel); + +template +std::vector> object_fields(const T& object); + +template +void read_from_fields( + const Yaml& yml, + T& object); + +template +void write_from_fields( + Yaml& yml, + const T& object); + +} /* namespace yaml */ +} /* namespace ddspipe */ +} /* namespace eprosima */ + +// Include implementation template file +#include diff --git a/ddspipe_yaml/include/ddspipe_yaml/field/impl/YamlObjectField.ipp b/ddspipe_yaml/include/ddspipe_yaml/field/impl/YamlObjectField.ipp new file mode 100644 index 000000000..ca4e8c970 --- /dev/null +++ b/ddspipe_yaml/include/ddspipe_yaml/field/impl/YamlObjectField.ipp @@ -0,0 +1,181 @@ +// Copyright 2023 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +#include +#include + +namespace eprosima { +namespace ddspipe { +namespace yaml { + +//////////////////////////////////////////////// +// DEFINITIONS +//////////////////////////////////////////////// +// These definitions are hidden from user and thus they are in .ipp + +class IYamlObjectField +{ +public: + virtual ~IYamlObjectField() = default; + virtual void read_field(const Yaml& yml) = 0; + virtual void write_field(Yaml& yml) const = 0; + virtual std::string tag() const noexcept = 0; +}; + +template +class YamlObjectField : public IYamlObjectField +{ +public: + + YamlObjectField( + const std::string& tag, + const OptionalKind& kind, + T& vessel); + + YamlObjectField( + const std::string& tag, + const OptionalKind& kind, + const T& vessel); + + virtual void read_field( + const Yaml& yml) override; + + virtual void write_field( + Yaml& yml) const override; + + virtual std::string tag() const noexcept override; + +protected: + + std::string tag_; + OptionalKind kind_; + T& vessel_; +}; + +DDSPIPE_YAML_DllAPI +void read_fields( + const Yaml& yml, + const std::vector>& fields, + bool fail_with_extra_tags = false, + bool show_warning_with_extra_tags = true); + +DDSPIPE_YAML_DllAPI +void write_fields( + Yaml& yml, + const std::vector>& fields); + +//////////////////////////////////////////////// +// IMPLEMENTATIONS +//////////////////////////////////////////////// + +template +YamlObjectField::YamlObjectField( + const std::string& tag, + const OptionalKind& kind, + const T& vessel) + : tag_(tag) + , kind_(kind) + , vessel_(const_cast(vessel)) +{ + // Do nothing + + // WARNING: This ctor does something that SHOULD NOT BE DONE + // It cast a const reference to non const. This is done because we assume this will be used wisely + // and non const variables will be tried to be written. + // However it suppose a risk that may change in the future if we find a way to solve the following problem: + // There is NO WAY to write function object_fields commonly for const and non const variables. + // So instead of forcing developer to write it twice for each type, it is just written once and here cast is made. +} + +template +void YamlObjectField::read_field( + const Yaml& yml) +{ + bool present = is_tag_present(yml, this->tag_); + if (present) + { + // If value in tag present, read it + read(yml, this->tag_, vessel_); + } + else if (this->kind_ == OptionalKind::required) + { + // If field was required and it is not present, fail + throw eprosima::utils::ConfigurationException(STR_ENTRY + << "Required tag <" << this->tag_ + << "> not present."); + } + else if (this->kind_ == OptionalKind::advisable) + { + // If field was advisable and it is not present, show warning + logWarning(DDSPIPE_YAML, "Tag <" << this->tag_ << "> is advisable but not present in YAML."); + } +} + +template +void YamlObjectField::write_field( + Yaml& yml) const +{ + // Write every field except extra ones + if (kind_ != OptionalKind::extra) + { + write(yml, tag_, vessel_); + } +} + +template +std::string YamlObjectField::tag() const noexcept +{ + return tag_; +} + +template +utils::Heritable create_object_field( + const std::string& tag, + const OptionalKind& kind, + const T& vessel) +{ + return utils::Heritable>::make_heritable( + YamlObjectField(tag, kind, vessel)); +} + +template +void read_from_fields( + const Yaml& yml, + T& object) +{ + read_fields( + yml, + object_fields(object) + ); +} + +template +void write_from_fields( + Yaml& yml, + const T& object) +{ + write_fields( + yml, + object_fields(object) + ); +} + +} /* namespace yaml */ +} /* namespace ddspipe */ +} /* namespace eprosima */ diff --git a/ddspipe_yaml/include/ddspipe_yaml/impl/YamlReader.ipp b/ddspipe_yaml/include/ddspipe_yaml/impl/YamlReader.ipp deleted file mode 100644 index 7b79d1e29..000000000 --- a/ddspipe_yaml/include/ddspipe_yaml/impl/YamlReader.ipp +++ /dev/null @@ -1,241 +0,0 @@ -// Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima). -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include -#include -#include -#include - -namespace eprosima { -namespace ddspipe { -namespace yaml { - -template -T YamlReader::get( - const Yaml& yml, - const TagType& tag, - const YamlReaderVersion version) -{ - // ATTENTION: This try catch can be avoided, it is only used to add verbose information - try - { - return get(get_value_in_tag(yml, tag), version); - } - catch (const std::exception& e) - { - throw eprosima::utils::ConfigurationException( - utils::Formatter() << - "Error getting required value of type <" << TYPE_NAME(T) << - "> in tag <" << tag << "> :\n " << e.what()); - } -} - -template -void YamlReader::fill( - T& object, - const Yaml& yml, - const TagType& tag, - const YamlReaderVersion version) -{ - // ATTENTION: This try catch can be avoided, it is only used to add verbose information - try - { - return fill(get_value_in_tag(yml, tag), object, version); - } - catch (const std::exception& e) - { - throw eprosima::utils::ConfigurationException( - utils::Formatter() << - "Error filling object of type <" << TYPE_NAME(T) << - "> in tag <" << tag << "> :\n " << e.what()); - } -} - -template -T YamlReader::get_scalar( - const Yaml& yml, - const TagType& tag) -{ - try - { - return get_scalar(get_value_in_tag(yml, tag)); - } - catch (const std::exception& e) - { - throw eprosima::utils::ConfigurationException( - utils::Formatter() << "Error reading yaml scalar under tag <" << tag << "> :\n " << e.what()); - } -} - -template -T YamlReader::get_scalar( - const Yaml& yml) -{ - if (!yml.IsScalar()) - { - throw eprosima::utils::ConfigurationException( - utils::Formatter() << - "Trying to read a primitive value of type <" << TYPE_NAME(T) << "> from a non scalar yaml."); - } - - try - { - return yml.as(); - } - catch (const std::exception& e) - { - throw eprosima::utils::ConfigurationException( - utils::Formatter() << - "Incorrect format for primitive value, expected <" << TYPE_NAME(T) << ">:\n " << e.what()); - } -} - -template -std::list YamlReader::get_list( - const Yaml& yml, - const TagType& tag, - const YamlReaderVersion version) -{ - try - { - return get_list(get_value_in_tag(yml, tag), version); - } - catch (const std::exception& e) - { - throw eprosima::utils::ConfigurationException( - utils::Formatter() << "Error reading yaml list under tag <" << tag << "> :\n " << e.what()); - } -} - -template -std::list YamlReader::get_list( - const Yaml& yml, - const YamlReaderVersion version) -{ - if (!yml.IsSequence()) - { - throw eprosima::utils::ConfigurationException( - utils::Formatter() << "Incorrect format, yaml Sequence expected."); - } - - std::list result; - - try - { - for (Yaml element : yml) - { - result.push_back(get(element, version)); - } - } - catch (const std::exception& e) - { - throw eprosima::utils::ConfigurationException( - utils::Formatter() << "Error reading yaml sequence of type <" << TYPE_NAME(T) << "> :\n " << - e.what()); - } - - return result; -} - -template -std::set YamlReader::get_set( - const Yaml& yml, - const TagType& tag, - const YamlReaderVersion version) -{ - std::list elements_list = get_list(yml, tag, version); - return std::set(elements_list.begin(), elements_list.end()); -} - -template -T YamlReader::get_enumeration( - const Yaml& yml, - const TagType& tag, - const std::map& enum_values) -{ - try - { - return get_enumeration(get_value_in_tag(yml, tag), enum_values); - } - catch (const std::exception& e) - { - throw eprosima::utils::ConfigurationException( - utils::Formatter() << "Error reading enumeration value under tag <" << tag << "> :\n " << e.what()); - } -} - -template -T YamlReader::get_enumeration( - const Yaml& yml, - const std::map& enum_values) -{ - TagType value = get_scalar(yml); - - // Find value - auto it = enum_values.find(value); - - if (it == enum_values.end()) - { - throw eprosima::utils::ConfigurationException( - utils::Formatter() << "Value <" << value << "> is not valid in enumeration <" << TYPE_NAME(T) << "."); - } - else - { - return it->second; - } -} - -template -T YamlReader::get_enumeration_from_builder( - const Yaml& yml, - const utils::EnumBuilder& enum_builder) -{ - std::string str_value = get_scalar(yml); - T enum_value; - bool found = enum_builder.string_to_enumeration(str_value, enum_value); - - if (found) - { - return enum_value; - } - else - { - throw eprosima::utils::ConfigurationException(utils::Formatter() - << "Value <" << str_value << "> cannot be parsed as enum <" << TYPE_NAME(T) << ">."); - } -} - -template -T YamlReader::get_enumeration_from_builder( - const Yaml& yml, - const TagType& tag, - const utils::EnumBuilder& enum_builder) -{ - try - { - return get_enumeration_from_builder(get_value_in_tag(yml, tag), enum_builder); - } - catch (const std::exception& e) - { - throw eprosima::utils::ConfigurationException(utils::Formatter() - << "Error reading enumeration from builder under tag <" - << tag << "> :\n " << e.what()); - } -} - -} /* namespace yaml */ -} /* namespace ddspipe */ -} /* namespace eprosima */ diff --git a/ddspipe_yaml/include/ddspipe_yaml/impl/YamlWriter.ipp b/ddspipe_yaml/include/ddspipe_yaml/impl/YamlWriter.ipp deleted file mode 100644 index 0845b7c09..000000000 --- a/ddspipe_yaml/include/ddspipe_yaml/impl/YamlWriter.ipp +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright 2023 Proyectos y Sistemas de Mantenimiento SL (eProsima). -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include -#include -#include -#include - -#include - -#include -#include - -namespace eprosima { -namespace ddspipe { -namespace yaml { - -template -void set( - Yaml& yml, - const std::vector& collection); - -template -void set( - Yaml& yml, - const std::set& collection); - -template -void set( - Yaml& yml, - const std::map& collection); - -template -void set_collection( - Yaml& yml, - const std::vector& collection); - -template -void set_map( - Yaml& yml, - const std::map& collection); - -//////////////////////////////////////////////// -// SPECIALIZATIONS FOR TRIVIAL TYPES -//////////////////////////////////////////////// - -template <> -DDSPIPE_YAML_DllAPI -void set( - Yaml& yml, - const std::string& value); - -template <> -DDSPIPE_YAML_DllAPI -void set( - Yaml& yml, - const bool& value); - -template <> -DDSPIPE_YAML_DllAPI -void set( - Yaml& yml, - const int& value); - -//////////////////////////////////////////////// -// SPECIALIZATIONS FOR OTHER TYPES -//////////////////////////////////////////////// - -template -void set( - Yaml& yml, - const std::vector& collection) -{ - set_collection(yml, collection); -} - -template -void set( - Yaml& yml, - const std::set& collection) -{ - set_collection(yml, std::vector(collection.begin(), collection.end())); -} - -template -void set( - Yaml& yml, - const std::map& collection) -{ - set_map(yml, collection); -} - -//////////////////////////////////// -// SPECIALIZATIONS NEEDED -//////////////////////////////////// - -template -void set( - Yaml& yml, - const TagType& tag, - const T& value) -{ - auto yml_under_tag = add_tag(yml, tag); - set(yml_under_tag, value); -} - -template -void set_collection( - Yaml& yml, - const std::vector& collection) -{ - for (const auto& v : collection) - { - Yaml yml_value; - set(yml_value, v); - yml.push_back(yml_value); - } -} - -template -void set_map( - Yaml& yml, - const std::map& collection) -{ - for (const auto& v : collection) - { - Yaml yml_in_new_tag = yml[utils::generic_to_string(v.first)]; - set(yml_in_new_tag, v.second); - } -} - -} /* namespace yaml */ -} /* namespace ddspipe */ -} /* namespace eprosima */ diff --git a/ddspipe_yaml/include/ddspipe_yaml/reader/YamlReader.hpp b/ddspipe_yaml/include/ddspipe_yaml/reader/YamlReader.hpp new file mode 100644 index 000000000..57df0de6e --- /dev/null +++ b/ddspipe_yaml/include/ddspipe_yaml/reader/YamlReader.hpp @@ -0,0 +1,71 @@ +// Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include + +#include +#include + +namespace eprosima { +namespace ddspipe { +namespace yaml { + +/** + * @brief Fill an element given by parameter with the values inside \c yml + * + * This method simplifies the process of retrieving an object whose parent has its own \c read method, + * as the code is reused from one another calling parent \c read in child. + * It is also very helpful to handle default creation values. Without this, every different default value + * must have its own if-else clause, forcing to create the respective constructor. With this method, + * the default values are initialized with the default constructor, and then are overwritten by the yaml. + * [this problem arises because C++ does not allow different order of parameters in method call] + */ +template +void read( + const Yaml& yml, + T& object); + +//! Fill an element given by parameter with the values inside \c tag in \c yml +template +void read( + const Yaml& yml, + const TagType& tag, + T& object); + +template +T read( + const Yaml& yml); + +template +T read( + const Yaml& yml, + const TagType& tag); + +//! Fill \c object with a Yaml structure +template +void operator <<( + T& object, + const Yaml& yml); + +} /* namespace yaml */ +} /* namespace ddspipe */ +} /* namespace eprosima */ + +// Include implementation template file +#include +#include diff --git a/ddspipe_yaml/include/ddspipe_yaml/reader/impl/YamlReader_declarations.ipp b/ddspipe_yaml/include/ddspipe_yaml/reader/impl/YamlReader_declarations.ipp new file mode 100644 index 000000000..d254d5355 --- /dev/null +++ b/ddspipe_yaml/include/ddspipe_yaml/reader/impl/YamlReader_declarations.ipp @@ -0,0 +1,82 @@ +// Copyright 2023 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include +#include + +#include + +namespace eprosima { +namespace ddspipe { +namespace yaml { + +//////////////////////////////////////////////// +// DEFINITION OF SPECIFIC TYPES +//////////////////////////////////////////////// + +template +T read_enumeration( + const Yaml& yml, + const std::map& enum_values); + +//////////////////////////////////////////////// +// DEFINITION OF FUNCTIONS FOR TEMPLATED TYPES +//////////////////////////////////////////////// + +template +void read_fuzzy( + const Yaml& yml, + utils::Fuzzy& fuzzy); + +template +void read_collection( + const Yaml& yml, + std::vector& collection); + +template +void read_map( + const Yaml& yml, + std::map& collection); + +//////////////////////////////////////////////// +// SPECIALIZATION DECLARATIONS FOR TEMPLATED TYPES +//////////////////////////////////////////////// + +template +void read( + const Yaml& yml, + utils::Fuzzy& fuzzy); + +template +void read( + const Yaml& yml, + std::vector& collection); + +template +void read( + const Yaml& yml, + std::set& collection); + +template +void read( + const Yaml& yml, + std::map& collection); + +} /* namespace yaml */ +} /* namespace ddspipe */ +} /* namespace eprosima */ diff --git a/ddspipe_yaml/include/ddspipe_yaml/reader/impl/YamlReader_implementations.ipp b/ddspipe_yaml/include/ddspipe_yaml/reader/impl/YamlReader_implementations.ipp new file mode 100644 index 000000000..21a97bd86 --- /dev/null +++ b/ddspipe_yaml/include/ddspipe_yaml/reader/impl/YamlReader_implementations.ipp @@ -0,0 +1,183 @@ +// Copyright 2023 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include +#include + +namespace eprosima { +namespace ddspipe { +namespace yaml { + +//////////////////////////////////////////////// +// DEFINITION OF SPECIFIC TYPES +//////////////////////////////////////////////// + +template +T read_enumeration( + const Yaml& yml, + const std::map& enum_values) +{ + TagType value; + read(yml, value); + + // Find value + auto it = enum_values.find(value); + + if (it == enum_values.end()) + { + throw eprosima::utils::ConfigurationException( + STR_ENTRY << "Value <" << value << "> is not valid in enumeration <" << TYPE_NAME(T) << "."); + } + else + { + return it->second; + } +} + +//////////////////////////////////////////////// +// DEFINITION OF FUNCTIONS FOR TEMPLATED TYPES +//////////////////////////////////////////////// + +template +void read_fuzzy( + const Yaml& yml, + utils::Fuzzy& fuzzy) +{ + read(yml, fuzzy.get_reference()); + fuzzy.set_level(); +} + +template +void read_collection( + const Yaml& yml, + std::vector& collection) +{ + if (!yml.IsSequence()) + { + throw eprosima::utils::ConfigurationException( + STR_ENTRY << "Incorrect format, yaml Sequence expected."); + } + + try + { + for (Yaml yml_element : yml) + { + collection.push_back(read(yml_element)); + } + } + catch (const std::exception& e) + { + throw eprosima::utils::ConfigurationException( + STR_ENTRY << "Error reading yaml sequence of type <" << TYPE_NAME(T) << "> :\n " << + e.what()); + } +} + +//////////////////////////////////////////////// +// SPECIALIZATION DECLARATIONS FOR TEMPLATED TYPES +//////////////////////////////////////////////// + +template +void read( + const Yaml& yml, + utils::Fuzzy& fuzzy) +{ + read_fuzzy(yml, fuzzy); +} + +template +void read( + const Yaml& yml, + std::vector& collection) +{ + read_collection(yml, collection); +} + +template +void read( + const Yaml& yml, + std::set& collection) +{ + std::vector collection_vector; + read_collection(yml, collection_vector); + collection = std::set(collection_vector.begin(), collection_vector.end()); +} + +template +void read( + const Yaml& yml, + std::map& collection) +{ + read_map(yml, collection); +} + +//////////////////////////////////////////////// +// SPECIALIZATIONS OF SPECIFIC FUNCTIONS +//////////////////////////////////////////////// + +template +void read( + const Yaml& yml, + const TagType& tag, + T& object) +{ + // ATTENTION: This try catch can be avoided, it is only used to add verbose information + try + { + return read(get_value_in_tag(yml, tag), object); + } + catch (const std::exception& e) + { + throw eprosima::utils::ConfigurationException( + STR_ENTRY << + "Error reading object of type <" << TYPE_NAME(T) << + "> in tag <" << tag << "> :\n " << e.what()); + } +} + + +template +T read( + const Yaml& yml) +{ + T object; + read(yml, object); + return object; +} + +template +T read( + const Yaml& yml, + const TagType& tag) +{ + T object; + read(yml, tag, object); + return object; +} + +template +void operator <<( + T& object, + const Yaml& yml) +{ + read(yml, object); +} + +} /* namespace yaml */ +} /* namespace ddspipe */ +} /* namespace eprosima */ diff --git a/ddspipe_yaml/include/ddspipe_yaml/yaml_configuration_tags.hpp b/ddspipe_yaml/include/ddspipe_yaml/tags/yaml_configuration_tags.hpp similarity index 100% rename from ddspipe_yaml/include/ddspipe_yaml/yaml_configuration_tags.hpp rename to ddspipe_yaml/include/ddspipe_yaml/tags/yaml_configuration_tags.hpp diff --git a/ddspipe_yaml/include/ddspipe_yaml/testing/generate_yaml.hpp b/ddspipe_yaml/include/ddspipe_yaml/testing/generate_yaml.hpp deleted file mode 100644 index fb68838d8..000000000 --- a/ddspipe_yaml/include/ddspipe_yaml/testing/generate_yaml.hpp +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima). -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -namespace eprosima { -namespace ddspipe { -namespace yaml { -namespace testing { - -template -struct YamlField -{ - YamlField() - : present(false) - { - } - - YamlField( - const T& arg_value, - bool arg_present = true) - : value(arg_value) - , present(arg_present) - { - } - - T value; - bool present; -}; - -template -void add_field_to_yaml( - Yaml& yml, - const YamlField& field, - const std::string& tag) -{ - if (field.present) - { - yml[tag] = field.value; - } -} - -void guid_prefix_to_yaml( - Yaml& yml, - const core::types::GuidPrefix& guid_prefix) -{ - std::stringstream ss; - ss << guid_prefix; - - add_field_to_yaml( - yml, - YamlField(ss.str()), - DISCOVERY_SERVER_GUID_TAG); -} - -void discovery_server_guid_prefix_to_yaml( - Yaml& yml, - const core::types::GuidPrefix& guid_prefix) -{ - Yaml yml_guid; - guid_prefix_to_yaml(yml_guid, guid_prefix); - - yml[DISCOVERY_SERVER_GUID_PREFIX_TAG] = yml_guid; -} - -void address_to_yaml( - Yaml& yml, - const participants::types::Address& address) -{ - add_field_to_yaml( - yml, - YamlField(address.ip()), - ADDRESS_IP_TAG); - - add_field_to_yaml( - yml, - YamlField(address.port()), - ADDRESS_PORT_TAG); - - if (address.transport_protocol() == participants::types::TransportProtocol::udp) - { - add_field_to_yaml( - yml, - YamlField(ADDRESS_TRANSPORT_UDP_TAG), - ADDRESS_TRANSPORT_TAG); - } - else if (address.transport_protocol() == participants::types::TransportProtocol::tcp) - { - add_field_to_yaml( - yml, - YamlField(ADDRESS_TRANSPORT_TCP_TAG), - ADDRESS_TRANSPORT_TAG); - } - - if (address.ip_version() == participants::types::IpVersion::v4) - { - add_field_to_yaml( - yml, - YamlField(ADDRESS_IP_VERSION_V4_TAG), - ADDRESS_IP_VERSION_TAG); - } - else if (address.ip_version() == participants::types::IpVersion::v6) - { - add_field_to_yaml( - yml, - YamlField(ADDRESS_IP_VERSION_V6_TAG), - ADDRESS_IP_VERSION_TAG); - } -} - -void participantid_to_yaml( - Yaml& yml, - const core::types::ParticipantId& id) -{ - add_field_to_yaml( - yml, - YamlField(id), - PARTICIPANT_NAME_TAG); -} - -void domain_to_yaml( - Yaml& yml, - const core::types::DomainId& domain) -{ - add_field_to_yaml( - yml, - YamlField(domain.domain_id), - DOMAIN_ID_TAG); -} - -void repeater_to_yaml( - Yaml& yml, - const bool& repeater) -{ - add_field_to_yaml( - yml, - YamlField(repeater), - IS_REPEATER_TAG); -} - -// Create a yaml QoS object only with reliability -void qos_to_yaml( - Yaml& yml, - const core::types::TopicQoS& qos) -{ - // TODO: extend this for all qos - add_field_to_yaml(yml, YamlField(qos.is_reliable()), QOS_RELIABLE_TAG); -} - -// Create a yaml Topic object with name, type and key tags -void filter_topic_to_yaml( - Yaml& yml, - const core::types::WildcardDdsFilterTopic& topic) -{ - if (topic.topic_name.is_set()) - { - add_field_to_yaml(yml, YamlField(topic.topic_name.get_reference()), TOPIC_NAME_TAG); - } - - if (topic.type_name.is_set()) - { - add_field_to_yaml(yml, YamlField(topic.type_name.get_reference()), TOPIC_TYPE_NAME_TAG); - } -} - -// Create a yaml DdsTopic object with name, type, key and reliable tags -void real_topic_to_yaml( - Yaml& yml, - const core::types::DdsTopic& topic) -{ - add_field_to_yaml(yml, YamlField(topic.m_topic_name), TOPIC_NAME_TAG); - add_field_to_yaml(yml, YamlField(topic.type_name), TOPIC_TYPE_NAME_TAG); - - // QoS - Yaml yml_qos; - qos_to_yaml(yml_qos, topic.topic_qos); - add_field_to_yaml(yml, YamlField(yml_qos), TOPIC_QOS_TAG); -} - -} /* namespace testing */ -} /* namespace yaml */ -} /* namespace ddspipe */ -} /* namespace eprosima */ diff --git a/ddspipe_yaml/include/ddspipe_yaml/writer/YamlWriter.hpp b/ddspipe_yaml/include/ddspipe_yaml/writer/YamlWriter.hpp new file mode 100644 index 000000000..cfe460ef2 --- /dev/null +++ b/ddspipe_yaml/include/ddspipe_yaml/writer/YamlWriter.hpp @@ -0,0 +1,63 @@ +// Copyright 2023 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +namespace eprosima { +namespace ddspipe { +namespace yaml { + +/** + * @brief Set a new object in \c yml . + * + * This method is thought to be specialized for each different type coding the serialization method to a yaml. + * + * @param yml base yaml where to write the object + * @param object object to write + * + * @tparam T type of the object to set in the yaml. + * + * @note some specializations are already implemented: + * - native types (int, string, boolean) + * - collections (vector, set, map) + */ +template +void write( + Yaml& yml, + const T& object); + +//! Set the \c object in a new yaml in \c yml under \c tag . +template +void write( + Yaml& yml, + const TagType& tag, + const T& object); + + +//! Fill Yaml structure with \c object +template +void operator <<( + Yaml& yml, + const T& object); + +} /* namespace yaml */ +} /* namespace ddspipe */ +} /* namespace eprosima */ + +// Include implementation template file +#include +#include diff --git a/ddspipe_yaml/include/ddspipe_yaml/writer/impl/YamlWriter_declarations.ipp b/ddspipe_yaml/include/ddspipe_yaml/writer/impl/YamlWriter_declarations.ipp new file mode 100644 index 000000000..ec99107cf --- /dev/null +++ b/ddspipe_yaml/include/ddspipe_yaml/writer/impl/YamlWriter_declarations.ipp @@ -0,0 +1,109 @@ +// Copyright 2023 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include +#include + +#include + +namespace eprosima { +namespace ddspipe { +namespace yaml { + +//////////////////////////////////////////////// +// DEFINITION OF SPECIFIC TYPES +//////////////////////////////////////////////// + +template +void write_enumeration( + Yaml& yml, + const T& object, + const std::map& enum_values); + +//////////////////////////////////////////////// +// DEFINITION OF FUNCTIONS FOR TEMPLATED TYPES +//////////////////////////////////////////////// + +template +void write_fuzzy( + Yaml& yml, + const utils::Fuzzy& object); + +template +void write_vector( + Yaml& yml, + const std::vector& object); + +template +void write_map( + Yaml& yml, + const std::map& object); + +//////////////////////////////////////////////// +// DEFINITION OF FUNCTIONS FOR TRIVIAL TYPES +//////////////////////////////////////////////// +// These are needed for Dll export + +template <> +void write( + Yaml& yml, + const std::string& object); + +template <> +void write( + Yaml& yml, + const bool& object); + +template <> +void write( + Yaml& yml, + const int& object); + +//////////////////////////////////////////////// +// SPECIALIZATION DECLARATIONS FOR TEMPLATED TYPES +//////////////////////////////////////////////// + +template +void write( + Yaml& yml, + const TagType& tag, + const utils::Fuzzy& object); + +template +void write( + Yaml& yml, + const utils::Fuzzy& object); + +template +void write( + Yaml& yml, + const std::vector& object); + +template +void write( + Yaml& yml, + const std::set& object); + +template +void write( + Yaml& yml, + const std::map& object); + +} /* namespace yaml */ +} /* namespace ddspipe */ +} /* namespace eprosima */ diff --git a/ddspipe_yaml/include/ddspipe_yaml/writer/impl/YamlWriter_implementations.ipp b/ddspipe_yaml/include/ddspipe_yaml/writer/impl/YamlWriter_implementations.ipp new file mode 100644 index 000000000..7e5d99f2a --- /dev/null +++ b/ddspipe_yaml/include/ddspipe_yaml/writer/impl/YamlWriter_implementations.ipp @@ -0,0 +1,158 @@ +// Copyright 2023 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +namespace eprosima { +namespace ddspipe { +namespace yaml { + +//////////////////////////////////////////////// +// DEFINITION OF SPECIFIC TYPES +//////////////////////////////////////////////// + +template +void write_enumeration( + Yaml& yml, + const T& value, + const std::map& enum_values) +{ + // TODO check if value exists + for (const auto& it : enum_values) + { + if (value == it.second) + { + write(yml, it.first); + } + return; + } + + // If it finished without finding value, error + throw utils::InconsistencyException( + STR_ENTRY << "Value <" << value << "> of enumeration type <" << TYPE_NAME(T) << " has no parse value."); +} + +//////////////////////////////////////////////// +// SPECIALIZATIONS FOR TEMPLATED TYPES +//////////////////////////////////////////////// + +template +void write( + Yaml& yml, + const TagType& tag, + const utils::Fuzzy& object) +{ + if (object.is_set()) + { + write(yml, tag, object.get_reference()); + } +} + +template +void write( + Yaml& yml, + const utils::Fuzzy& object) +{ + write_fuzzy(yml, object); +} + +template +void write( + Yaml& yml, + const std::vector& object) +{ + write_vector(yml, object); +} + +template +void write( + Yaml& yml, + const std::set& object) +{ + write_vector(yml, std::vector(object.begin(), object.end())); +} + +template +void write( + Yaml& yml, + const std::map& object) +{ + write_map(yml, object); +} + +//////////////////////////////////////////////// +// SPECIALIZATIONS OF SPECIFIC FUNCTIONS +//////////////////////////////////////////////// + +template +void write( + Yaml& yml, + const TagType& tag, + const T& object) +{ + auto yml_under_tag = add_tag(yml, tag); + write(yml_under_tag, object); +} + +template +void operator <<( + Yaml& yml, + const T& object) +{ + write(yml, object); +} + +//////////////////////////////////////////////// +// SPECIALIZATIONS OF SPECIFIC TYPES FUNCTIONS +//////////////////////////////////////////////// + +template +void write_fuzzy( + Yaml& yml, + const utils::Fuzzy& object) +{ + write(yml, object.get_reference()); +} + +template +void write_vector( + Yaml& yml, + const std::vector& object) +{ + for (const auto& v : object) + { + Yaml yml_value; + write(yml_value, v); + yml.push_back(yml_value); + } +} + +template +void write_map( + Yaml& yml, + const std::map& object) +{ + for (const auto& v : object) + { + Yaml yml_in_new_tag = yml[utils::generic_to_string(v.first)]; + write(yml_in_new_tag, v.second); + } +} + +} /* namespace yaml */ +} /* namespace ddspipe */ +} /* namespace eprosima */ diff --git a/ddspipe_yaml/src/cpp/NewYamlReader_generic._cpp b/ddspipe_yaml/src/cpp/NewYamlReader_generic._cpp new file mode 100644 index 000000000..55d90d866 --- /dev/null +++ b/ddspipe_yaml/src/cpp/NewYamlReader_generic._cpp @@ -0,0 +1,86 @@ +// Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @file YamlReader.cpp + * + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace eprosima { +namespace ddspipe { +namespace yaml { + +using namespace eprosima::ddspipe::core::types; +using namespace eprosima::ddspipe::participants::types; + +/************************ +* GENERIC * +************************/ + +bool is_tag_present( + const Yaml& yml, + const TagType& tag) +{ + if (!yml.IsMap() && !yml.IsNull()) + { + throw eprosima::utils::ConfigurationException( + utils::Formatter() << "Trying to find a tag: <" << tag << "> in a not yaml object map."); + } + + // Explicit conversion to avoid windows format warning + // This method performace is the same as only retrieving bool + return (yml[tag]) ? true : false; +} + +Yaml get_value_in_tag( + const Yaml& yml, + const TagType& tag) +{ + if (is_tag_present(yml, tag)) + { + return yml[tag]; + } + else + { + throw eprosima::utils::ConfigurationException( + utils::Formatter() << "Required tag not found: <" << tag << ">."); + } +} + +} /* namespace yaml */ +} /* namespace ddspipe */ +} /* namespace eprosima */ diff --git a/ddspipe_yaml/src/cpp/YamlReader_generic.cpp b/ddspipe_yaml/src/cpp/YamlReader_generic._cpp similarity index 76% rename from ddspipe_yaml/src/cpp/YamlReader_generic.cpp rename to ddspipe_yaml/src/cpp/YamlReader_generic._cpp index 1e9ae5514..ec68944ce 100644 --- a/ddspipe_yaml/src/cpp/YamlReader_generic.cpp +++ b/ddspipe_yaml/src/cpp/YamlReader_generic._cpp @@ -36,7 +36,7 @@ #include #include -#include +#include #include #include @@ -215,6 +215,72 @@ std::string YamlReader::get( return get_scalar(yml); } +bool check_tags( + const std::vector& tags_allowed, + const Yaml& yml, + bool fail_with_extra_tags /* = true */, + bool fail_with_exception /* = true */) +{ + if (!yml.IsMap() && !yml.IsNull()) + { + throw eprosima::utils::ConfigurationException(STR_ENTRY + << "Trying to check tags: in a not yaml object map."); + } + + // First, check that every required flag is present + for (const auto& field : tags_allowed) + { + if (field.kind == TagKind::required) + { + if (!YamlReader::is_tag_present(yml, field.tag)) + { + if (fail_with_exception) + { + throw eprosima::utils::ConfigurationException(STR_ENTRY + << "Required tag <" << field.tag << "> not present."); + } + else + { + return false; + } + } + } + } + + // Now that every required field is present, check for extra tags + for (const auto& yaml_field : yml) + { + auto tag = yaml_field.first.as(); + bool should_be_present = false; + + // For each tag, check if it is inside allowed tags + for (const auto& field : tags_allowed) + { + if (field.tag == tag) + { + should_be_present = true; + break; + } + } + + // If present tag is not inside allowed ones, fail + if (!should_be_present) + { + if (fail_with_exception) + { + throw eprosima::utils::ConfigurationException(STR_ENTRY + << "Unexpected tag <" << tag << "> present."); + } + else + { + return false; + } + } + } + + return true; +} + } /* namespace yaml */ } /* namespace ddspipe */ } /* namespace eprosima */ diff --git a/ddspipe_yaml/src/cpp/YamlReader_participants.cpp b/ddspipe_yaml/src/cpp/YamlReader_participants._cpp similarity index 99% rename from ddspipe_yaml/src/cpp/YamlReader_participants.cpp rename to ddspipe_yaml/src/cpp/YamlReader_participants._cpp index c9188e829..7abf4e5e5 100644 --- a/ddspipe_yaml/src/cpp/YamlReader_participants.cpp +++ b/ddspipe_yaml/src/cpp/YamlReader_participants._cpp @@ -34,7 +34,7 @@ #include #include -#include +#include #include #include diff --git a/ddspipe_yaml/src/cpp/YamlReader_types.cpp b/ddspipe_yaml/src/cpp/YamlReader_types._cpp similarity index 94% rename from ddspipe_yaml/src/cpp/YamlReader_types.cpp rename to ddspipe_yaml/src/cpp/YamlReader_types._cpp index 74283a6bd..bbfa4ee9d 100644 --- a/ddspipe_yaml/src/cpp/YamlReader_types.cpp +++ b/ddspipe_yaml/src/cpp/YamlReader_types._cpp @@ -37,7 +37,7 @@ #include #include -#include +#include #include #include @@ -264,8 +264,8 @@ DiscoveryServerConnectionAddress _get_discovery_server_connection_address_v1( const YamlReaderVersion version) { // GuidPrefix required - GuidPrefix server_guid = YamlReader::get(yml, version); + GuidPrefix server_guid = YamlReader::get(yml, version); // Addresses required std::set
addresses = YamlReader::get_set
(yml, COLLECTION_ADDRESSES_TAG, version); @@ -384,6 +384,17 @@ void YamlReader::fill( } } +template <> +DDSPIPE_YAML_DllAPI +TopicQoS YamlReader::get( + const Yaml& yml, + const YamlReaderVersion version) +{ + TopicQoS qos; + fill(qos, yml, version); + return qos; +} + /************************ * TOPICS * ************************/ @@ -395,17 +406,17 @@ void YamlReader::fill( const Yaml& yml, const YamlReaderVersion version) { - // Name required - object.m_topic_name = get(yml, TOPIC_NAME_TAG, version); - - // Data Type required - object.type_name = get(yml, TOPIC_TYPE_NAME_TAG, version); - - // Optional QoS - if (is_tag_present(yml, TOPIC_QOS_TAG)) + static const std::vector fields_allowed = { - fill(object.topic_qos, get_value_in_tag(yml, TOPIC_QOS_TAG), version); - } + new YamlFieldGetter(TOPIC_NAME_TAG, TagKind::required, object.m_topic_name), + new YamlFieldGetter(TOPIC_TYPE_NAME_TAG, TagKind::required, object.type_name), + new YamlFieldGetter(TOPIC_QOS_TAG, TagKind::optional, object.topic_qos) + }; + + get_tags( + fields_allowed, + yml + ); } template <> @@ -426,19 +437,16 @@ void YamlReader::fill( const Yaml& yml, const YamlReaderVersion version) { - // Optional name - if (is_tag_present(yml, TOPIC_NAME_TAG)) + static const std::vector fields_allowed = { - object.topic_name.set_value(get(yml, TOPIC_NAME_TAG, version)); - } - - // Optional data type - if (is_tag_present(yml, TOPIC_TYPE_NAME_TAG)) - { - object.type_name.set_value(get(yml, TOPIC_TYPE_NAME_TAG, version)); - } + new YamlFieldGetterFuzzy(TOPIC_NAME_TAG, TagKind::optional, object.topic_name), + new YamlFieldGetterFuzzy(TOPIC_TYPE_NAME_TAG, TagKind::optional, object.type_name) + }; - // TODO: decide whether we want to use QoS as filtering + get_tags( + fields_allowed, + yml + ); } template <> diff --git a/ddspipe_yaml/src/cpp/YamlWriter.cpp b/ddspipe_yaml/src/cpp/core/Yaml.cpp similarity index 60% rename from ddspipe_yaml/src/cpp/YamlWriter.cpp rename to ddspipe_yaml/src/cpp/core/Yaml.cpp index bd7d7b643..2696067fd 100644 --- a/ddspipe_yaml/src/cpp/YamlWriter.cpp +++ b/ddspipe_yaml/src/cpp/core/Yaml.cpp @@ -1,4 +1,4 @@ -// Copyright 2023 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima). // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,16 +12,47 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include + +#include #include -#include -#include -#include +#include namespace eprosima { namespace ddspipe { namespace yaml { +bool is_tag_present( + const Yaml& yml, + const TagType& tag) +{ + if (!yml.IsMap() && !yml.IsNull()) + { + throw eprosima::utils::PreconditionNotMet( + utils::Formatter() << "Trying to find a tag: <" << tag << "> in a not yaml object map."); + } + + // Explicit conversion to avoid windows format warning + // This method performace is the same as only retrieving bool + return (yml[tag]) ? true : false; +} + +Yaml get_value_in_tag( + const Yaml& yml, + const TagType& tag) +{ + if (is_tag_present(yml, tag)) + { + return yml[tag]; + } + else + { + throw eprosima::utils::PreconditionNotMet( + utils::Formatter() << "Required tag not found: <" << tag << ">."); + } +} + Yaml add_tag( Yaml& yml, const TagType& tag, @@ -29,7 +60,7 @@ Yaml add_tag( bool overwrite /* = true */) { // If node must be initialized and could not overwrite, and node already exist, throw failure. - if (initialize && !overwrite && YamlReader::is_tag_present(yml, tag)) + if (initialize && !overwrite && is_tag_present(yml, tag)) { throw utils::PreconditionNotMet( STR_ENTRY @@ -50,30 +81,6 @@ Yaml add_tag( return yml[tag]; } -template <> -void set( - Yaml& yml, - const std::string& value) -{ - yml = value; -} - -template <> -void set( - Yaml& yml, - const bool& value) -{ - yml = value; -} - -template <> -void set( - Yaml& yml, - const int& value) -{ - yml = value; -} - } /* namespace yaml */ } /* namespace ddspipe */ } /* namespace eprosima */ diff --git a/ddspipe_yaml/src/cpp/YamlManager.cpp b/ddspipe_yaml/src/cpp/core/YamlManager.cpp similarity index 89% rename from ddspipe_yaml/src/cpp/YamlManager.cpp rename to ddspipe_yaml/src/cpp/core/YamlManager.cpp index 9c310c8b2..ac9ace8f6 100644 --- a/ddspipe_yaml/src/cpp/YamlManager.cpp +++ b/ddspipe_yaml/src/cpp/core/YamlManager.cpp @@ -12,21 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -/** - * @file YamlManager.cpp - * - */ - #include -#include -#include +#include +#include namespace eprosima { namespace ddspipe { namespace yaml { -Yaml YamlManager::load_file( +Yaml YamlFileManager::load_file( const std::string& file_path) { try diff --git a/ddspipe_yaml/src/cpp/field/YamlObjectField_generic.cpp b/ddspipe_yaml/src/cpp/field/YamlObjectField_generic.cpp new file mode 100644 index 000000000..409bf507a --- /dev/null +++ b/ddspipe_yaml/src/cpp/field/YamlObjectField_generic.cpp @@ -0,0 +1,94 @@ +// Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include +#include + +namespace eprosima { +namespace ddspipe { +namespace yaml { + +void read_fields( + const Yaml& yml, + const std::vector>& fields, + bool fail_with_extra_tags /* = false */, + bool show_warning_with_extra_tags /* = true */) +{ + // Check that yml to find is actually a map or it is empty + if (!yml.IsMap() && !yml.IsNull()) + { + throw eprosima::utils::ConfigurationException(STR_ENTRY + << "Trying to get tags: in a not yaml object map."); + } + + // First, check that every required flag is present + for (const auto& field : fields) + { + field->read_field(yml); + } + + // If it should not show warnings, neither fail, do not check extra args + if (!fail_with_extra_tags && !show_warning_with_extra_tags) + { + return; + } + + // Now that every required field is present, check for extra tags + for (const auto& yaml_field : yml) + { + auto tag = yaml_field.first.as(); + bool should_be_present = false; + + // For each tag, check if it is inside allowed tags + for (const auto& field : fields) + { + if (field->tag() == tag) + { + should_be_present = true; + break; + } + } + + // If present tag is not inside allowed ones, fail + if (!should_be_present) + { + if (fail_with_extra_tags) + { + throw eprosima::utils::ConfigurationException(STR_ENTRY + << "Unexpected tag <" << tag << "> present."); + } + else if(show_warning_with_extra_tags) + { + logWarning(DDSPIPE_YAML, "Unexpected tag <" << tag << "> present."); + } + } + } +} + +void write_fields( + Yaml& yml, + const std::vector>& fields) +{ + for (const auto& field : fields) + { + field->write_field(yml); + } +} + +} /* namespace yaml */ +} /* namespace ddspipe */ +} /* namespace eprosima */ diff --git a/ddspipe_yaml/src/cpp/field/YamlObjectField_types.cpp b/ddspipe_yaml/src/cpp/field/YamlObjectField_types.cpp new file mode 100644 index 000000000..476c0455d --- /dev/null +++ b/ddspipe_yaml/src/cpp/field/YamlObjectField_types.cpp @@ -0,0 +1,83 @@ +// Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include +#include + +#include + +#include +#include +#include + +namespace eprosima { +namespace ddspipe { +namespace yaml { + +template <> +std::vector> object_fields( + const core::types::TopicQoS& object) +{ + // WARNING these fields are not complete + // reliability_qos , durability_qos and ownership_qos are parsed separately + return + { + create_object_field(QOS_HISTORY_DEPTH_TAG, OptionalKind::advisable, object.history_depth), + create_object_field(QOS_PARTITION_TAG, OptionalKind::optional, object.use_partitions), + create_object_field(QOS_DOWNSAMPLING_TAG, OptionalKind::optional, object.downsampling), + create_object_field(QOS_KEYED_TAG, OptionalKind::optional, object.keyed), + create_object_field(QOS_MAX_RECEPTION_RATE_TAG, OptionalKind::optional, object.max_reception_rate), + }; +} + +template <> +std::vector> object_fields( + const core::types::DdsTopic& object) +{ + return + { + create_object_field(TOPIC_NAME_TAG, OptionalKind::required, object.m_topic_name), + create_object_field(TOPIC_TYPE_NAME_TAG, OptionalKind::required, object.type_name), + create_object_field(TOPIC_QOS_TAG, OptionalKind::optional, object.topic_qos) + }; +} + +template <> +std::vector> object_fields( + const core::types::WildcardDdsFilterTopic& object) +{ + return + { + create_object_field(TOPIC_NAME_TAG, OptionalKind::optional, object.topic_name), + create_object_field(TOPIC_TYPE_NAME_TAG, OptionalKind::optional, object.type_name), + }; +} + +template <> +std::vector> object_fields( + const participants::types::DiscoveryServerConnectionAddress& object) +{ + return + { + create_object_field(DISCOVERY_SERVER_GUID_PREFIX_TAG, OptionalKind::required, object.discovery_server_guid_prefix), + create_object_field(COLLECTION_ADDRESSES_TAG, OptionalKind::advisable, object.addresses), + }; +} + +} /* namespace yaml */ +} /* namespace ddspipe */ +} /* namespace eprosima */ diff --git a/ddspipe_yaml/src/cpp/reader/YamlReader_generic.cpp b/ddspipe_yaml/src/cpp/reader/YamlReader_generic.cpp new file mode 100644 index 000000000..e2d8422f8 --- /dev/null +++ b/ddspipe_yaml/src/cpp/reader/YamlReader_generic.cpp @@ -0,0 +1,88 @@ +// Copyright 2023 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +namespace eprosima { +namespace ddspipe { +namespace yaml { + +//////////////////////////////////////////////// +// IMPLEMENTATION OF TRIVIAL TYPES +//////////////////////////////////////////////// + +template <> +void read( + const Yaml& yml, + std::string& object) +{ + object = yml.as(); +} + +template <> +void read( + const Yaml& yml, + int& object) +{ + object = yml.as(); +} + +template <> +void read( + const Yaml& yml, + unsigned int& object) +{ + int x = yml.as(); + if (x < 0) + { + throw eprosima::utils::ConfigurationException( + utils::Formatter() << "Expected to read a positive integer."); + } + object = x; +} + +template <> +void read( + const Yaml& yml, + unsigned short& object) +{ + short x = yml.as(); + if (x < 0) + { + throw eprosima::utils::ConfigurationException( + utils::Formatter() << "Expected to read a positive integer."); + } + object = x; +} + +template <> +void read( + const Yaml& yml, + float& object) +{ + object = yml.as(); +} + +template <> +void read( + const Yaml& yml, + bool& object) +{ + object = yml.as(); +} + +} /* namespace yaml */ +} /* namespace ddspipe */ +} /* namespace eprosima */ diff --git a/ddspipe_yaml/src/cpp/reader/YamlReader_types.cpp b/ddspipe_yaml/src/cpp/reader/YamlReader_types.cpp new file mode 100644 index 000000000..72dbf314e --- /dev/null +++ b/ddspipe_yaml/src/cpp/reader/YamlReader_types.cpp @@ -0,0 +1,289 @@ +// Copyright 2023 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +namespace eprosima { +namespace ddspipe { +namespace yaml { + +//////////////////////////////////////////////// +// IMPLEMENTATION OF ENUMERATIONS +//////////////////////////////////////////////// + +template <> +void read( + const Yaml& yml, + participants::types::TransportProtocol& object) +{ + // TODO get a way of not duplicating this map in write and read + read_enumeration( + yml, + { + {ADDRESS_TRANSPORT_TCP_TAG, participants::types::TransportProtocol::tcp}, + {ADDRESS_TRANSPORT_UDP_TAG, participants::types::TransportProtocol::udp}, + }); +} + +template <> +void read( + const Yaml& yml, + participants::types::IpVersion& object) +{ + read_enumeration( + yml, + { + {ADDRESS_IP_VERSION_V4_TAG, participants::types::IpVersion::v4}, + {ADDRESS_IP_VERSION_V6_TAG, participants::types::IpVersion::v6}, + }); +} + +//////////////////////////////////////////////// +// IMPLEMENTATION OF TYPES BY DEFAULT +//////////////////////////////////////////////// + +template <> +void read( + const Yaml& yml, + core::types::DdsTopic& object) +{ + read_from_fields(yml, object); +} + +template <> +void read( + const Yaml& yml, + core::types::WildcardDdsFilterTopic& object) +{ + read_from_fields(yml, object); +} + +template <> +void read( + const Yaml& yml, + participants::types::DiscoveryServerConnectionAddress& object) +{ + read_from_fields(yml, object); +} + +//////////////////////////////////////////////// +// IMPLEMENTATION OF SPECIFIC TYPES +//////////////////////////////////////////////// + +template <> +void read( + const Yaml& yml, + core::types::TopicQoS& object) +{ + read_from_fields(yml, object); + + // Reliability optional + if (is_tag_present(yml, QOS_RELIABLE_TAG)) + { + if (read(yml, QOS_RELIABLE_TAG)) + { + object.reliability_qos = eprosima::ddspipe::core::types::ReliabilityKind::RELIABLE; + } + else + { + object.reliability_qos = eprosima::ddspipe::core::types::ReliabilityKind::BEST_EFFORT; + } + } + + // Durability optional + if (is_tag_present(yml, QOS_TRANSIENT_TAG)) + { + if (read(yml, QOS_TRANSIENT_TAG)) + { + object.durability_qos = eprosima::ddspipe::core::types::DurabilityKind::TRANSIENT_LOCAL; + } + else + { + object.durability_qos = eprosima::ddspipe::core::types::DurabilityKind::VOLATILE; + } + } + + // Ownership optional + if (is_tag_present(yml, QOS_OWNERSHIP_TAG)) + { + if (read(yml, QOS_OWNERSHIP_TAG)) + { + object.ownership_qos = eprosima::ddspipe::core::types::OwnershipQosPolicyKind::EXCLUSIVE_OWNERSHIP_QOS; + } + else + { + object.ownership_qos = eprosima::ddspipe::core::types::OwnershipQosPolicyKind::SHARED_OWNERSHIP_QOS; + } + } +} + +template <> +void read( + const Yaml& yml, + core::types::GuidPrefix& object) +{ + // If guid exists, use it. Non mandatory. + if (is_tag_present(yml, DISCOVERY_SERVER_GUID_TAG)) + { + std::string guid = read(yml, DISCOVERY_SERVER_GUID_TAG); + object = core::types::GuidPrefix(guid); + return; + } + + // ROS DS is optional. + bool ros_id; + bool ros_id_set = is_tag_present(yml, DISCOVERY_SERVER_ID_ROS_TAG); + if (ros_id_set) + { + ros_id = read(yml, DISCOVERY_SERVER_ID_ROS_TAG); + } + + // Id is mandatory if guid is not present + uint32_t id = read(yml, DISCOVERY_SERVER_ID_TAG); + + // Create GuidPrefix + if (ros_id_set) + { + object = core::types::GuidPrefix(ros_id, id); + } + else + { + object = core::types::GuidPrefix(id); + } +} + +template <> +void read( + const Yaml& yml, + participants::types::Address& object) +{ + // Optional get IP version + participants::types::IpVersion ip_version; + bool ip_version_set = is_tag_present(yml, ADDRESS_IP_VERSION_TAG); + if (ip_version_set) + { + // Get IP Version from enumeration + ip_version = read(yml, ADDRESS_IP_VERSION_TAG); + } + + // Optional get IP + participants::types::IpType ip; + bool ip_set = is_tag_present(yml, ADDRESS_IP_TAG); + if (ip_set) + { + ip = read(yml, ADDRESS_IP_TAG); + } + + // Optional get Domain tag for DNS + std::string domain_name; + bool domain_name_set = is_tag_present(yml, ADDRESS_DNS_TAG); + if (domain_name_set) + { + domain_name = read(yml, ADDRESS_DNS_TAG); + } + + // If IP and domain_name set, warning that domain_name will not be used + // If only domain_name set, get DNS response + // If neither set, get default + if (ip_set && domain_name_set) + { + logWarning(ddspipe_YAML, + "Tag <" << ADDRESS_DNS_TAG << "> will not be used as <" << ADDRESS_IP_TAG << "> is set."); + domain_name_set = false; + } + else if (!ip_set && !domain_name_set) + { + throw eprosima::utils::ConfigurationException(utils::Formatter() << + "Address requires to specify <" << ADDRESS_IP_TAG << "> or <" << ADDRESS_DNS_TAG << ">."); + } + + // Optional get port + participants::types::PortType port; + bool port_set = is_tag_present(yml, ADDRESS_PORT_TAG); + if (port_set) + { + port = read(yml, ADDRESS_PORT_TAG); + } + else + { + port = participants::types::Address::default_port(); + } + + // WARNING: This adds logic to the parse of the entity, + // This may not be the best place to do so. In the future move this logic to the Address class. + + // Optional get external port + // If it is not set, same as internal port is used + participants::types::PortType external_port; + bool external_port_set = is_tag_present(yml, ADDRESS_EXTERNAL_PORT_TAG); + if (external_port_set) + { + external_port = read(yml, ADDRESS_EXTERNAL_PORT_TAG); + } + else + { + external_port = port; + } + + // Optional get Transport protocol + participants::types::TransportProtocol tp; + bool tp_set = is_tag_present(yml, ADDRESS_TRANSPORT_TAG); + if (tp_set) + { + tp = read(yml, ADDRESS_TRANSPORT_TAG); + } + else + { + tp = participants::types::Address::default_transport_protocol(); + } + + // Construct Address object + if (domain_name_set) + { + if (ip_version_set) + { + object = participants::types::Address(port, external_port, ip_version, domain_name, tp); + } + else + { + object = participants::types::Address(port, external_port, domain_name, tp); + } + } + else + { + if (ip_version_set) + { + object = participants::types::Address(ip, port, external_port, ip_version, tp); + } + else + { + object = participants::types::Address(ip, port, external_port, tp); + } + } +} + +} /* namespace yaml */ +} /* namespace ddspipe */ +} /* namespace eprosima */ diff --git a/ddspipe_yaml/src/cpp/writer/YamlWriter_generic.cpp b/ddspipe_yaml/src/cpp/writer/YamlWriter_generic.cpp new file mode 100644 index 000000000..8071202ad --- /dev/null +++ b/ddspipe_yaml/src/cpp/writer/YamlWriter_generic.cpp @@ -0,0 +1,91 @@ +// Copyright 2023 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include +#include +#include + +namespace eprosima { +namespace ddspipe { +namespace yaml { + +//////////////////////////////////////////////// +// IMPLEMENTATION OF TRIVIAL TYPES +//////////////////////////////////////////////// + +template <> +void write( + Yaml& yml, + const std::string& value) +{ + yml = value; +} + +template <> +void write( + Yaml& yml, + const int& value) +{ + yml = value; +} + +template <> +void write( + Yaml& yml, + const unsigned int& value) +{ + int x = value; + if (x < 0) + { + throw eprosima::utils::ConfigurationException( + utils::Formatter() << "Expected to write a positive integer."); + } + yml = value; +} + +template <> +void write( + Yaml& yml, + const unsigned short& value) +{ + int x = value; + if (x < 0) + { + throw eprosima::utils::ConfigurationException( + utils::Formatter() << "Expected to write a positive short."); + } + yml = value; +} + +template <> +void write( + Yaml& yml, + const bool& value) +{ + yml = value; +} + +template <> +void write( + Yaml& yml, + const float& value) +{ + yml = value; +} + +} /* namespace yaml */ +} /* namespace ddspipe */ +} /* namespace eprosima */ diff --git a/ddspipe_yaml/src/cpp/writer/YamlWriter_types.cpp b/ddspipe_yaml/src/cpp/writer/YamlWriter_types.cpp new file mode 100644 index 000000000..33565529e --- /dev/null +++ b/ddspipe_yaml/src/cpp/writer/YamlWriter_types.cpp @@ -0,0 +1,134 @@ +// Copyright 2023 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +namespace eprosima { +namespace ddspipe { +namespace yaml { + +//////////////////////////////////////////////// +// IMPLEMENTATION OF ENUMERATIONS +//////////////////////////////////////////////// + +template <> +void write( + Yaml& yml, + const participants::types::TransportProtocol& object) +{ + // TODO get a way of not duplicating this map in write and write + write_enumeration( + yml, + object, + { + {ADDRESS_TRANSPORT_TCP_TAG, participants::types::TransportProtocol::tcp}, + {ADDRESS_TRANSPORT_UDP_TAG, participants::types::TransportProtocol::udp}, + }); +} + +template <> +void write( + Yaml& yml, + const participants::types::IpVersion& object) +{ + write_enumeration( + yml, + object, + { + {ADDRESS_IP_VERSION_V4_TAG, participants::types::IpVersion::v4}, + {ADDRESS_IP_VERSION_V6_TAG, participants::types::IpVersion::v6}, + }); +} + +//////////////////////////////////////////////// +// IMPLEMENTATION OF TYPES BY DEFAULT +//////////////////////////////////////////////// + +template <> +void write( + Yaml& yml, + const core::types::DdsTopic& object) +{ + write_from_fields(yml, object); +} + +template <> +void write( + Yaml& yml, + const core::types::WildcardDdsFilterTopic& object) +{ + write_from_fields(yml, object); +} + +template <> +void write( + Yaml& yml, + const participants::types::DiscoveryServerConnectionAddress& object) +{ + write_from_fields(yml, object); +} + +//////////////////////////////////////////////// +// IMPLEMENTATION OF SPECIFIC TYPES +//////////////////////////////////////////////// + +template <> +void write( + Yaml& yml, + const core::types::TopicQoS& object) +{ + write_from_fields(yml, object); + + write(yml, QOS_RELIABLE_TAG, object.is_reliable()); + write(yml, QOS_TRANSIENT_TAG, object.is_transient_local()); + write(yml, QOS_OWNERSHIP_TAG, object.has_ownership()); +} + +template <> +void write( + Yaml& yml, + const core::types::GuidPrefix& object) +{ + write(yml, DISCOVERY_SERVER_GUID_TAG, utils::generic_to_string(object)); +} + +template <> +void write( + Yaml& yml, + const participants::types::Address& object) +{ + write(yml, ADDRESS_IP_TAG, object.ip()); + write(yml, ADDRESS_PORT_TAG, object.port()); + write(yml, ADDRESS_IP_VERSION_TAG, object.ip_version()); + write(yml, ADDRESS_TRANSPORT_TAG, object.transport_protocol()); + + if (object.port() != object.external_port()) + { + write(yml, ADDRESS_PORT_TAG, object.external_port()); + } +} + +} /* namespace yaml */ +} /* namespace ddspipe */ +} /* namespace eprosima */ diff --git a/ddspipe_yaml/test/unittest/CMakeLists.txt b/ddspipe_yaml/test/unittest/CMakeLists.txt index 5204db13f..4551fd7c5 100644 --- a/ddspipe_yaml/test/unittest/CMakeLists.txt +++ b/ddspipe_yaml/test/unittest/CMakeLists.txt @@ -17,5 +17,5 @@ ############## add_subdirectory(entities) -add_subdirectory(yaml_reader) -add_subdirectory(yaml_writer) +# add_subdirectory(yaml_reader) +# add_subdirectory(yaml_writer) diff --git a/ddspipe_yaml/test/unittest/entities/CMakeLists.txt b/ddspipe_yaml/test/unittest/entities/CMakeLists.txt index 7920290b5..38af61f78 100644 --- a/ddspipe_yaml/test/unittest/entities/CMakeLists.txt +++ b/ddspipe_yaml/test/unittest/entities/CMakeLists.txt @@ -16,6 +16,7 @@ # Yaml GetEntities Test # ######################### -add_subdirectory(address) -add_subdirectory(guid) -add_subdirectory(topic) +# add_subdirectory(address) +# add_subdirectory(guid) +# add_subdirectory(topic) +add_subdirectory(generic) diff --git a/ddspipe_yaml/test/unittest/entities/address/CMakeLists.txt b/ddspipe_yaml/test/unittest/entities/address/CMakeLists.txt index 143b72bb1..a15e367ea 100644 --- a/ddspipe_yaml/test/unittest/entities/address/CMakeLists.txt +++ b/ddspipe_yaml/test/unittest/entities/address/CMakeLists.txt @@ -19,9 +19,9 @@ set(TEST_NAME YamlGetEntityAddressTest) set(TEST_SOURCES - ${PROJECT_SOURCE_DIR}/src/cpp/YamlReader_generic.cpp - ${PROJECT_SOURCE_DIR}/src/cpp/YamlReader_participants.cpp - ${PROJECT_SOURCE_DIR}/src/cpp/YamlReader_types.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/reader/YamlReader_generic.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/reader/YamlReader_participants.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/reader/YamlReader_types.cpp YamlGetEntityAddressTest.cpp ) @@ -58,9 +58,9 @@ add_unittest_executable( set(TEST_NAME YamlGetEntityDiscoveryServerAddressTest) set(TEST_SOURCES - ${PROJECT_SOURCE_DIR}/src/cpp/YamlReader_generic.cpp - ${PROJECT_SOURCE_DIR}/src/cpp/YamlReader_participants.cpp - ${PROJECT_SOURCE_DIR}/src/cpp/YamlReader_types.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/reader/YamlReader_generic.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/reader/YamlReader_participants.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/reader/YamlReader_types.cpp YamlGetEntityDiscoveryServerAddressTest.cpp ) diff --git a/ddspipe_yaml/test/unittest/entities/generic/CMakeLists.txt b/ddspipe_yaml/test/unittest/entities/generic/CMakeLists.txt new file mode 100644 index 000000000..aa7bd574d --- /dev/null +++ b/ddspipe_yaml/test/unittest/entities/generic/CMakeLists.txt @@ -0,0 +1,29 @@ +# Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +############################### +# Yaml GetEntities Topic Test # +############################### + +set(TEST_NAME ParametrizedGenericReaderWriterTest) + +set(TEST_SOURCES + GenericReaderWriterTest.cpp + ) + +add_blackbox_executable( + "${TEST_NAME}" + "${TEST_SOURCES}" + "" + "") diff --git a/ddspipe_yaml/test/unittest/entities/generic/GenericReaderWriterTest.cpp b/ddspipe_yaml/test/unittest/entities/generic/GenericReaderWriterTest.cpp new file mode 100644 index 000000000..f212d3a1d --- /dev/null +++ b/ddspipe_yaml/test/unittest/entities/generic/GenericReaderWriterTest.cpp @@ -0,0 +1,102 @@ +// Copyright 2021 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + +using namespace eprosima; + +namespace test { + +constexpr const unsigned int N_TEST_CASES = 1000; + +template +T arbitrary( + unsigned int seed) +{ + return ddspipe::core::testing::arbitrary(seed); +} + +template <> +ddspipe::core::types::TopicQoS arbitrary( + unsigned int seed) +{ + return ddspipe::core::testing::arbitrary(seed, false); +} + +} // namespace test + +// Empty class to parametrized tests +template +struct GenericReaderWriterTest : public ::testing::Test +{}; +// Needed gtest macro +TYPED_TEST_SUITE_P(GenericReaderWriterTest); + +TYPED_TEST_P(GenericReaderWriterTest, generic_from_and_to) +{ + for (unsigned int i = 0 ; i < test::N_TEST_CASES ; ++i) + { + TypeParam write_object = test::arbitrary(i); + + ddspipe::yaml::Yaml yml; + ddspipe::yaml::write(yml, write_object); + + TypeParam read_object; + ddspipe::yaml::read(yml, read_object); + + ASSERT_EQ(write_object, read_object) << "Failure in value " << i; + } +} + +// Register test class and test cases +REGISTER_TYPED_TEST_SUITE_P( + GenericReaderWriterTest, + generic_from_and_to +); + +// Set types used in parametrization +typedef ::testing::Types< + ddspipe::core::types::DdsTopic, + ddspipe::core::types::TopicQoS, + ddspipe::core::types::WildcardDdsFilterTopic, + ddspipe::core::types::GuidPrefix, + ddspipe::participants::types::Address, + ddspipe::participants::types::DiscoveryServerConnectionAddress + > CaseTypes; + +// Generate each test case for each type case +INSTANTIATE_TYPED_TEST_SUITE_P( + ParametrizedGenericReaderWriterTest, + GenericReaderWriterTest, + CaseTypes); + +int main( + int argc, + char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/ddspipe_yaml/test/unittest/entities/guid/CMakeLists.txt b/ddspipe_yaml/test/unittest/entities/guid/CMakeLists.txt index e67669ec3..42c3d5d16 100644 --- a/ddspipe_yaml/test/unittest/entities/guid/CMakeLists.txt +++ b/ddspipe_yaml/test/unittest/entities/guid/CMakeLists.txt @@ -20,9 +20,9 @@ set(TEST_NAME YamlGetEntityGuidPrefixTest) set(TEST_SOURCES YamlGetEntityGuidPrefixTest.cpp - ${PROJECT_SOURCE_DIR}/src/cpp/YamlReader_generic.cpp - ${PROJECT_SOURCE_DIR}/src/cpp/YamlReader_participants.cpp - ${PROJECT_SOURCE_DIR}/src/cpp/YamlReader_types.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/reader/YamlReader_generic.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/reader/YamlReader_participants.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/reader/YamlReader_types.cpp ${PROJECT_SOURCE_DIR}/src/cpp/YamlManager.cpp ) diff --git a/ddspipe_yaml/test/unittest/entities/topic/CMakeLists.txt b/ddspipe_yaml/test/unittest/entities/topic/CMakeLists.txt index cf536cc3d..a74d08dd3 100644 --- a/ddspipe_yaml/test/unittest/entities/topic/CMakeLists.txt +++ b/ddspipe_yaml/test/unittest/entities/topic/CMakeLists.txt @@ -20,9 +20,9 @@ set(TEST_NAME YamlGetEntityTopicTest) set(TEST_SOURCES YamlGetEntityTopicTest.cpp - ${PROJECT_SOURCE_DIR}/src/cpp/YamlReader_generic.cpp - ${PROJECT_SOURCE_DIR}/src/cpp/YamlReader_participants.cpp - ${PROJECT_SOURCE_DIR}/src/cpp/YamlReader_types.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/reader/YamlReader_generic.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/reader/YamlReader_participants.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/reader/YamlReader_types.cpp ${PROJECT_SOURCE_DIR}/src/cpp/YamlManager.cpp ) diff --git a/ddspipe_yaml/test/unittest/entities/topic/YamlGetEntityTopicTest.cpp b/ddspipe_yaml/test/unittest/entities/topic/YamlGetEntityTopicTest.cpp index 164db031b..a1d3466be 100644 --- a/ddspipe_yaml/test/unittest/entities/topic/YamlGetEntityTopicTest.cpp +++ b/ddspipe_yaml/test/unittest/entities/topic/YamlGetEntityTopicTest.cpp @@ -141,6 +141,7 @@ TEST(YamlGetEntityTopicTest, get_real_topic) * - Empty * - Topic without name * - Topic without type + * - Topic with extra field */ TEST(YamlGetEntityTopicTest, get_real_topic_negative) { @@ -177,6 +178,20 @@ TEST(YamlGetEntityTopicTest, get_real_topic_negative) ASSERT_THROW(YamlReader::get(yml, "topic", LATEST), eprosima::utils::ConfigurationException); } + + // Topic without type + { + Yaml yml_topic; + add_field_to_yaml(yml_topic, YamlField(test::TOPIC_TYPE), TOPIC_TYPE_NAME_TAG); + add_field_to_yaml(yml_topic, YamlField(test::TOPIC_NAME), TOPIC_NAME_TAG); + add_field_to_yaml(yml_topic, YamlField("some_value"), "some_tag"); + + Yaml yml; + yml["topic"] = yml_topic; + + ASSERT_THROW(YamlReader::get(yml, "topic", + LATEST), eprosima::utils::ConfigurationException); + } } /** diff --git a/ddspipe_yaml/test/unittest/yaml_reader/CMakeLists.txt b/ddspipe_yaml/test/unittest/yaml_reader/CMakeLists.txt index b6bc6909d..7980f50a1 100644 --- a/ddspipe_yaml/test/unittest/yaml_reader/CMakeLists.txt +++ b/ddspipe_yaml/test/unittest/yaml_reader/CMakeLists.txt @@ -19,9 +19,9 @@ set(TEST_NAME YamlReaderScalarTest) set(TEST_SOURCES - ${PROJECT_SOURCE_DIR}/src/cpp/YamlReader_generic.cpp - ${PROJECT_SOURCE_DIR}/src/cpp/YamlReader_participants.cpp - ${PROJECT_SOURCE_DIR}/src/cpp/YamlReader_types.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/reader/YamlReader_generic.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/reader/YamlReader_participants.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/reader/YamlReader_types.cpp YamlReaderScalarTest.cpp ) diff --git a/ddspipe_yaml/test/unittest/yaml_writer/CMakeLists.txt b/ddspipe_yaml/test/unittest/yaml_writer/CMakeLists.txt index 700c43966..096a25c49 100644 --- a/ddspipe_yaml/test/unittest/yaml_writer/CMakeLists.txt +++ b/ddspipe_yaml/test/unittest/yaml_writer/CMakeLists.txt @@ -19,8 +19,8 @@ set(TEST_NAME YamlWriterTest) set(TEST_SOURCES - ${PROJECT_SOURCE_DIR}/src/cpp/YamlReader_generic.cpp - ${PROJECT_SOURCE_DIR}/src/cpp/YamlWriter.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/reader/YamlReader_generic.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/writer/YamlWriter.cpp YamlWriterTest.cpp ) @@ -60,8 +60,8 @@ add_unittest_executable( set(TEST_NAME YamlWriter_collections_test) set(TEST_SOURCES - ${PROJECT_SOURCE_DIR}/src/cpp/YamlReader_generic.cpp - ${PROJECT_SOURCE_DIR}/src/cpp/YamlWriter.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/reader/YamlReader_generic.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/writer/YamlWriter.cpp YamlWriter_collections_test.cpp )