From e72cfa7b89dbe44d03ca53f179938e6562675b5c Mon Sep 17 00:00:00 2001 From: Irene Bandera Date: Thu, 26 Oct 2023 12:26:03 +0200 Subject: [PATCH 1/7] Add ROS 2 Mangling methods Signed-off-by: Irene Bandera --- cpp_utils/include/cpp_utils/ros2_mangling.hpp | 157 ++++++ cpp_utils/src/cpp/ros2_mangling.cpp | 350 ++++++++++++ cpp_utils/test/unittest/CMakeLists.txt | 1 + .../unittest/ros2_mangling/CMakeLists.txt | 64 +++ .../ros2_mangling/ROS2ManglingTest.cpp | 504 ++++++++++++++++++ 5 files changed, 1076 insertions(+) create mode 100644 cpp_utils/include/cpp_utils/ros2_mangling.hpp create mode 100644 cpp_utils/src/cpp/ros2_mangling.cpp create mode 100644 cpp_utils/test/unittest/ros2_mangling/CMakeLists.txt create mode 100644 cpp_utils/test/unittest/ros2_mangling/ROS2ManglingTest.cpp diff --git a/cpp_utils/include/cpp_utils/ros2_mangling.hpp b/cpp_utils/include/cpp_utils/ros2_mangling.hpp new file mode 100644 index 00000000..f6ce30b2 --- /dev/null +++ b/cpp_utils/include/cpp_utils/ros2_mangling.hpp @@ -0,0 +1,157 @@ +// 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 + +namespace eprosima { +namespace utils { + +/** + * @param[in] name string that will be stripped from prefix + * @param[in] prefix prefix to be stripped + * @return name stripped of prefix, or + * @return "" if name doesn't start with prefix + */ +std::string remove_prefix( + const std::string& name, + const std::string& prefix); + +/** + * @param[in] name string to be prefixed with "prefix" + * @param[in] prefix prefix to be added + * @return Returns the name with the prefix added "prefixname" + */ +std::string add_prefix( + const std::string& name, + const std::string& prefix); + +/** + * @todo + */ +std::string add_suffix( + const std::string& name, + const std::string& suffix); + +/** + * @return Returns the ROS specific prefix if present, otherwise "". + */ +std::string get_ros_prefix_if_exists( + const std::string& topic_name); + +/** + * @brief Remove the ROS specific prefix from the topic name if it exists. + * + * @return Returns the topic name stripped of a ROS specific prefix if present. + */ +std::string remove_ros_prefix_if_exists( + const std::string& topic_name); + +/** + * @todo + */ +std::string add_ros_topic_prefix( + const std::string& topic_name); + +/** + * @todo + */ +std::string add_ros_service_requester_prefix( + const std::string& topic_name); + +/** + * @todo + */ +std::string add_ros_service_response_prefix( + const std::string& topic_name); + +/** + * @return Returns \c ros_prefixes_. + */ +const std::vector& get_all_ros_prefixes(); + +/** + * @return Returns the demangle ROS topic or the original if not a ROS topic. + */ +std::string demangle_if_ros_topic( + const std::string& topic_name); + +/** + * @todo + */ +std::string mangle_if_ros_topic( + const std::string& topic_name); + +/** + * @return Returns the demangled ROS type or the original if not a ROS type. + */ +std::string demangle_if_ros_type( + const std::string& dds_type_string); + +/** + * @todo + */ +std::string mangle_if_ros_type( + const std::string& ros2_type_string); + +/** + * @return Returns the topic name for a given topic if it is part of a ROS topic, otherwise "". + */ +std::string demangle_ros_topic_prefix_from_topic( + const std::string& topic_name); + +/** + * @return Returns the service name for a given topic if it is part of a ROS service, otherwise "". + */ +std::string demangle_ros_service_prefix_from_topic( + const std::string& topic_name); +/** + * @return Returns the service name for a given topic if it is part of a ROS service request, otherwise "". + */ +std::string demangle_ros_service_request_prefix_from_topic( + const std::string& topic_name); + +/** + * @todo + */ +std::string mangle_ros_service_request_prefix_in_topic( + const std::string& topic_name); + +/** + * @return Returns the service name for a given topic if it is part of a service response, otherwise "". + */ +std::string demangle_ros_service_reply_prefix_from_topic( + const std::string& topic_name); + +/** + * @todo + */ +std::string mangle_ros_service_reply_prefix_in_topic( + const std::string& topic_name); + +/** + * @return Returns the demangled service type if it is an ROS srv type, otherwise "". + */ +std::string demangle_service_type_only( + const std::string& dds_type_name); + +/** + * @todo + */ +std::string mangle_service_type_only( + const std::string& ros2_type_name); + +} /* namespace utils */ +} /* namespace eprosima */ diff --git a/cpp_utils/src/cpp/ros2_mangling.cpp b/cpp_utils/src/cpp/ros2_mangling.cpp new file mode 100644 index 00000000..e3e52130 --- /dev/null +++ b/cpp_utils/src/cpp/ros2_mangling.cpp @@ -0,0 +1,350 @@ +// 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 + +namespace eprosima { +namespace utils { + +const char* const ros_topic_prefix = "rt"; +const char* const ros_service_requester_prefix = "rq"; +const char* const ros_service_response_prefix = "rr"; + +const std::vector ros_prefixes_ = +{ros_topic_prefix, ros_service_requester_prefix, ros_service_response_prefix}; + +std::string remove_prefix( + const std::string& name, + const std::string& prefix) +{ + if (name.rfind(prefix + "/", 0) == 0) + { + return name.substr(prefix.length()); + } + return ""; +} + +std::string add_prefix( + const std::string& name, + const std::string& prefix) +{ + return prefix + name; +} + +std::string add_suffix( + const std::string& name, + const std::string& suffix) +{ + return name + suffix; +} + +std::string get_ros_prefix_if_exists( + const std::string& topic_name) +{ + for (const auto& prefix : ros_prefixes_) + { + if (topic_name.rfind(prefix + "/", 0) == 0) + { + return prefix; + } + } + return ""; +} + +std::string remove_ros_prefix_if_exists( + const std::string& topic_name) +{ + for (const auto& prefix : ros_prefixes_) + { + if (topic_name.rfind(prefix + "/", 0) == 0) + { + return topic_name.substr(prefix.length()); + } + } + return topic_name; +} + +std::string add_ros_topic_prefix( + const std::string& topic_name) +{ + return add_prefix(topic_name, ros_topic_prefix); +} + +std::string add_ros_service_requester_prefix( + const std::string& topic_name) +{ + return add_prefix(topic_name, ros_service_requester_prefix); + +} + +std::string add_ros_service_response_prefix( + const std::string& topic_name) +{ + return add_prefix(topic_name, ros_service_response_prefix); +} + +const std::vector& get_all_ros_prefixes() +{ + return ros_prefixes_; +} + +std::string demangle_if_ros_topic( + const std::string& topic_name) +{ + return remove_ros_prefix_if_exists(topic_name); +} + +std::string mangle_if_ros_topic( + const std::string& topic_name) +{ + if (topic_name.rfind("/", 0) == 0) + { + return add_ros_topic_prefix(topic_name); + } + return topic_name; +} + +std::string demangle_if_ros_type( + const std::string& dds_type_string) +{ + if (dds_type_string[dds_type_string.size() - 1] != '_') + { + // not a ROS type + return dds_type_string; + } + + std::string substring = "dds_::"; + size_t substring_position = dds_type_string.find(substring); + if (substring_position == std::string::npos) + { + // not a ROS type + return dds_type_string; + } + + std::string type_namespace = dds_type_string.substr(0, substring_position); + + replace_all(type_namespace, "::", "/"); + + size_t start = substring_position + substring.size(); + std::string type_name = dds_type_string.substr(start, dds_type_string.length() - 1 - start); + + return type_namespace + type_name; +} + +std::string mangle_if_ros_type( + const std::string& ros2_type_string) +{ + std::string dds_type_string = ros2_type_string; + + size_t substring_position = dds_type_string.find("_msgs/msg/"); + if (substring_position == std::string::npos) + { + return dds_type_string; + } + + std::string substring = "dds_::"; + + std::string type_namespace = dds_type_string.substr(0, substring_position + 10); + std::string type_name = dds_type_string.substr(substring_position + 10, dds_type_string.length() - 1); + + if (type_name.length() == 0) + { + return dds_type_string; + } + + replace_all(type_namespace, "/", "::"); + + return type_namespace + "dds_::" + type_name + "_"; +} + +std::string demangle_ros_topic_prefix_from_topic( + const std::string& topic_name) +{ + return remove_prefix(topic_name, ros_topic_prefix); +} + +std::string demangle_ros_service_prefix_from_topic( + const std::string& prefix, + const std::string& topic_name, + std::string suffix) +{ + std::string service_name = remove_prefix(topic_name, prefix); + if ("" == service_name) + { + return ""; + } + + size_t suffix_position = service_name.rfind(suffix); + if (suffix_position != std::string::npos) + { + if (service_name.length() - suffix_position - suffix.length() != 0) + { + logWarning(DDSPIPE_DEMANGLE, + "service topic has service prefix and a suffix, but not at the end" + ", report this: " << topic_name.c_str()); + return ""; + } + } + else + { + logWarning(DDSPIPE_DEMANGLE, + "service topic has prefix but no suffix" + ", report this: " << topic_name.c_str()); + return ""; + } + return service_name.substr(0, suffix_position); +} + +std::string mangle_ros_service_in_topic( + const std::string& prefix, + const std::string& topic_name, + const std::string suffix) +{ + size_t suffix_position = topic_name.rfind("/"); + if (suffix_position != 0) + { + return ""; + } + + std::string service_name = add_prefix(topic_name, prefix); + service_name = add_suffix(service_name, suffix); + + return service_name; +} + +std::string demangle_ros_service_prefix_from_topic( + const std::string& topic_name) +{ + const std::string demangled_topic = demangle_ros_service_reply_prefix_from_topic(topic_name); + if ("" != demangled_topic) + { + return demangled_topic; + } + return demangle_ros_service_request_prefix_from_topic(topic_name); +} + +std::string demangle_ros_service_request_prefix_from_topic( + const std::string& topic_name) +{ + return demangle_ros_service_prefix_from_topic(ros_service_requester_prefix, topic_name, "Request"); +} + +std::string mangle_ros_service_request_prefix_in_topic( + const std::string& topic_name) +{ + return mangle_ros_service_in_topic(ros_service_requester_prefix, topic_name, "Request"); +} + +std::string demangle_ros_service_reply_prefix_from_topic( + const std::string& topic_name) +{ + return demangle_ros_service_prefix_from_topic(ros_service_response_prefix, topic_name, "Reply"); +} + +std::string mangle_ros_service_reply_prefix_in_topic( + const std::string& topic_name) +{ + return mangle_ros_service_in_topic(ros_service_response_prefix, topic_name, "Reply"); +} + +std::string demangle_service_type_only( + const std::string& dds_type_name) +{ + std::string ns_substring = "dds_::"; + size_t ns_substring_position = dds_type_name.find(ns_substring); + if (std::string::npos == ns_substring_position) + { + // not a ROS service type + return ""; + } + auto suffixes = { + std::string("_Response_"), + std::string("_Request_"), + }; + std::string found_suffix = ""; + size_t suffix_position = 0; + for (auto suffix : suffixes) + { + suffix_position = dds_type_name.rfind(suffix); + if (suffix_position != std::string::npos) + { + if (dds_type_name.length() - suffix_position - suffix.length() != 0) + { + logWarning(DDSPIPE_DEMANGLE, + "service type contains 'dds_::' and a suffix, but not at the end" + ", report this: " << dds_type_name.c_str()); + continue; + } + found_suffix = suffix; + break; + } + } + if (std::string::npos == suffix_position) + { + logWarning(DDSPIPE_DEMANGLE, + "service type contains 'dds_::' but does not have a suffix" + ", report this: " << dds_type_name.c_str()); + return ""; + } + // everything checks out, reformat it from '[type_namespace::]dds_::' + // to '[type_namespace/]' + std::string type_namespace = dds_type_name.substr(0, ns_substring_position); + replace_all(type_namespace, "::", "/"); + size_t start = ns_substring_position + ns_substring.length(); + std::string type_name = dds_type_name.substr(start, suffix_position - start); + return type_namespace + type_name; +} + +std::string mangle_service_type_only( + const std::string& ros2_type_name) +{ + size_t ns_substring_srv_position = ros2_type_name.find("/srv/"); + if (std::string::npos == ns_substring_srv_position) + { + return ""; + } + + std::string dds_type_name = ros2_type_name.substr(0, ns_substring_srv_position + 5) + "dds_::"; + dds_type_name = dds_type_name + ros2_type_name.substr(ns_substring_srv_position + 5, ros2_type_name.length() - 1); + + size_t ns_substring_rq_position = ros2_type_name.find("rq/"); + size_t ns_substring_rr_position = ros2_type_name.find("rr/"); + + if (std::string::npos != ns_substring_rq_position) + { + dds_type_name = dds_type_name + "_Request_"; + } + else if (std::string::npos != ns_substring_rr_position) + { + dds_type_name = dds_type_name + "_Response_"; + } + else + { + return ""; + } + + replace_all(dds_type_name, "/", "::"); + + return dds_type_name; +} + +} /* namespace utils */ +} /* namespace eprosima */ diff --git a/cpp_utils/test/unittest/CMakeLists.txt b/cpp_utils/test/unittest/CMakeLists.txt index e484e0ab..16588195 100644 --- a/cpp_utils/test/unittest/CMakeLists.txt +++ b/cpp_utils/test/unittest/CMakeLists.txt @@ -24,6 +24,7 @@ add_subdirectory(math) add_subdirectory(math/random) add_subdirectory(memory) add_subdirectory(return_code) +add_subdirectory(ros2_mangling) add_subdirectory(testing) add_subdirectory(thread_pool) add_subdirectory(time) diff --git a/cpp_utils/test/unittest/ros2_mangling/CMakeLists.txt b/cpp_utils/test/unittest/ros2_mangling/CMakeLists.txt new file mode 100644 index 00000000..9ec2b22b --- /dev/null +++ b/cpp_utils/test/unittest/ros2_mangling/CMakeLists.txt @@ -0,0 +1,64 @@ +# 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. + +################# +# Demangle Test # +################# + +set(TEST_NAME ROS2ManglingTest) + +set(TEST_SOURCES + ROS2ManglingTest.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/exception/Exception.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/Formatter.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/math/math_extension.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/utils.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/ros2_mangling.cpp + ) + +set(TEST_LIST + remove_prefix + add_prefix + add_suffix + get_ros_prefix_if_exists + remove_ros_prefix_if_exists + add_ros_topic_prefix + add_ros_service_requester_prefix + add_ros_service_response_prefix + get_all_ros_prefixes + demangle_if_ros_topic + mangle_if_ros_topic + demangle_if_ros_type + mangle_if_ros_type + demangle_ros_topic_prefix_from_topic + demangle_ros_service_prefix_from_topic + demangle_ros_service_request_prefix_from_topic + mangle_ros_service_request_prefix_in_topic + demangle_ros_service_reply_prefix_from_topic + mangle_ros_service_reply_prefix_in_topic + demangle_service_type_only + mangle_service_type_only + ) + +set(TEST_EXTRA_LIBRARIES + fastcdr + fastrtps + ) + +add_unittest_executable( + "${TEST_NAME}" + "${TEST_SOURCES}" + "${TEST_LIST}" + "${TEST_EXTRA_LIBRARIES}" + ) diff --git a/cpp_utils/test/unittest/ros2_mangling/ROS2ManglingTest.cpp b/cpp_utils/test/unittest/ros2_mangling/ROS2ManglingTest.cpp new file mode 100644 index 00000000..83764608 --- /dev/null +++ b/cpp_utils/test/unittest/ros2_mangling/ROS2ManglingTest.cpp @@ -0,0 +1,504 @@ +// 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 + +using namespace eprosima::utils; + +/** + * Test remove_prefix() method + * + * CASES: + * - Name: "hello" Prefix: "world" Return: "" + * - Name: "hello/rt" Prefix: "rt" Return: "" + * - Name: "rt/hello" Prefix: "rt/" Return: "" + * - Name: "rt/hello" Prefix: "rt" Return: "/hello" + */ +TEST(ROS2ManglingTest, remove_prefix) +{ + EXPECT_EQ("", remove_prefix("hello", "world")); + EXPECT_EQ("", remove_prefix("hello/rt", "rt")); + EXPECT_EQ("", remove_prefix("rt/hello", "rt/")); + EXPECT_EQ("/hello", remove_prefix("rt/hello", "rt")); +} + +/** + * Test add_prefix() method + * + * CASES: + * - Name: "hello" Prefix: "world" Return: "worldhello" + * - Name: "hello" Prefix: "rt" Return: "rthello" + * - Name: "/hello" Prefix: "rt/" Return: "rt//hello" + * - Name: "/hello" Prefix: "rt" Return: "rt/hello" + */ +TEST(ROS2ManglingTest, add_prefix) +{ + EXPECT_EQ("worldhello", add_prefix("hello", "world")); + EXPECT_EQ("rthello", add_prefix("hello", "rt")); + EXPECT_EQ("rt//hello", add_prefix("/hello", "rt/")); + EXPECT_EQ("rt/hello", add_prefix("/hello", "rt")); +} + +/** + * Test add_suffix() method + * + * CASES: + * - Name: "hello" Suffix: "world" Return: "helloworld" + * - Name: "hello" Suffix: "rt" Return: "hellort" + * - Name: "/hello" Suffix: "rt/" Return: "/hellort/" + * - Name: "/hello" Suffix: "rt" Return: "/hellort" + * - Name: "rt/" Suffix: "hello" Return: "rt/hello" + */ +TEST(ROS2ManglingTest, add_suffix) +{ + EXPECT_EQ("helloworld", add_suffix("hello", "world")); + EXPECT_EQ("hellort", add_suffix("hello", "rt")); + EXPECT_EQ("/hellort/", add_suffix("/hello", "rt/")); + EXPECT_EQ("/hellort", add_suffix("/hello", "rt")); + EXPECT_EQ("rt/hello", add_suffix("rt/", "hello")); +} + +/** + * Test get_ros_prefix_if_exists() method + * + * CASES: + * - ROS 2 Topic Name: "hello" Return: "" + * - ROS 2 Topic Name: "hello/rt" Return: "" + * - ROS 2 Topic Name: "rt/hello" Return: "rt" + * - ROS 2 Topic Name: "/rt/hello" Return: "" + * - ROS 2 Topic Name: "hello/rq" Return: "" + * - ROS 2 Topic Name: "rq/hello" Return: "rq" + * - ROS 2 Topic Name: "/rq/hello" Return: "" + * - ROS 2 Topic Name: "hello/rr" Return: "" + * - ROS 2 Topic Name: "rr/hello" Return: "rr" + * - ROS 2 Topic Name: "/rr/hello" Return: "" + */ +TEST(ROS2ManglingTest, get_ros_prefix_if_exists) +{ + EXPECT_EQ("", get_ros_prefix_if_exists("hello")); + + // ros_topic_prefix + EXPECT_EQ("", get_ros_prefix_if_exists("hello/rt")); + EXPECT_EQ("rt", get_ros_prefix_if_exists("rt/hello")); + EXPECT_EQ("", get_ros_prefix_if_exists("/rt/hello")); + + // ros_service_requester_prefix + EXPECT_EQ("", get_ros_prefix_if_exists("hello/rq")); + EXPECT_EQ("rq", get_ros_prefix_if_exists("rq/hello")); + EXPECT_EQ("", get_ros_prefix_if_exists("/rq/hello")); + + // ros_service_requester_prefix + EXPECT_EQ("", get_ros_prefix_if_exists("hello/rr")); + EXPECT_EQ("rr", get_ros_prefix_if_exists("rr/hello")); + EXPECT_EQ("", get_ros_prefix_if_exists("/rr/hello")); +} + +/** + * Test remove_ros_prefix_if_exists() method + * + * CASES: + * - ROS 2 Topic Name: "hello" Return: "" + * - ROS 2 Topic Name: "hello/rt" Return: "hello/rt" + * - ROS 2 Topic Name: "rt/hello" Return: "/hello" + * - ROS 2 Topic Name: "/rt/hello" Return: "/rt/hello" + * - ROS 2 Topic Name: "hello/rq" Return: "hello/rq" + * - ROS 2 Topic Name: "rq/hello" Return: "/hello" + * - ROS 2 Topic Name: "/rq/hello" Return: "/rq/hello" + * - ROS 2 Topic Name: "hello/rr" Return: "hello/rr" + * - ROS 2 Topic Name: "rr/hello" Return: "/hello" + * - ROS 2 Topic Name: "/rr/hello" Return: "/rr/hello" + */ +TEST(ROS2ManglingTest, remove_ros_prefix_if_exists) +{ + EXPECT_EQ("hello", remove_ros_prefix_if_exists("hello")); + + // ros_topic_prefix + EXPECT_EQ("hello/rt", remove_ros_prefix_if_exists("hello/rt")); + EXPECT_EQ("/hello", remove_ros_prefix_if_exists("rt/hello")); + EXPECT_EQ("/rt/hello", remove_ros_prefix_if_exists("/rt/hello")); + + // ros_service_requester_prefix + EXPECT_EQ("hello/rq", remove_ros_prefix_if_exists("hello/rq")); + EXPECT_EQ("/hello", remove_ros_prefix_if_exists("rq/hello")); + EXPECT_EQ("/rq/hello", remove_ros_prefix_if_exists("/rq/hello")); + + // ros_service_requester_prefix + EXPECT_EQ("hello/rr", remove_ros_prefix_if_exists("hello/rr")); + EXPECT_EQ("/hello", remove_ros_prefix_if_exists("rr/hello")); + EXPECT_EQ("/rr/hello", remove_ros_prefix_if_exists("/rr/hello")); +} + +/** + * Test add_ros_topic_prefix() method + * + * CASES: + * - ROS 2 Topic Name: "hello" Return: "rthello" + * - ROS 2 Topic Name: "hello/rt" Return: "rthello/rt" + * - ROS 2 Topic Name: "/hello" Return: "rt/hello" + * - ROS 2 Topic Name: "rt/hello" Return: "rtrt/hello" + */ +TEST(ROS2ManglingTest, add_ros_topic_prefix) +{ + EXPECT_EQ("rthello", add_ros_topic_prefix("hello")); + EXPECT_EQ("rthello/rt", add_ros_topic_prefix("hello/rt")); + EXPECT_EQ("rt/hello", add_ros_topic_prefix("/hello")); + EXPECT_EQ("rtrt/hello", add_ros_topic_prefix("rt/hello")); +} + +/** + * Test add_ros_service_requester_prefix() method + * + * CASES: + * - ROS 2 Topic Name: "hello" Return: "rqhello" + * - ROS 2 Topic Name: "hello/rq" Return: "rqhello/rq" + * - ROS 2 Topic Name: "/hello" Return: "rq/hello" + * - ROS 2 Topic Name: "rq/hello" Return: "rqrq/hello" + */ +TEST(ROS2ManglingTest, add_ros_service_requester_prefix) +{ + EXPECT_EQ("rqhello", add_ros_service_requester_prefix("hello")); + EXPECT_EQ("rqhello/rq", add_ros_service_requester_prefix("hello/rq")); + EXPECT_EQ("rq/hello", add_ros_service_requester_prefix("/hello")); + EXPECT_EQ("rqrq/hello", add_ros_service_requester_prefix("rq/hello")); +} + +/** + * Test add_ros_service_response_prefix() method + * + * CASES: + * - ROS 2 Topic Name: "hello" Return: "rrhello" + * - ROS 2 Topic Name: "hello/rr" Return: "rrhello/rr" + * - ROS 2 Topic Name: "/hello" Return: "rr/hello" + * - ROS 2 Topic Name: "rr/hello" Return: "rrrr/hello" + */ +TEST(ROS2ManglingTest, add_ros_service_response_prefix) +{ + EXPECT_EQ("rrhello", add_ros_service_response_prefix("hello")); + EXPECT_EQ("rrhello/rr", add_ros_service_response_prefix("hello/rr")); + EXPECT_EQ("rr/hello", add_ros_service_response_prefix("/hello")); + EXPECT_EQ("rrrr/hello", add_ros_service_response_prefix("rr/hello")); +} + +/** + * Test get_all_ros_prefixes() method + */ +TEST(ROS2ManglingTest, get_all_ros_prefixes) +{ + const std::vector ros_prefixes = {"rt", "rq", "rr"}; + EXPECT_EQ(ros_prefixes, get_all_ros_prefixes()); +} + +/** + * Test demangle_if_ros_topic() method + * + * CASES: + * - Topic Name: "hello" Return: "hello" + * - Topic Name: "hello/rt" Return: "hello/rt" + * - Topic Name: "rt/hello" Return: "/hello" + * - Topic Name: "/rt/hello" Return: "/rt/hello" + * - Topic Name: "hello/rq" Return: "hello/rq" + * - Topic Name: "rq/hello" Return: "/hello" + * - Topic Name: "/rq/hello" Return: "/rq/hello" + * - Topic Name: "hello/rr" Return: "hello/rr" + * - Topic Name: "rr/hello" Return: "/hello" + * - Topic Name: "/rr/hello" Return: "/rr/hello" + */ +TEST(ROS2ManglingTest, demangle_if_ros_topic) +{ + EXPECT_EQ("hello", demangle_if_ros_topic("hello")); + + // ros_topic_prefix + EXPECT_EQ("hello/rt", demangle_if_ros_topic("hello/rt")); + EXPECT_EQ("/hello", demangle_if_ros_topic("rt/hello")); + EXPECT_EQ("/rt/hello", demangle_if_ros_topic("/rt/hello")); + + // ros_service_requester_prefix + EXPECT_EQ("hello/rq", demangle_if_ros_topic("hello/rq")); + EXPECT_EQ("/hello", demangle_if_ros_topic("rq/hello")); + EXPECT_EQ("/rq/hello", demangle_if_ros_topic("/rq/hello")); + + // ros_service_requester_prefix + EXPECT_EQ("hello/rr", demangle_if_ros_topic("hello/rr")); + EXPECT_EQ("/hello", demangle_if_ros_topic("rr/hello")); + EXPECT_EQ("/rr/hello", demangle_if_ros_topic("/rr/hello")); +} + +/** + * Test mangle_if_ros_topic() method + * + * CASES: + * - Topic Name: "hello" Return: "hello" + * - Topic Name: "hello/rt" Return: "hello/rt" + * - Topic Name: "/hello" Return: "rt/hello" + * - Topic Name: "/rt/hello" Return: "rt/rt/hello" + */ +TEST(ROS2ManglingTest, mangle_if_ros_topic) +{ + EXPECT_EQ("hello", mangle_if_ros_topic("hello")); + EXPECT_EQ("hello/rt", mangle_if_ros_topic("hello/rt")); + EXPECT_EQ("rt/hello", mangle_if_ros_topic("/hello")); + EXPECT_EQ("rt/rt/hello", mangle_if_ros_topic("/rt/hello")); +} + +/** + * Test demangle_if_ros_type() method + * + * CASES: + * - Type Name: "hello" Return: "hello" + * - Type Name: "msg::dds_" Return: "msg::dds_" + * - Type Name: "msgs::msg::" Return: "msgs::msg::" + * - Type Name: "msgs::msg::dds_" Return: "msgs::msg::dds_" + * - Type Name: "msg::dds_::hello" Return: "msg::dds_::hello" + * - Type Name: "std_msgs::msg::dds_::String_" Return: "std_msgs/msg/String" + */ +TEST(ROS2ManglingTest, demangle_if_ros_type) +{ + // not a ROS type + EXPECT_EQ("hello", demangle_if_ros_type("hello")); + EXPECT_EQ("msg::dds_", demangle_if_ros_type("msg::dds_")); + EXPECT_EQ("msgs::msg::", demangle_if_ros_type("msgs::msg::")); + EXPECT_EQ("msgs::msg::dds_", demangle_if_ros_type("msgs::msg::dds_")); + EXPECT_EQ("msgs::msg::hello", demangle_if_ros_type("msgs::msg::hello")); + + // ROS type + EXPECT_EQ("std_msgs/msg/String", demangle_if_ros_type("std_msgs::msg::dds_::String_")); +} + +/** + * Test mangle_if_ros_type() method + * + * CASES: + * - Type Name: "hello" Return: "hello" + * - Type Name: "msg" Return: "msg" + * - Type Name: "std_msgs/msg/" Return: "std_msgs/msg/" + * - Type Name: "std_msgs/msg/String" Return: "std_msgs::msg::dds_::String_" + */ +TEST(ROS2ManglingTest, mangle_if_ros_type) +{ + // not a ROS type + EXPECT_EQ("hello", mangle_if_ros_type("hello")); + EXPECT_EQ("msg", mangle_if_ros_type("msg")); + EXPECT_EQ("std_msgs/msg/", mangle_if_ros_type("std_msgs/msg/")); + + // ROS type + EXPECT_EQ("std_msgs::msg::dds_::String_", mangle_if_ros_type("std_msgs/msg/String")); +} + +/** + * Test demangle_ros_topic_prefix_from_topic() method + * + * CASES: + * - Topic Name: "hello" Return: "" + * - Topic Name: "hello/rt" Return: "" + * - Topic Name: "rt/hello" Return: "/hello" + * - Topic Name: "hello/rq" Return: "" + * - Topic Name: "rq/hello" Return: "" + * - Topic Name: "hello/rr" Return: "" + * - Topic Name: "rr/hello" Return: "" + */ +TEST(ROS2ManglingTest, demangle_ros_topic_prefix_from_topic) +{ + EXPECT_EQ("", demangle_ros_topic_prefix_from_topic("hello")); + EXPECT_EQ("", demangle_ros_topic_prefix_from_topic("hello/rt")); + EXPECT_EQ("/hello", demangle_ros_topic_prefix_from_topic("rt/hello")); + + EXPECT_EQ("", demangle_ros_topic_prefix_from_topic("hello/rq")); + EXPECT_EQ("", demangle_ros_topic_prefix_from_topic("rq/hello")); + + EXPECT_EQ("", demangle_ros_topic_prefix_from_topic("hello/rr")); + EXPECT_EQ("", demangle_ros_topic_prefix_from_topic("rr/hello")); +} + +/** + * Test demangle_ros_service_prefix_from_topic() method + * + * CASES: + * - Service Name: "hello" Return: "" + * - Service Name: "rq/hello" Return: "" + * - Service Name: "rr/hello" Return: "" + * - Service Name: "rq/hello/worldRequest" Return: "/hello/world" + * - Service Name: "rr/hello/worldReply" Return: "/hello/world" + * - Service Name: "Request/hello/worldrq" Return: "" + * - Service Name: "Reply/hello/worldrr" Return: "" + */ +TEST(ROS2ManglingTest, demangle_ros_service_prefix_from_topic) +{ + EXPECT_EQ("", demangle_ros_service_prefix_from_topic("hello")); + + EXPECT_EQ("", demangle_ros_service_prefix_from_topic("rq/hello")); + EXPECT_EQ("", demangle_ros_service_prefix_from_topic("rr/hello")); + + EXPECT_EQ("/hello/world", demangle_ros_service_prefix_from_topic("rq/hello/worldRequest")); + EXPECT_EQ("/hello/world", demangle_ros_service_prefix_from_topic("rr/hello/worldReply")); + + EXPECT_EQ("", demangle_ros_service_prefix_from_topic("Request/hello/worldrq")); + EXPECT_EQ("", demangle_ros_service_prefix_from_topic("Reply/hello/worldrr")); +} + +/** + * Test demangle_ros_service_request_prefix_from_topic() method + * + * CASES: + * - Service Request Name: "hello" Return: "" + * - Service Request Name: "rq/hello" Return: "" + * - Service Request Name: "rr/hello" Return: "" + * - Service Request Name: "rq/hello/worldRequest" Return: "/hello/world" + * - Service Request Name: "rr/hello/worldReply" Return: "" + * - Service Request Name: "Request/hello/worldrq" Return: "" + * - Service Request Name: "Reply/hello/worldrr" Return: "" + */ +TEST(ROS2ManglingTest, demangle_ros_service_request_prefix_from_topic) +{ + EXPECT_EQ("", demangle_ros_service_request_prefix_from_topic("hello")); + + EXPECT_EQ("", demangle_ros_service_request_prefix_from_topic("rq/hello")); + EXPECT_EQ("", demangle_ros_service_request_prefix_from_topic("rr/hello")); + + EXPECT_EQ("/hello/world", demangle_ros_service_request_prefix_from_topic("rq/hello/worldRequest")); + EXPECT_EQ("", demangle_ros_service_request_prefix_from_topic("rr/hello/worldReply")); + + EXPECT_EQ("", demangle_ros_service_request_prefix_from_topic("Request/hello/worldrq")); + EXPECT_EQ("", demangle_ros_service_request_prefix_from_topic("Reply/hello/worldrr")); +} + +/** + * Test mangle_ros_service_request_prefix_in_topic() method + * + * CASES: + * - Service Request Name: "hello" Return: "" + * - Service Request Name: "rq/hello" Return: "" + * - Service Request Name: "rr/hello" Return: "" + * - Service Request Name: "/hello" Return: "rq/helloRequest" + */ +TEST(ROS2ManglingTest, mangle_ros_service_request_prefix_in_topic) +{ + EXPECT_EQ("", mangle_ros_service_request_prefix_in_topic("hello")); + + EXPECT_EQ("", mangle_ros_service_request_prefix_in_topic("rq/hello")); + EXPECT_EQ("", mangle_ros_service_request_prefix_in_topic("rr/hello")); + + EXPECT_EQ("rq/helloRequest", mangle_ros_service_request_prefix_in_topic("/hello")); +} + +/** + * Test demangle_ros_service_reply_prefix_from_topic() method + * + * CASES: + * - Service Reply Name: "hello" Return: "" + * - Service Reply Name: "rq/hello" Return: "" + * - Service Reply Name: "rr/hello" Return: "" + * - Service Reply Name: "rq/hello/worldRequest" Return: "" + * - Service Reply Name: "rr/hello/worldReply" Return: "/hello/world" + * - Service Reply Name: "Request/hello/worldrq" Return: "" + * - Service Reply Name: "Reply/hello/worldrr" Return: "" + */ +TEST(ROS2ManglingTest, demangle_ros_service_reply_prefix_from_topic) +{ + EXPECT_EQ("", demangle_ros_service_reply_prefix_from_topic("hello")); + + EXPECT_EQ("", demangle_ros_service_reply_prefix_from_topic("rq/hello")); + EXPECT_EQ("", demangle_ros_service_reply_prefix_from_topic("rr/hello")); + + EXPECT_EQ("", demangle_ros_service_reply_prefix_from_topic("rq/hello/worldRequest")); + EXPECT_EQ("/hello/world", demangle_ros_service_reply_prefix_from_topic("rr/hello/worldReply")); + + EXPECT_EQ("", demangle_ros_service_reply_prefix_from_topic("Request/hello/worldrq")); + EXPECT_EQ("", demangle_ros_service_reply_prefix_from_topic("Reply/hello/worldrr")); +} + +/** + * Test mangle_ros_service_reply_prefix_in_topic() method + * + * CASES: + * - Service Reply Name: "hello" Return: "" + * - Service Reply Name: "rq/hello" Return: "" + * - Service Reply Name: "rr/hello" Return: "" + * - Service Reply Name: "/hello" Return: "rr/helloReply" + */ +TEST(ROS2ManglingTest, mangle_ros_service_reply_prefix_in_topic) +{ + EXPECT_EQ("", mangle_ros_service_reply_prefix_in_topic("hello")); + + EXPECT_EQ("", mangle_ros_service_reply_prefix_in_topic("rq/hello")); + EXPECT_EQ("", mangle_ros_service_reply_prefix_in_topic("rr/hello")); + + EXPECT_EQ("rr/helloReply", mangle_ros_service_reply_prefix_in_topic("/hello")); +} + +/** + * Test demangle_service_type_only() method + * + * CASES: + * - DDS Service Name: "hello" Return: "" + * - DDS Service Name: "rq/hello" Return: "" + * - DDS Service Name: "rr/hello" Return: "" + * - DDS Service Name: "rt/hello" Return: "" + * - DDS Service Name: "rq::dds_::hello" Return: "" + * - DDS Service Name: "rr::dds_::hello" Return: "" + * - DDS Service Name: "rt::dds_::hello" Return: "" + * - DDS Service Name: "rq::srv::dds_::hello_Request_" Return: "rq/srv/hello" + * - DDS Service Name: "rr::srv::dds_::hello_Request_" Return: "rr/srv/hello" + */ +TEST(ROS2ManglingTest, demangle_service_type_only) +{ + // not a ROS service type + EXPECT_EQ("", demangle_service_type_only("hello")); + EXPECT_EQ("", demangle_service_type_only("rq/hello")); + EXPECT_EQ("", demangle_service_type_only("rr/hello")); + EXPECT_EQ("", demangle_service_type_only("rt/hello")); + + EXPECT_EQ("", demangle_service_type_only("rq::dds_::hello")); + EXPECT_EQ("", demangle_service_type_only("rr::dds_::hello")); + EXPECT_EQ("", demangle_service_type_only("rt::dds_::hello")); + + // ROS service type + EXPECT_EQ("rq/srv/hello", demangle_service_type_only("rq::srv::dds_::hello_Request_")); + EXPECT_EQ("rr/srv/hello", demangle_service_type_only("rr::srv::dds_::hello_Response_")); +} + +/** + * Test mangle_service_type_only() method + * + * CASES: + * - DDS Service Name: "hello" Return: "" + * - DDS Service Name: "rt/hello" Return: "" + * - DDS Service Name: "rq/hello" Return: "rq::dds_::hello_Request_" + * - DDS Service Name: "rr/hello" Return: "rr::dds_::hello_Response_" + * - DDS Service Name: "rq::dds_::hello" Return: "" + * - DDS Service Name: "rr::dds_::hello" Return: "" + * - DDS Service Name: "rt::dds_::hello" Return: "" + */ +TEST(ROS2ManglingTest, mangle_service_type_only) +{ + EXPECT_EQ("", mangle_service_type_only("hello")); + EXPECT_EQ("", mangle_service_type_only("rt/hello")); + + EXPECT_EQ("rq::srv::dds_::hello_Request_", mangle_service_type_only("rq/srv/hello")); + EXPECT_EQ("rr::srv::dds_::hello_Response_", mangle_service_type_only("rr/srv/hello")); + + EXPECT_EQ("", mangle_service_type_only("rq::dds_::hello")); + EXPECT_EQ("", mangle_service_type_only("rr::dds_::hello")); + EXPECT_EQ("", mangle_service_type_only("rt::dds_::hello")); +} + +int main( + int argc, + char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} From 402f3f676c887d83e31e589f821d5264a46c5587 Mon Sep 17 00:00:00 2001 From: Irene Bandera Date: Fri, 27 Oct 2023 11:23:53 +0200 Subject: [PATCH 2/7] Update versions.md Signed-off-by: Irene Bandera --- versions.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/versions.md b/versions.md index df1d3edc..edfc39e1 100644 --- a/versions.md +++ b/versions.md @@ -3,6 +3,9 @@ This file includes the released versions of **dev-utils** project along with their contributions to the project. The *Forthcoming* section includes those features added in `main` branch that are not yet in a stable release. +## Forthcoming + +* Add ROS 2 mangling methods. ## Version 0.4.0 From 6988b6266485c472836159ff8e40345b03942977 Mon Sep 17 00:00:00 2001 From: Irene Bandera Date: Fri, 27 Oct 2023 11:48:15 +0200 Subject: [PATCH 3/7] Fix filename in CMakeLists.txt Signed-off-by: Irene Bandera --- cpp_utils/include/cpp_utils/ros2_mangling.hpp | 23 +++++++++++++++++++ cpp_utils/test/labels/CMakeLists.txt | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/cpp_utils/include/cpp_utils/ros2_mangling.hpp b/cpp_utils/include/cpp_utils/ros2_mangling.hpp index f6ce30b2..5bb3face 100644 --- a/cpp_utils/include/cpp_utils/ros2_mangling.hpp +++ b/cpp_utils/include/cpp_utils/ros2_mangling.hpp @@ -16,6 +16,8 @@ #include +#include + namespace eprosima { namespace utils { @@ -25,6 +27,7 @@ namespace utils { * @return name stripped of prefix, or * @return "" if name doesn't start with prefix */ +CPP_UTILS_DllAPI std::string remove_prefix( const std::string& name, const std::string& prefix); @@ -34,6 +37,7 @@ std::string remove_prefix( * @param[in] prefix prefix to be added * @return Returns the name with the prefix added "prefixname" */ +CPP_UTILS_DllAPI std::string add_prefix( const std::string& name, const std::string& prefix); @@ -41,6 +45,7 @@ std::string add_prefix( /** * @todo */ +CPP_UTILS_DllAPI std::string add_suffix( const std::string& name, const std::string& suffix); @@ -48,6 +53,7 @@ std::string add_suffix( /** * @return Returns the ROS specific prefix if present, otherwise "". */ +CPP_UTILS_DllAPI std::string get_ros_prefix_if_exists( const std::string& topic_name); @@ -56,100 +62,117 @@ std::string get_ros_prefix_if_exists( * * @return Returns the topic name stripped of a ROS specific prefix if present. */ +CPP_UTILS_DllAPI std::string remove_ros_prefix_if_exists( const std::string& topic_name); /** * @todo */ +CPP_UTILS_DllAPI std::string add_ros_topic_prefix( const std::string& topic_name); /** * @todo */ +CPP_UTILS_DllAPI std::string add_ros_service_requester_prefix( const std::string& topic_name); /** * @todo */ +CPP_UTILS_DllAPI std::string add_ros_service_response_prefix( const std::string& topic_name); /** * @return Returns \c ros_prefixes_. */ +CPP_UTILS_DllAPI const std::vector& get_all_ros_prefixes(); /** * @return Returns the demangle ROS topic or the original if not a ROS topic. */ +CPP_UTILS_DllAPI std::string demangle_if_ros_topic( const std::string& topic_name); /** * @todo */ +CPP_UTILS_DllAPI std::string mangle_if_ros_topic( const std::string& topic_name); /** * @return Returns the demangled ROS type or the original if not a ROS type. */ +CPP_UTILS_DllAPI std::string demangle_if_ros_type( const std::string& dds_type_string); /** * @todo */ +CPP_UTILS_DllAPI std::string mangle_if_ros_type( const std::string& ros2_type_string); /** * @return Returns the topic name for a given topic if it is part of a ROS topic, otherwise "". */ +CPP_UTILS_DllAPI std::string demangle_ros_topic_prefix_from_topic( const std::string& topic_name); /** * @return Returns the service name for a given topic if it is part of a ROS service, otherwise "". */ +CPP_UTILS_DllAPI std::string demangle_ros_service_prefix_from_topic( const std::string& topic_name); /** * @return Returns the service name for a given topic if it is part of a ROS service request, otherwise "". */ +CPP_UTILS_DllAPI std::string demangle_ros_service_request_prefix_from_topic( const std::string& topic_name); /** * @todo */ +CPP_UTILS_DllAPI std::string mangle_ros_service_request_prefix_in_topic( const std::string& topic_name); /** * @return Returns the service name for a given topic if it is part of a service response, otherwise "". */ +CPP_UTILS_DllAPI std::string demangle_ros_service_reply_prefix_from_topic( const std::string& topic_name); /** * @todo */ +CPP_UTILS_DllAPI std::string mangle_ros_service_reply_prefix_in_topic( const std::string& topic_name); /** * @return Returns the demangled service type if it is an ROS srv type, otherwise "". */ +CPP_UTILS_DllAPI std::string demangle_service_type_only( const std::string& dds_type_name); /** * @todo */ +CPP_UTILS_DllAPI std::string mangle_service_type_only( const std::string& ros2_type_name); diff --git a/cpp_utils/test/labels/CMakeLists.txt b/cpp_utils/test/labels/CMakeLists.txt index a92ef04f..ccd8cc3c 100644 --- a/cpp_utils/test/labels/CMakeLists.txt +++ b/cpp_utils/test/labels/CMakeLists.txt @@ -19,5 +19,5 @@ set_test_label_file(${CMAKE_CURRENT_SOURCE_DIR}/XTSAN.list "xtsan") # Set list of tests that can fail in windows if (WIN32) - set_test_label_file(${CMAKE_CURRENT_SOURCE_DIR}/WINDOWS_TEST_XFAIL.list "xfail") + set_test_label_file(${CMAKE_CURRENT_SOURCE_DIR}/WINDOWS_XFAIL.list "xfail") endif() From 71a05ef37f8efbdd90a8a671d079bf3f1c70f19e Mon Sep 17 00:00:00 2001 From: Irene Bandera Date: Fri, 27 Oct 2023 11:48:15 +0200 Subject: [PATCH 4/7] Fix filename in CMakeLists.txt Signed-off-by: Irene Bandera --- cpp_utils/src/cpp/ros2_mangling.cpp | 1 + cpp_utils/test/labels/CMakeLists.txt | 2 +- cpp_utils/test/unittest/ros2_mangling/CMakeLists.txt | 1 + cpp_utils/test/unittest/ros2_mangling/ROS2ManglingTest.cpp | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/cpp_utils/src/cpp/ros2_mangling.cpp b/cpp_utils/src/cpp/ros2_mangling.cpp index e3e52130..3cd50089 100644 --- a/cpp_utils/src/cpp/ros2_mangling.cpp +++ b/cpp_utils/src/cpp/ros2_mangling.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include diff --git a/cpp_utils/test/labels/CMakeLists.txt b/cpp_utils/test/labels/CMakeLists.txt index a92ef04f..ccd8cc3c 100644 --- a/cpp_utils/test/labels/CMakeLists.txt +++ b/cpp_utils/test/labels/CMakeLists.txt @@ -19,5 +19,5 @@ set_test_label_file(${CMAKE_CURRENT_SOURCE_DIR}/XTSAN.list "xtsan") # Set list of tests that can fail in windows if (WIN32) - set_test_label_file(${CMAKE_CURRENT_SOURCE_DIR}/WINDOWS_TEST_XFAIL.list "xfail") + set_test_label_file(${CMAKE_CURRENT_SOURCE_DIR}/WINDOWS_XFAIL.list "xfail") endif() diff --git a/cpp_utils/test/unittest/ros2_mangling/CMakeLists.txt b/cpp_utils/test/unittest/ros2_mangling/CMakeLists.txt index 9ec2b22b..b6b01dea 100644 --- a/cpp_utils/test/unittest/ros2_mangling/CMakeLists.txt +++ b/cpp_utils/test/unittest/ros2_mangling/CMakeLists.txt @@ -54,6 +54,7 @@ set(TEST_LIST set(TEST_EXTRA_LIBRARIES fastcdr fastrtps + $<$:iphlpapi$Shlwapi> ) add_unittest_executable( diff --git a/cpp_utils/test/unittest/ros2_mangling/ROS2ManglingTest.cpp b/cpp_utils/test/unittest/ros2_mangling/ROS2ManglingTest.cpp index 83764608..978f5ab2 100644 --- a/cpp_utils/test/unittest/ros2_mangling/ROS2ManglingTest.cpp +++ b/cpp_utils/test/unittest/ros2_mangling/ROS2ManglingTest.cpp @@ -15,6 +15,7 @@ #include #include + #include using namespace eprosima::utils; From 260d70c142a52ad539031138391135aee6e477fd Mon Sep 17 00:00:00 2001 From: Irene Bandera Date: Tue, 31 Oct 2023 17:25:26 +0100 Subject: [PATCH 5/7] Apply changes Signed-off-by: Irene Bandera --- cpp_utils/include/cpp_utils/ros2_mangling.hpp | 62 +++++++++++++++---- cpp_utils/src/cpp/ros2_mangling.cpp | 24 +++---- .../ros2_mangling/ROS2ManglingTest.cpp | 4 +- 3 files changed, 66 insertions(+), 24 deletions(-) diff --git a/cpp_utils/include/cpp_utils/ros2_mangling.hpp b/cpp_utils/include/cpp_utils/ros2_mangling.hpp index 5bb3face..581023e6 100644 --- a/cpp_utils/include/cpp_utils/ros2_mangling.hpp +++ b/cpp_utils/include/cpp_utils/ros2_mangling.hpp @@ -15,6 +15,7 @@ #pragma once #include +#include #include @@ -43,7 +44,9 @@ std::string add_prefix( const std::string& prefix); /** - * @todo + * @param[in] name string to be suffixed with "suffix" + * @param[in] suffix suffix to be added + * @return Returns the name with the suffix added "namesuffix" */ CPP_UTILS_DllAPI std::string add_suffix( @@ -51,6 +54,7 @@ std::string add_suffix( const std::string& suffix); /** + * @param[in] topic_name name of the topic * @return Returns the ROS specific prefix if present, otherwise "". */ CPP_UTILS_DllAPI @@ -58,7 +62,8 @@ std::string get_ros_prefix_if_exists( const std::string& topic_name); /** - * @brief Remove the ROS specific prefix from the topic name if it exists. + * @brief Remove the ROS specific prefix from the \c topic_name if it exists. + * @param[in] topic_name name of the topic * * @return Returns the topic name stripped of a ROS specific prefix if present. */ @@ -67,21 +72,30 @@ std::string remove_ros_prefix_if_exists( const std::string& topic_name); /** - * @todo + * @brief Add the ROS Topic prefix in the \c topic_name. + * @param[in] topic_name name of the topic + * + * @return Returns the topic name with the ROS Topic prefix. */ CPP_UTILS_DllAPI std::string add_ros_topic_prefix( const std::string& topic_name); /** - * @todo + * @brief Add the ROS Service Requester prefix in the \c topic_name. + * @param[in] topic_name name of the topic + * + * @return Returns the topic name with the ROS Requester prefix. */ CPP_UTILS_DllAPI std::string add_ros_service_requester_prefix( const std::string& topic_name); /** - * @todo + * @brief Add the ROS Service Response prefix in the \c topic_name. + * @param[in] topic_name name of the topic + * + * @return Returns the topic name with the ROS Response prefix. */ CPP_UTILS_DllAPI std::string add_ros_service_response_prefix( @@ -94,6 +108,8 @@ CPP_UTILS_DllAPI const std::vector& get_all_ros_prefixes(); /** + * @param[in] topic_name name of the topic + * * @return Returns the demangle ROS topic or the original if not a ROS topic. */ CPP_UTILS_DllAPI @@ -101,13 +117,17 @@ std::string demangle_if_ros_topic( const std::string& topic_name); /** - * @todo + * @param[in] topic_name name of the topic + * + * @return Returns the mangle ROS topic or the original if not a ROS topic (start with "/"). */ CPP_UTILS_DllAPI std::string mangle_if_ros_topic( const std::string& topic_name); /** + * @param[in] topic_name name of the topic + * * @return Returns the demangled ROS type or the original if not a ROS type. */ CPP_UTILS_DllAPI @@ -115,13 +135,17 @@ std::string demangle_if_ros_type( const std::string& dds_type_string); /** - * @todo + * @param[in] topic_name name of the topic + * + * @return Returns the DDS type or the original if not a ROS type. */ CPP_UTILS_DllAPI std::string mangle_if_ros_type( const std::string& ros2_type_string); /** + * @param[in] topic_name name of the topic + * * @return Returns the topic name for a given topic if it is part of a ROS topic, otherwise "". */ CPP_UTILS_DllAPI @@ -129,12 +153,16 @@ std::string demangle_ros_topic_prefix_from_topic( const std::string& topic_name); /** + * @param[in] topic_name name of the topic + * * @return Returns the service name for a given topic if it is part of a ROS service, otherwise "". */ CPP_UTILS_DllAPI std::string demangle_ros_service_prefix_from_topic( const std::string& topic_name); /** + * @param[in] topic_name name of the topic + * * @return Returns the service name for a given topic if it is part of a ROS service request, otherwise "". */ CPP_UTILS_DllAPI @@ -142,13 +170,18 @@ std::string demangle_ros_service_request_prefix_from_topic( const std::string& topic_name); /** - * @todo + * @param[in] topic_name name of the topic + * + * @return Returns the service name for a given topic with the ros service requester prefix + * if it is part of a service request (start with "/"), otherwise "". */ CPP_UTILS_DllAPI std::string mangle_ros_service_request_prefix_in_topic( const std::string& topic_name); /** + * @param[in] topic_name name of the topic + * * @return Returns the service name for a given topic if it is part of a service response, otherwise "". */ CPP_UTILS_DllAPI @@ -156,21 +189,28 @@ std::string demangle_ros_service_reply_prefix_from_topic( const std::string& topic_name); /** - * @todo + * @param[in] topic_name name of the topic + * + * @return Returns the service name for a given topic with the ros service response prefix if + * it is part of a service response (start with "/"), otherwise "". */ CPP_UTILS_DllAPI std::string mangle_ros_service_reply_prefix_in_topic( const std::string& topic_name); /** - * @return Returns the demangled service type if it is an ROS srv type, otherwise "". + * @param[in] dds_type_name name of the topic + * + * @return Returns the demangled service type if it is an DDS srv type, otherwise "". */ CPP_UTILS_DllAPI std::string demangle_service_type_only( const std::string& dds_type_name); /** - * @todo + * @param[in] ros2_type_name name of the topic + * + * @return Returns the mangled service type if it is an ROS srv type, otherwise "". */ CPP_UTILS_DllAPI std::string mangle_service_type_only( diff --git a/cpp_utils/src/cpp/ros2_mangling.cpp b/cpp_utils/src/cpp/ros2_mangling.cpp index 3cd50089..dcd46351 100644 --- a/cpp_utils/src/cpp/ros2_mangling.cpp +++ b/cpp_utils/src/cpp/ros2_mangling.cpp @@ -13,8 +13,6 @@ // limitations under the License. #include -#include -#include #include #include @@ -32,6 +30,8 @@ const char* const ros_service_response_prefix = "rr"; const std::vector ros_prefixes_ = {ros_topic_prefix, ros_service_requester_prefix, ros_service_response_prefix}; +const char* const ros2_msgs_format = "_msgs/msg/"; + std::string remove_prefix( const std::string& name, const std::string& prefix) @@ -155,7 +155,7 @@ std::string mangle_if_ros_type( { std::string dds_type_string = ros2_type_string; - size_t substring_position = dds_type_string.find("_msgs/msg/"); + size_t substring_position = dds_type_string.find(ros2_msgs_format); if (substring_position == std::string::npos) { return dds_type_string; @@ -163,8 +163,9 @@ std::string mangle_if_ros_type( std::string substring = "dds_::"; - std::string type_namespace = dds_type_string.substr(0, substring_position + 10); - std::string type_name = dds_type_string.substr(substring_position + 10, dds_type_string.length() - 1); + std::string type_namespace = dds_type_string.substr(0, substring_position + strlen(ros2_msgs_format)); + std::string type_name = dds_type_string.substr(substring_position + strlen(ros2_msgs_format), + dds_type_string.length() - substring_position - strlen(ros2_msgs_format)); if (type_name.length() == 0) { @@ -219,8 +220,8 @@ std::string mangle_ros_service_in_topic( const std::string& topic_name, const std::string suffix) { - size_t suffix_position = topic_name.rfind("/"); - if (suffix_position != 0) + size_t topic_name_position = topic_name.rfind("/"); + if (topic_name_position != 0) { return ""; } @@ -323,17 +324,18 @@ std::string mangle_service_type_only( return ""; } - std::string dds_type_name = ros2_type_name.substr(0, ns_substring_srv_position + 5) + "dds_::"; - dds_type_name = dds_type_name + ros2_type_name.substr(ns_substring_srv_position + 5, ros2_type_name.length() - 1); + std::string dds_type_name = ros2_type_name.substr(0, ns_substring_srv_position + strlen("/srv/")) + "dds_::"; + dds_type_name = dds_type_name + ros2_type_name.substr(ns_substring_srv_position + strlen( + "/srv/"), ros2_type_name.length() - ns_substring_srv_position - strlen("/srv/")); size_t ns_substring_rq_position = ros2_type_name.find("rq/"); size_t ns_substring_rr_position = ros2_type_name.find("rr/"); - if (std::string::npos != ns_substring_rq_position) + if (0 == ns_substring_rq_position) { dds_type_name = dds_type_name + "_Request_"; } - else if (std::string::npos != ns_substring_rr_position) + else if (0 == ns_substring_rr_position) { dds_type_name = dds_type_name + "_Response_"; } diff --git a/cpp_utils/test/unittest/ros2_mangling/ROS2ManglingTest.cpp b/cpp_utils/test/unittest/ros2_mangling/ROS2ManglingTest.cpp index 978f5ab2..bbf92b32 100644 --- a/cpp_utils/test/unittest/ros2_mangling/ROS2ManglingTest.cpp +++ b/cpp_utils/test/unittest/ros2_mangling/ROS2ManglingTest.cpp @@ -477,8 +477,8 @@ TEST(ROS2ManglingTest, demangle_service_type_only) * CASES: * - DDS Service Name: "hello" Return: "" * - DDS Service Name: "rt/hello" Return: "" - * - DDS Service Name: "rq/hello" Return: "rq::dds_::hello_Request_" - * - DDS Service Name: "rr/hello" Return: "rr::dds_::hello_Response_" + * - DDS Service Name: "rq/srv/hello" Return: "rq::srv::dds_::hello_Request_" + * - DDS Service Name: "rr/srv/hello" Return: "rr::srv::dds_::hello_Response_" * - DDS Service Name: "rq::dds_::hello" Return: "" * - DDS Service Name: "rr::dds_::hello" Return: "" * - DDS Service Name: "rt::dds_::hello" Return: "" From 8fe9072527187116258c4e614ef2a6c43739fe05 Mon Sep 17 00:00:00 2001 From: Irene Bandera Date: Thu, 2 Nov 2023 16:35:54 +0100 Subject: [PATCH 6/7] Apply changes Signed-off-by: Irene Bandera --- cpp_utils/include/cpp_utils/ros2_mangling.hpp | 143 ++++++++++++++---- cpp_utils/src/cpp/ros2_mangling.cpp | 9 +- 2 files changed, 120 insertions(+), 32 deletions(-) diff --git a/cpp_utils/include/cpp_utils/ros2_mangling.hpp b/cpp_utils/include/cpp_utils/ros2_mangling.hpp index 581023e6..8fbb53fc 100644 --- a/cpp_utils/include/cpp_utils/ros2_mangling.hpp +++ b/cpp_utils/include/cpp_utils/ros2_mangling.hpp @@ -25,6 +25,7 @@ namespace utils { /** * @param[in] name string that will be stripped from prefix * @param[in] prefix prefix to be stripped + * * @return name stripped of prefix, or * @return "" if name doesn't start with prefix */ @@ -36,6 +37,7 @@ std::string remove_prefix( /** * @param[in] name string to be prefixed with "prefix" * @param[in] prefix prefix to be added + * * @return Returns the name with the prefix added "prefixname" */ CPP_UTILS_DllAPI @@ -46,6 +48,7 @@ std::string add_prefix( /** * @param[in] name string to be suffixed with "suffix" * @param[in] suffix suffix to be added + * * @return Returns the name with the suffix added "namesuffix" */ CPP_UTILS_DllAPI @@ -54,7 +57,8 @@ std::string add_suffix( const std::string& suffix); /** - * @param[in] topic_name name of the topic + * @param[in] topic_name The name of the topic to be processed. + * * @return Returns the ROS specific prefix if present, otherwise "". */ CPP_UTILS_DllAPI @@ -63,7 +67,8 @@ std::string get_ros_prefix_if_exists( /** * @brief Remove the ROS specific prefix from the \c topic_name if it exists. - * @param[in] topic_name name of the topic + * + * @param[in] topic_name The name of the topic to be processed. * * @return Returns the topic name stripped of a ROS specific prefix if present. */ @@ -73,7 +78,8 @@ std::string remove_ros_prefix_if_exists( /** * @brief Add the ROS Topic prefix in the \c topic_name. - * @param[in] topic_name name of the topic + * + * @param[in] topic_name The name of the topic to be processed. * * @return Returns the topic name with the ROS Topic prefix. */ @@ -83,7 +89,8 @@ std::string add_ros_topic_prefix( /** * @brief Add the ROS Service Requester prefix in the \c topic_name. - * @param[in] topic_name name of the topic + * + * @param[in] topic_name The name of the topic to be processed. * * @return Returns the topic name with the ROS Requester prefix. */ @@ -93,7 +100,8 @@ std::string add_ros_service_requester_prefix( /** * @brief Add the ROS Service Response prefix in the \c topic_name. - * @param[in] topic_name name of the topic + * + * @param[in] topic_name The name of the topic to be processed. * * @return Returns the topic name with the ROS Response prefix. */ @@ -108,7 +116,13 @@ CPP_UTILS_DllAPI const std::vector& get_all_ros_prefixes(); /** - * @param[in] topic_name name of the topic + * @brief Obtain the ROS topic associated with the provided \c topic_name, + * excluding the ROS prefix. + * + * If the topic_name begins with a ROS prefix (i.e., starts with ROS prefix + "/"). + * If the input topic name does not contain a ROS prefix + "/", it is returned unchanged. + * + * @param[in] topic_name The name of the topic to be processed. * * @return Returns the demangle ROS topic or the original if not a ROS topic. */ @@ -117,7 +131,12 @@ std::string demangle_if_ros_topic( const std::string& topic_name); /** - * @param[in] topic_name name of the topic + * @brief Mangle a given \c topic_name if it starts with "/". + * + * If the topic name begins with "/", it adds the ROS topic prefix to the \c topic_name and then returns it. + * If the topic name does not start with "/", it is returned unchanged. + * + * @param[in] topic_name The name of the topic to be processed. * * @return Returns the mangle ROS topic or the original if not a ROS topic (start with "/"). */ @@ -126,91 +145,157 @@ std::string mangle_if_ros_topic( const std::string& topic_name); /** - * @param[in] topic_name name of the topic + * @brief Demangle a DDS type string if it is a ROS type. * - * @return Returns the demangled ROS type or the original if not a ROS type. + * This function takes a DDS type string as input and checks if it represents a ROS type. + * If the input type string is not a ROS type, it is returned unchanged. + * If the input type string is a ROS type, it demangles the type string by converting DDS-specific namespace + * separators ("::") to "/", removing "dds" and returns the demangled result. + * + * @param[in] dds_type_string DDS type string to be processed. + * + * @return The demangled ROS type string or the original input if it is not a ROS type. */ CPP_UTILS_DllAPI std::string demangle_if_ros_type( const std::string& dds_type_string); /** - * @param[in] topic_name name of the topic + * @brief Mangle a ROS 2 type string into a DDS type string. + * + * This function takes a ROS 2 type string as input and mangles it into a DDS type string. + * If the input string does not contain a ROS 2-specific substring, it is returned unchanged. + * If the ROS 2 substring is found, this function extracts the type namespace and type name, + * converts namespace separators from "/" to "::", and adds the "dds_::" prefix and a trailing + * underscore to the type name. + * + * @param[in] ros2_type_string The input ROS 2 type string to be mangled. * - * @return Returns the DDS type or the original if not a ROS type. + * @return The mangled DDS type string or the original input if it does not contain the ROS 2 substring. */ CPP_UTILS_DllAPI std::string mangle_if_ros_type( const std::string& ros2_type_string); /** - * @param[in] topic_name name of the topic + * @brief Demangle a ROS topic name by removing the ROS topic prefix. * - * @return Returns the topic name for a given topic if it is part of a ROS topic, otherwise "". + * This function takes a ROS topic name as input and removes the ROS topic prefix if it exists. + * + * @param[in] topic_name The input ROS topic name to be processed. + * + * @return The demangled ROS topic name with the ROS topic prefix removed, or "" if the prefix is not present. */ CPP_UTILS_DllAPI std::string demangle_ros_topic_prefix_from_topic( const std::string& topic_name); /** - * @param[in] topic_name name of the topic + * @brief Demangle a ROS service topic name by identifying its type and extracting the appropriate service name. + * + * This function takes a ROS service topic name as input and attempts to demangle it by identifying its type + * (whether it's a reply or request service topic). + * If neither function successfully demangles the input, an empty string is returned. + * + * @param[in] topic_name The input ROS service topic name to be processed. * - * @return Returns the service name for a given topic if it is part of a ROS service, otherwise "". + * @return The demangled service name if successfully extracted, or an empty string if demangling fails. */ CPP_UTILS_DllAPI std::string demangle_ros_service_prefix_from_topic( const std::string& topic_name); /** - * @param[in] topic_name name of the topic + * @brief Demangle a ROS service request topic name by removing the requester prefix. * - * @return Returns the service name for a given topic if it is part of a ROS service request, otherwise "". + * This function takes a ROS service request topic name as input and removes the specified requester prefix and the common "Request" suffix. + * If the input topic name does not contain both the requester prefix + * and the "Request" suffix, an empty string is returned. + * + * @param[in] topic_name The input ROS service request topic name to be processed. + * + * @return The demangled service name with the requester prefix and "Request" suffix removed, or an empty string + * if the necessary prefixes and suffixes are not present. */ CPP_UTILS_DllAPI std::string demangle_ros_service_request_prefix_from_topic( const std::string& topic_name); /** - * @param[in] topic_name name of the topic + * @brief Mangle a ROS service request topic name by adding the requester prefix and "Request" suffix. + * + * This function takes a ROS service request topic name as input and mangles it by adding the specified + * requester prefix and the common "Request" suffix. If the input topic name starts with "/", indicating + * it is part of a service request, the mangled service name is returned. Otherwise, an empty string is returned. + * + * @param[in] topic_name The input ROS service request topic name to be processed. * - * @return Returns the service name for a given topic with the ros service requester prefix - * if it is part of a service request (start with "/"), otherwise "". + * @return The mangled service name with the requester prefix and "Request" suffix added if + * it is part of a service request (start with "/"), otherwise an empty string (""). */ CPP_UTILS_DllAPI std::string mangle_ros_service_request_prefix_in_topic( const std::string& topic_name); /** - * @param[in] topic_name name of the topic + * @brief Demangle a ROS service reply topic name by removing the response prefix and "Reply" suffix. * - * @return Returns the service name for a given topic if it is part of a service response, otherwise "". + * This function takes a ROS service reply topic name as input and demangles it by removing the specified + * response prefix and the common "Reply" suffix. + * If the input topic name does not contain both the response prefix and the "Reply" suffix, an empty string is returned. + * + * @param[in] topic_name The input ROS service reply topic name to be processed. + * + * @return The demangled service name with the response prefix and "Reply" suffix removed, or an empty string + * if the necessary prefixes and suffixes are not present. */ CPP_UTILS_DllAPI std::string demangle_ros_service_reply_prefix_from_topic( const std::string& topic_name); /** - * @param[in] topic_name name of the topic + * @brief Mangle a ROS service reply topic name by adding the response prefix and "Reply" suffix. + * + * This function takes a ROS service reply topic name as input and mangles it by adding the specified + * response prefix and the common "Reply" suffix. If the input topic name does not start with "/", indicating + * it is part of a service response, an empty string is returned. + * + * @param[in] topic_name The input ROS service reply topic name to be processed. * - * @return Returns the service name for a given topic with the ros service response prefix if - * it is part of a service response (start with "/"), otherwise "". + * @return The mangled service name with the response prefix and "Reply" suffix added if it is part of + * a service response (starts with "/"), otherwise an empty string (""). */ CPP_UTILS_DllAPI std::string mangle_ros_service_reply_prefix_in_topic( const std::string& topic_name); /** - * @param[in] dds_type_name name of the topic + * @brief Demangle a ROS service type name to extract the core type in ROS 2 format. * - * @return Returns the demangled service type if it is an DDS srv type, otherwise "". + * This function takes a ROS service type name in DDS format as input and demangles it to the ROS 2 format, + * extracting the core type. If the input type name does not match the expected ROS service type format, + * an empty string is returned. + * + * @param[in] dds_type_name The input ROS service type name in DDS format to be processed. + * + * @return The demangled core service type name in ROS 2 format, or an empty string if the input + * does not conform to the expected format. */ CPP_UTILS_DllAPI std::string demangle_service_type_only( const std::string& dds_type_name); /** - * @param[in] ros2_type_name name of the topic + * @brief Mangle a ROS 2 service type name to DDS format. + * + * This function takes a ROS 2 service type name as input and mangles it to DDS format by adding necessary + * prefixes and separators. It identifies whether it's a service request or response type and handles the + * conversion accordingly. If the input type name is not in the expected ROS 2 service type format, an empty + * string is returned. + * + * @param[in] ros2_type_name The input ROS 2 service type name to be processed. * - * @return Returns the mangled service type if it is an ROS srv type, otherwise "". + * @return The mangled ROS 2 service type name in DDS format, or an empty string if the input does not + * conform to the expected format. */ CPP_UTILS_DllAPI std::string mangle_service_type_only( diff --git a/cpp_utils/src/cpp/ros2_mangling.cpp b/cpp_utils/src/cpp/ros2_mangling.cpp index dcd46351..ce4469cc 100644 --- a/cpp_utils/src/cpp/ros2_mangling.cpp +++ b/cpp_utils/src/cpp/ros2_mangling.cpp @@ -31,6 +31,7 @@ const std::vector ros_prefixes_ = {ros_topic_prefix, ros_service_requester_prefix, ros_service_response_prefix}; const char* const ros2_msgs_format = "_msgs/msg/"; +const char* const ros2_srv_format = "/srv/"; std::string remove_prefix( const std::string& name, @@ -318,15 +319,17 @@ std::string demangle_service_type_only( std::string mangle_service_type_only( const std::string& ros2_type_name) { - size_t ns_substring_srv_position = ros2_type_name.find("/srv/"); + size_t ns_substring_srv_position = ros2_type_name.find(ros2_srv_format); if (std::string::npos == ns_substring_srv_position) { return ""; } - std::string dds_type_name = ros2_type_name.substr(0, ns_substring_srv_position + strlen("/srv/")) + "dds_::"; + std::string dds_type_name = + ros2_type_name.substr(0, ns_substring_srv_position + strlen(ros2_srv_format)) + "dds_::"; dds_type_name = dds_type_name + ros2_type_name.substr(ns_substring_srv_position + strlen( - "/srv/"), ros2_type_name.length() - ns_substring_srv_position - strlen("/srv/")); + ros2_srv_format), + ros2_type_name.length() - ns_substring_srv_position - strlen(ros2_srv_format)); size_t ns_substring_rq_position = ros2_type_name.find("rq/"); size_t ns_substring_rr_position = ros2_type_name.find("rr/"); From 0af87a7040c7ffa7bb99fbd4240269a1736ab5ac Mon Sep 17 00:00:00 2001 From: Irene Bandera Date: Fri, 3 Nov 2023 09:15:44 +0100 Subject: [PATCH 7/7] Apply changes Signed-off-by: Irene Bandera --- cpp_utils/include/cpp_utils/ros2_mangling.hpp | 98 +++++++++++++------ .../ros2_mangling/ROS2ManglingTest.cpp | 5 + 2 files changed, 74 insertions(+), 29 deletions(-) diff --git a/cpp_utils/include/cpp_utils/ros2_mangling.hpp b/cpp_utils/include/cpp_utils/ros2_mangling.hpp index 8fbb53fc..a17e5d3d 100644 --- a/cpp_utils/include/cpp_utils/ros2_mangling.hpp +++ b/cpp_utils/include/cpp_utils/ros2_mangling.hpp @@ -23,11 +23,18 @@ namespace eprosima { namespace utils { /** - * @param[in] name string that will be stripped from prefix - * @param[in] prefix prefix to be stripped + * @brief Remove a specified prefix from a string. * - * @return name stripped of prefix, or - * @return "" if name doesn't start with prefix + * This function takes a string and a prefix as input. It checks if the string starts with the specified prefix + * followed by a forward slash ('/'). If the prefix exists at the beginning of the string, it removes the prefix + * and the following slash and returns the modified string. If the prefix is not found at the beginning of the + * string, an empty string is returned. + * + * @param[in] name The input string from which the prefix will be removed. + * @param[in] prefix The prefix to be removed from the input string. + * + * @return The modified string with the specified prefix removed, or an empty string if the prefix is not present + * at the beginning of the input string. */ CPP_UTILS_DllAPI std::string remove_prefix( @@ -35,10 +42,15 @@ std::string remove_prefix( const std::string& prefix); /** - * @param[in] name string to be prefixed with "prefix" - * @param[in] prefix prefix to be added + * @brief Add a specified prefix to a string. + * + * This function takes a string and a prefix as input. It concatenates the prefix with the input string + * and returns the resulting string with the prefix added. * - * @return Returns the name with the prefix added "prefixname" + * @param[in] name The input string to which the prefix will be added. + * @param[in] prefix The prefix to be added to the input string. + * + * @return The modified string with the specified prefix added. */ CPP_UTILS_DllAPI std::string add_prefix( @@ -46,10 +58,15 @@ std::string add_prefix( const std::string& prefix); /** - * @param[in] name string to be suffixed with "suffix" - * @param[in] suffix suffix to be added + * @brief Add a specified suffix to a string. + * + * This function takes a string and a suffix as input. It concatenates the suffix with the input string + * and returns the resulting string with the suffix added. * - * @return Returns the name with the suffix added "namesuffix" + * @param[in] name The input string to which the suffix will be added. + * @param[in] suffix The suffix to be added to the input string. + * + * @return The modified string with the specified suffix added. */ CPP_UTILS_DllAPI std::string add_suffix( @@ -57,70 +74,93 @@ std::string add_suffix( const std::string& suffix); /** - * @param[in] topic_name The name of the topic to be processed. + * @brief Get a ROS prefix if it exists at the beginning of a topic name. + * + * This function takes a topic name as input and checks if it starts with any of the ROS prefixes. + * If a matching ROS prefix is found at the beginning of the topic name, the prefix is returned. + * If no matching prefix is found, an empty string is returned. + * + * @param[in] topic_name The input topic name to be checked for a ROS prefix. * - * @return Returns the ROS specific prefix if present, otherwise "". + * @return The ROS prefix found at the beginning of the topic name, or an empty string if no prefix exists. */ CPP_UTILS_DllAPI std::string get_ros_prefix_if_exists( const std::string& topic_name); /** - * @brief Remove the ROS specific prefix from the \c topic_name if it exists. + * @brief Remove a ROS prefix if it exists at the beginning of a topic name. + * + * This function takes a topic name as input and checks if it starts with any of the ROS prefixes. + * If a matching ROS prefix is found at the beginning of the topic name, the prefix is removed, + * and the modified topic name is returned. If no matching prefix is found, the original topic name is returned unchanged. * * @param[in] topic_name The name of the topic to be processed. * - * @return Returns the topic name stripped of a ROS specific prefix if present. + * @return The topic name with the ROS prefix removed, or the original topic name if no prefix exists. */ CPP_UTILS_DllAPI std::string remove_ros_prefix_if_exists( const std::string& topic_name); /** - * @brief Add the ROS Topic prefix in the \c topic_name. + * @brief Add the ROS topic prefix to a given topic name. * - * @param[in] topic_name The name of the topic to be processed. + * This function takes a topic name as input and adds the ROS topic prefix to it. + * The modified topic name with the prefix added is returned. + * + * @param[in] topic_name The input topic name to which the ROS topic prefix will be added. * - * @return Returns the topic name with the ROS Topic prefix. + * @return The modified topic name with the ROS topic prefix added. */ CPP_UTILS_DllAPI std::string add_ros_topic_prefix( const std::string& topic_name); /** - * @brief Add the ROS Service Requester prefix in the \c topic_name. + * @brief Add the ROS service requester prefix to a given topic name. * - * @param[in] topic_name The name of the topic to be processed. + * This function takes a topic name as input and adds the ROS service requester prefix to it. + * The modified topic name with the prefix added is returned. + * + * @param[in] topic_name The input topic name to which the ROS service requester prefix will be added. * - * @return Returns the topic name with the ROS Requester prefix. + * @return The modified topic name with the ROS service requester prefix added. */ CPP_UTILS_DllAPI std::string add_ros_service_requester_prefix( const std::string& topic_name); /** - * @brief Add the ROS Service Response prefix in the \c topic_name. + * @brief Add the ROS service response prefix to a given topic name. * - * @param[in] topic_name The name of the topic to be processed. + * This function takes a topic name as input and adds the ROS service response prefix to it. + * The modified topic name with the prefix added is returned. + * + * @param[in] topic_name The input topic name to which the ROS service response prefix will be added. * - * @return Returns the topic name with the ROS Response prefix. + * @return The modified topic name with the ROS service response prefix added. */ CPP_UTILS_DllAPI std::string add_ros_service_response_prefix( const std::string& topic_name); /** - * @return Returns \c ros_prefixes_. + * @brief Get a reference to the collection of all ROS prefixes. + * + * This function returns a reference to the collection of ROS prefixes stored in the `ros_prefixes_` variable. + * + * @return A reference to the collection of all ROS prefixes. */ CPP_UTILS_DllAPI const std::vector& get_all_ros_prefixes(); /** - * @brief Obtain the ROS topic associated with the provided \c topic_name, - * excluding the ROS prefix. + * @brief Demangle a ROS topic name by removing the ROS prefix if it exists. * - * If the topic_name begins with a ROS prefix (i.e., starts with ROS prefix + "/"). - * If the input topic name does not contain a ROS prefix + "/", it is returned unchanged. + * This function takes a ROS topic name as input and attempts to demangle it by removing the ROS prefix. + * If the input topic name contains a ROS prefix, it is removed. If there is no ROS prefix, the topic name + * is returned unchanged. * * @param[in] topic_name The name of the topic to be processed. * @@ -205,7 +245,7 @@ CPP_UTILS_DllAPI std::string demangle_ros_service_prefix_from_topic( const std::string& topic_name); /** - * @brief Demangle a ROS service request topic name by removing the requester prefix. + * @brief Demangle a ROS service request topic name by removing the requester prefix and "Request" suffix. * * This function takes a ROS service request topic name as input and removes the specified requester prefix and the common "Request" suffix. * If the input topic name does not contain both the requester prefix diff --git a/cpp_utils/test/unittest/ros2_mangling/ROS2ManglingTest.cpp b/cpp_utils/test/unittest/ros2_mangling/ROS2ManglingTest.cpp index bbf92b32..0bf367e6 100644 --- a/cpp_utils/test/unittest/ros2_mangling/ROS2ManglingTest.cpp +++ b/cpp_utils/test/unittest/ros2_mangling/ROS2ManglingTest.cpp @@ -479,6 +479,8 @@ TEST(ROS2ManglingTest, demangle_service_type_only) * - DDS Service Name: "rt/hello" Return: "" * - DDS Service Name: "rq/srv/hello" Return: "rq::srv::dds_::hello_Request_" * - DDS Service Name: "rr/srv/hello" Return: "rr::srv::dds_::hello_Response_" + * - DDS Service Name: "/srv/hello" Return: "" + * - DDS Service Name: "/srv/hello" Return: "" * - DDS Service Name: "rq::dds_::hello" Return: "" * - DDS Service Name: "rr::dds_::hello" Return: "" * - DDS Service Name: "rt::dds_::hello" Return: "" @@ -491,6 +493,9 @@ TEST(ROS2ManglingTest, mangle_service_type_only) EXPECT_EQ("rq::srv::dds_::hello_Request_", mangle_service_type_only("rq/srv/hello")); EXPECT_EQ("rr::srv::dds_::hello_Response_", mangle_service_type_only("rr/srv/hello")); + EXPECT_EQ("", mangle_service_type_only("/srv/hello")); + EXPECT_EQ("", mangle_service_type_only("/srv/hello")); + EXPECT_EQ("", mangle_service_type_only("rq::dds_::hello")); EXPECT_EQ("", mangle_service_type_only("rr::dds_::hello")); EXPECT_EQ("", mangle_service_type_only("rt::dds_::hello"));