From 81486959b524b466e1204f4d591e2ec8cefe8a37 Mon Sep 17 00:00:00 2001 From: Gonzo <42421541+gonzodepedro@users.noreply.github.com> Date: Mon, 8 Jan 2024 05:03:13 -0300 Subject: [PATCH] Protobuf typeadapter tests (#32) --------- Signed-off-by: Gonzo de Pedro Signed-off-by: Gonzalo de Pedro Co-authored-by: Gabriel <31079482+gdiaz-guevara@users.noreply.github.com> Co-authored-by: gdiaz-guevara Co-authored-by: Tully Foote --- .github/workflows/basic_ci.yaml | 2 +- rosidl_adapter_proto/CMakeLists.txt | 15 + rosidl_adapter_proto/package.xml | 3 + rosidl_adapter_proto/pytest.ini | 2 + rosidl_adapter_proto/test/msg/BoolTest.idl | 7 + .../msg/test_rosidl_adapter__empty_args.json | 3 + .../test/test_adapter_proto_message.py | 172 ++++ .../CMakeLists.txt | 148 ++++ .../typeadapt_message_fixtures.hpp | 740 ++++++++++++++++++ rosidl_typeadapter_protobuf_test/package.xml | 44 ++ .../test/subscribe_array_types.cpp | 92 +++ .../test/subscribe_array_types.hpp | 68 ++ .../test/subscribe_basic_types.cpp | 80 ++ .../test/subscribe_basic_types.hpp | 70 ++ .../test/subscribe_helper.hpp | 88 +++ .../test/subscribe_string_types.cpp | 48 ++ .../test/subscribe_string_types.hpp | 41 + .../test/test_proto_typeadapt.cpp | 182 +++++ rosidl_typesupport_protobuf_c/CMakeLists.txt | 11 + rosidl_typesupport_protobuf_c/package.xml | 2 + .../test/test_wstring_conversion.cpp | 76 ++ .../CMakeLists.txt | 9 + rosidl_typesupport_protobuf_cpp/package.xml | 2 + .../resource/msg__type_support.cpp.em | 2 +- .../test/test_wstring_conversion.cpp | 69 ++ 25 files changed, 1974 insertions(+), 2 deletions(-) create mode 100644 rosidl_adapter_proto/pytest.ini create mode 100644 rosidl_adapter_proto/test/msg/BoolTest.idl create mode 100644 rosidl_adapter_proto/test/msg/test_rosidl_adapter__empty_args.json create mode 100644 rosidl_adapter_proto/test/test_adapter_proto_message.py create mode 100644 rosidl_typeadapter_protobuf_test/CMakeLists.txt create mode 100644 rosidl_typeadapter_protobuf_test/include/rosidl_typeadapter_protobuf_test/typeadapt_message_fixtures.hpp create mode 100644 rosidl_typeadapter_protobuf_test/package.xml create mode 100644 rosidl_typeadapter_protobuf_test/test/subscribe_array_types.cpp create mode 100644 rosidl_typeadapter_protobuf_test/test/subscribe_array_types.hpp create mode 100644 rosidl_typeadapter_protobuf_test/test/subscribe_basic_types.cpp create mode 100644 rosidl_typeadapter_protobuf_test/test/subscribe_basic_types.hpp create mode 100644 rosidl_typeadapter_protobuf_test/test/subscribe_helper.hpp create mode 100644 rosidl_typeadapter_protobuf_test/test/subscribe_string_types.cpp create mode 100644 rosidl_typeadapter_protobuf_test/test/subscribe_string_types.hpp create mode 100644 rosidl_typeadapter_protobuf_test/test/test_proto_typeadapt.cpp create mode 100644 rosidl_typesupport_protobuf_c/test/test_wstring_conversion.cpp create mode 100644 rosidl_typesupport_protobuf_cpp/test/test_wstring_conversion.cpp diff --git a/.github/workflows/basic_ci.yaml b/.github/workflows/basic_ci.yaml index 0295dff..8ffee84 100644 --- a/.github/workflows/basic_ci.yaml +++ b/.github/workflows/basic_ci.yaml @@ -44,6 +44,6 @@ jobs: path: ros_ws/src - uses: ros-tooling/action-ros-ci@v0.3 with: - package-name: rosidl_adapter_proto rosidl_typesupport_protobuf rosidl_typesupport_protobuf_cpp rosidl_typesupport_protobuf_c + package-name: rosidl_adapter_proto rosidl_typesupport_protobuf rosidl_typesupport_protobuf_cpp rosidl_typesupport_protobuf_c rosidl_typeadapter_protobuf_test target-ros2-distro: ${{ matrix.ros_distribution }} vcs-repo-file-url: https://raw.githubusercontent.com/ros2/ros2/${{ matrix.ros_distribution }}/ros2.repos diff --git a/rosidl_adapter_proto/CMakeLists.txt b/rosidl_adapter_proto/CMakeLists.txt index 8c50488..97868ca 100644 --- a/rosidl_adapter_proto/CMakeLists.txt +++ b/rosidl_adapter_proto/CMakeLists.txt @@ -22,6 +22,21 @@ project(rosidl_adapter_proto) find_package(ament_cmake REQUIRED) find_package(ament_cmake_python REQUIRED) +if(BUILD_TESTING) + find_package(ament_cmake_pytest REQUIRED) + find_package(rosidl_cmake REQUIRED) + ament_add_pytest_test(pytest test) + set(generator_arguments_file "${CMAKE_CURRENT_SOURCE_DIR}/test/msg/test_rosid_adapter_proto__arguments.json") + rosidl_write_generator_arguments( + "${generator_arguments_file}" + PACKAGE_NAME "${PROJECT_NAME}" + IDL_TUPLES "${CMAKE_CURRENT_SOURCE_DIR}/test:msg/BoolTest.idl" + OUTPUT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/test" + TEMPLATE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/resource" + TARGET_DEPENDENCIES "${CMAKE_CURRENT_SOURCE_DIR}/test/msg/BoolTest.idl" + ADDITIONAL_FILES "") +endif() + ament_python_install_package(${PROJECT_NAME}) ament_package(CONFIG_EXTRAS "cmake/rosidl_adapter_proto-extras.cmake.in") diff --git a/rosidl_adapter_proto/package.xml b/rosidl_adapter_proto/package.xml index ad4aac0..6a01ce4 100644 --- a/rosidl_adapter_proto/package.xml +++ b/rosidl_adapter_proto/package.xml @@ -13,6 +13,9 @@ rosidl_cli rosidl_parser + ament_cmake_pytest + rosidl_cmake + rosidl_interface_packages diff --git a/rosidl_adapter_proto/pytest.ini b/rosidl_adapter_proto/pytest.ini new file mode 100644 index 0000000..fe55d2e --- /dev/null +++ b/rosidl_adapter_proto/pytest.ini @@ -0,0 +1,2 @@ +[pytest] +junit_family=xunit2 diff --git a/rosidl_adapter_proto/test/msg/BoolTest.idl b/rosidl_adapter_proto/test/msg/BoolTest.idl new file mode 100644 index 0000000..a316f5c --- /dev/null +++ b/rosidl_adapter_proto/test/msg/BoolTest.idl @@ -0,0 +1,7 @@ +module rosidl_adapter_proto { + @verbatim (language="comment", text= + "This is for test purposes.") + struct Bool { + boolean data; + }; +}; diff --git a/rosidl_adapter_proto/test/msg/test_rosidl_adapter__empty_args.json b/rosidl_adapter_proto/test/msg/test_rosidl_adapter__empty_args.json new file mode 100644 index 0000000..544b7b4 --- /dev/null +++ b/rosidl_adapter_proto/test/msg/test_rosidl_adapter__empty_args.json @@ -0,0 +1,3 @@ +{ + +} \ No newline at end of file diff --git a/rosidl_adapter_proto/test/test_adapter_proto_message.py b/rosidl_adapter_proto/test/test_adapter_proto_message.py new file mode 100644 index 0000000..dca1c54 --- /dev/null +++ b/rosidl_adapter_proto/test/test_adapter_proto_message.py @@ -0,0 +1,172 @@ +# ================================= Apache 2.0 ================================= +# +# Copyright (C) 2021 Continental +# +# 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. +# +# ================================= Apache 2.0 ================================= + +import pathlib + +import pytest + +from rosidl_adapter_proto import collect_proto_imports +from rosidl_adapter_proto import compute_proto_field_number +from rosidl_adapter_proto import generate_proto +from rosidl_adapter_proto import MSG_TYPE_TO_PROTO +from rosidl_adapter_proto import to_proto_import +from rosidl_parser.definition import IdlLocator +from rosidl_parser.definition import Message +from rosidl_parser.parser import parse_idl_file + + +MESSAGE_IDL_LOCATOR = IdlLocator(pathlib.Path(__file__).parent, + pathlib.Path('msg') / 'BoolTest.idl') + + +@pytest.fixture(scope='module') +def message_idl_file(): + return parse_idl_file(MESSAGE_IDL_LOCATOR) + + +def search_word(file_path, word): + with open(file_path, 'r') as file: + content = file.read() + if word in content: + return True + return False + + +def get_member_name(message_idl_file): + messages = message_idl_file.content.get_elements_of_type(Message) + member = messages[0].structure.members[0] + return member.name + + +def test_message_proto_generated_invalid_argument(): + with pytest.raises(Exception): + generate_file_argument = IdlLocator( + pathlib.Path(__file__).parent, + pathlib.Path('msg') / 'empty_document.json') + rc = generate_proto(generate_file_argument.get_absolute_path()) + + assert rc is None + + +def test_message_proto_generated_empty_file(): + with pytest.raises(Exception): + generate_file_argument = IdlLocator( + pathlib.Path(__file__).parent, + pathlib.Path('msg') / 'test_rosidl_adapter__empty_args.json') + rc = generate_proto(generate_file_argument.get_absolute_path()) + + assert rc is None + + +def test_message_proto_generated(message_idl_file): + generate_file_argument = IdlLocator( + pathlib.Path(__file__).parent, + pathlib.Path('msg') / 'test_rosid_adapter_proto__arguments.json') + rc = generate_proto(generate_file_argument.get_absolute_path()) + + assert rc is not None + + messages = message_idl_file.content.get_elements_of_type(Message) + member = messages[0].structure.members[0] + field_number = compute_proto_field_number(member.name) + proto_type = MSG_TYPE_TO_PROTO[member.type.typename] + + proto_file_name = IdlLocator( + pathlib.Path(__file__).parent, + pathlib.Path('msg') / 'BoolTest.proto') + + assert search_word(proto_file_name.get_absolute_path(), member.name) is True + assert search_word(proto_file_name.get_absolute_path(), str(field_number)) is True + assert search_word(proto_file_name.get_absolute_path(), proto_type) is True + + +def test_compute_proto_field_number_is_greter_than_0(message_idl_file): + member_name = get_member_name(message_idl_file) + field_number = compute_proto_field_number(member_name) + + assert field_number > 0 + + +def test_compute_proto_field_number_is_not_in_the_reserved_range(message_idl_file): + member_name = get_member_name(message_idl_file) + field_number = compute_proto_field_number(member_name) + + assert field_number not in range(19000, 19999) + + +def test_compute_proto_field_number_repeated_with_same_member_name(message_idl_file): + member_name = get_member_name(message_idl_file) + field_number = compute_proto_field_number(member_name) + second_field_number = compute_proto_field_number('data') + + assert field_number == second_field_number + + +def test_msg_type_to_proto_from_message_file(message_idl_file): + messages = message_idl_file.content.get_elements_of_type(Message) + member = messages[0].structure.members[0] + proto_type = MSG_TYPE_TO_PROTO[member.type.typename] + assert proto_type == 'bool' + + +def test_msg_type_to_proto_mapping(): + idl_messages = ['boolean', 'octet', 'char', 'wchar', 'float', + 'double', 'long double', 'uint8', 'int8', + 'uint16', 'int16', 'uint32', 'int32', 'uint64', + 'int64', 'string', 'wstring'] + expected_proto_type_ = ['bool', 'uint32', 'uint32', 'uint32', + 'float', 'double', 'double', 'uint32', + 'int32', 'uint32', 'int32', 'fixed32', + 'sfixed32', 'fixed64', 'sfixed64', + 'string', 'bytes'] + index = 0 + for idl_message in idl_messages: + proto_type = MSG_TYPE_TO_PROTO[idl_message] + assert expected_proto_type_[index] == proto_type + index += 1 + + +def test_msg_type_to_proto_invalid(): + with pytest.raises(Exception): + MSG_TYPE_TO_PROTO['integer'] + + +def test_to_proto_import(message_idl_file): + messages = message_idl_file.content.get_elements_of_type(Message) + namespace_type = messages[0].structure.namespaced_type + proto_import = to_proto_import(namespace_type) + assert proto_import == 'rosidl_adapter_proto/Bool.proto' + + +def test_to_proto_import_invalid_argument(): + with pytest.raises(Exception): + to_proto_import('invalid argument') + + +def test_collect_proto_import(message_idl_file): + messages = message_idl_file.content.get_elements_of_type(Message) + proto_import_set = set() + for message in messages: + proto_import_set.update(collect_proto_imports(message)) + for proto_file in proto_import_set: + assert proto_file == 'rosidl_adapter_proto/Bool.proto' + + +def test_collect_proto_import_invalid_argument(): + with pytest.raises(Exception): + collect_proto_imports('string value') diff --git a/rosidl_typeadapter_protobuf_test/CMakeLists.txt b/rosidl_typeadapter_protobuf_test/CMakeLists.txt new file mode 100644 index 0000000..c1a5283 --- /dev/null +++ b/rosidl_typeadapter_protobuf_test/CMakeLists.txt @@ -0,0 +1,148 @@ +cmake_minimum_required(VERSION 3.5) + +project(rosidl_typeadapter_protobuf_test) + +# Default to C++17 +if(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 17) + set(CMAKE_CXX_STANDARD_REQUIRED ON) +endif() +if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options(-Wall -Wextra -Wpedantic) +endif() +if(CMAKE_BUILD_TYPE STREQUAL "Debug" AND MSVC) + # /bigobj is needed to avoid error C1128: + # https://msdn.microsoft.com/en-us/library/8578y171.aspx + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj") +endif() + +option(SKIP_SINGLE_RMW_TESTS + "Skip tests involving only a single RMW implementation" OFF) +option(SKIP_MULTI_RMW_TESTS + "Skip tests involving only multiple RMW implementations" OFF) + +find_package(ament_cmake_auto REQUIRED) +ament_auto_find_build_dependencies() + +if(BUILD_TESTING) + find_package(ament_cmake REQUIRED) + find_package(osrf_testing_tools_cpp REQUIRED) + find_package(rcpputils REQUIRED) + find_package(rcl REQUIRED) + find_package(rclcpp REQUIRED) + find_package(test_msgs REQUIRED) + find_package(rosidl_typesupport_protobuf_cpp REQUIRED) + + + include_directories(include) + + ament_index_get_resource(interface_files "rosidl_interfaces" "test_msgs") + string(REPLACE "\n" ";" interface_files "${interface_files}") + + + set(message_files "") + set(service_files "") + set(action_files "") + foreach(interface_file ${interface_files}) + get_filename_component(interface_ns "${interface_file}" DIRECTORY) + get_filename_component(interface_ns "${interface_ns}" NAME) + string_ends_with("${interface_file}" ".msg" is_message) + if(is_message AND interface_ns STREQUAL "msg") + list(APPEND message_files "${interface_file}") + continue() + endif() + string_ends_with("${interface_file}" ".srv" is_service) + if(is_service AND interface_ns STREQUAL "srv") + list(APPEND service_files "${interface_file}") + continue() + endif() + string_ends_with("${interface_file}" ".idl" is_action) + if(is_action AND interface_ns STREQUAL "action") + list(APPEND action_files "${interface_file}") + continue() + endif() + endforeach() + + find_package(ament_lint_auto REQUIRED) + ament_lint_auto_find_test_dependencies() + + # # Provides PYTHON_EXECUTABLE_DEBUG + # find_package(python_cmake_module REQUIRED) + # find_package(PythonExtra REQUIRED) + + # get the rmw implementations ahead of time + find_package(rmw_implementation_cmake REQUIRED) + get_available_rmw_implementations(rmw_implementations2) + foreach(rmw_implementation ${rmw_implementations2}) + find_package("${rmw_implementation}" REQUIRED) + endforeach() + + function(custom_test target with_message_argument) + if(with_message_argument) + # adding test for each message type + foreach(message_file ${message_files}) + get_filename_component(TEST_MESSAGE_TYPE "${message_file}" NAME_WE) + ament_add_test( + "${target}${target_suffix}__${TEST_MESSAGE_TYPE}" + COMMAND "$" "${TEST_MESSAGE_TYPE}" + TIMEOUT 15 + GENERATE_RESULT_FOR_RETURN_CODE_ZERO + APPEND_LIBRARY_DIRS "${append_library_dirs}") + set_tests_properties( + "${target}${target_suffix}__${TEST_MESSAGE_TYPE}" + PROPERTIES REQUIRED_FILES "$" + ) + endforeach() + else() + ament_add_test( + "${target}${target_suffix}" + COMMAND "$" + TIMEOUT 15 + GENERATE_RESULT_FOR_RETURN_CODE_ZERO + APPEND_LIBRARY_DIRS "${append_library_dirs}") + set_tests_properties( + "${target}${target_suffix}" + PROPERTIES REQUIRED_FILES "$" + ) + endif() + endfunction() + + function(custom_executable target) + add_executable(${target} ${ARGN}) + ament_target_dependencies(${target} + "rclcpp" + "rclcpp_action" + "test_msgs" + ) + endfunction() + + add_library(subscribe_types STATIC + "test/subscribe_array_types.cpp" + "test/subscribe_basic_types.cpp" + "test/subscribe_string_types.cpp") + ament_target_dependencies(subscribe_types + "rclcpp" + "test_msgs") + + # publisher combined with a subscriber + custom_executable(test_proto_typeadapt_cpp + "test/test_proto_typeadapt.cpp") + target_link_libraries(test_proto_typeadapt_cpp subscribe_types rcpputils::rcpputils) + + + set(append_library_dirs "${CMAKE_CURRENT_BINARY_DIR}") + if(WIN32) + set(append_library_dirs "${append_library_dirs}/$") + endif() + + # finding gtest once in the highest scope + # prevents finding it repeatedly in each local scope + ament_find_gtest() + + custom_test(test_proto_typeadapt_cpp TRUE) + +endif() # BUILD_TESTING + + + +ament_auto_package() \ No newline at end of file diff --git a/rosidl_typeadapter_protobuf_test/include/rosidl_typeadapter_protobuf_test/typeadapt_message_fixtures.hpp b/rosidl_typeadapter_protobuf_test/include/rosidl_typeadapter_protobuf_test/typeadapt_message_fixtures.hpp new file mode 100644 index 0000000..70ff242 --- /dev/null +++ b/rosidl_typeadapter_protobuf_test/include/rosidl_typeadapter_protobuf_test/typeadapt_message_fixtures.hpp @@ -0,0 +1,740 @@ +// Copyright 2015 Open Source Robotics Foundation, Inc. +// +// 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. + +#ifndef ROSIDL_TYPEADAPTER_PROTOBUF_TEST__TYPEADAPT_MESSAGE_FIXTURES_HPP_ +#define ROSIDL_TYPEADAPTER_PROTOBUF_TEST__TYPEADAPT_MESSAGE_FIXTURES_HPP_ + +#include +#include +#include +#include +#include +#include + +#include "test_msgs/rosidl_adapter_proto__visibility_control.h" +#include "builtin_interfaces/rosidl_adapter_proto__visibility_control.h" +#include "test_msgs/msg/arrays__typeadapter_protobuf_cpp.hpp" +#include "test_msgs/msg/basic_types__typeadapter_protobuf_cpp.hpp" +#include "test_msgs/msg/bounded_plain_sequences__typeadapter_protobuf_cpp.hpp" +#include "test_msgs/msg/bounded_sequences__typeadapter_protobuf_cpp.hpp" +#include "test_msgs/msg/builtins__typeadapter_protobuf_cpp.hpp" +#include "test_msgs/msg/constants__typeadapter_protobuf_cpp.hpp" +#include "test_msgs/msg/defaults__typeadapter_protobuf_cpp.hpp" +#include "test_msgs/msg/empty__typeadapter_protobuf_cpp.hpp" +#include "test_msgs/msg/multi_nested__typeadapter_protobuf_cpp.hpp" +#include "test_msgs/msg/nested__typeadapter_protobuf_cpp.hpp" +#include "test_msgs/msg/strings__typeadapter_protobuf_cpp.hpp" +#include "test_msgs/msg/unbounded_sequences__typeadapter_protobuf_cpp.hpp" +#include "test_msgs/msg/w_strings__typeadapter_protobuf_cpp.hpp" +#include "rosidl_typesupport_protobuf_cpp/wstring_conversion.hpp" + +namespace rosidl_typeadapter_protobuf_test +{ + +static inline std::string +from_u8string(const std::string & s) +{ + return s; +} + +static inline std::string +from_u8string(std::string && s) +{ + return std::move(s); +} + +#if defined(__cpp_lib_char8_t) +static inline std::string +from_u8string(const std::u8string & s) +{ + return std::string(s.begin(), s.end()); +} +#endif + +} // namespace rosidl_typeadapter_protobuf_test + +typedef std::shared_ptr EmptySharedPtr; +typedef std::shared_ptr BasicTypesSharedPtr; +typedef std::shared_ptr ConstantsSharedPtr; +typedef std::shared_ptr DefaultsSharedPtr; +typedef std::shared_ptr StringsSharedPtr; +typedef std::shared_ptr ArraysSharedPtr; +typedef std::shared_ptr UnboundedSequencesSharedPtr; +typedef std::shared_ptr BoundedPlainSequencesSharedPtr; +typedef std::shared_ptr BoundedSequencesSharedPtr; +typedef std::shared_ptr MultiNestedSharedPtr; +typedef std::shared_ptr NestedSharedPtr; +typedef std::shared_ptr BuiltinsSharedPtr; +typedef std::shared_ptr WStringsSharedPtr; + +static inline std::vector +get_proto_messages_empty() +{ + std::vector messages; + auto msg = std::make_shared(); + messages.push_back(msg); + return messages; +} + +static inline std::vector +get_proto_messages_basic_types() +{ + std::vector messages; + // { + // auto msg = std::make_shared(); + // msg->set_bool_value(false); + // msg->set_byte_value(0); + // msg->set_char_value(0); + // msg->set_float32_value(0.0f); + // msg->set_float64_value(0); + // msg->set_int8_value(0); + // msg->set_uint8_value(0); + // msg->set_int16_value(0); + // msg->set_uint16_value(0); + // msg->set_int32_value(0); + // msg->set_uint32_value(0); + // msg->set_int64_value(0); + // msg->set_uint64_value(0); + // messages.push_back(msg); + // } + { + auto msg = std::make_shared(); + msg->set_bool_value(true); + msg->set_byte_value(255); + msg->set_char_value(255); + msg->set_float32_value(1.125f); + msg->set_float64_value(1.125); + msg->set_int8_value(std::numeric_limits::max()); + msg->set_uint8_value(std::numeric_limits::max()); + msg->set_int16_value(std::numeric_limits::max()); + msg->set_uint16_value(std::numeric_limits::max()); + msg->set_int32_value(std::numeric_limits::max()); + msg->set_uint32_value(std::numeric_limits::max()); + msg->set_int64_value(std::numeric_limits::max()); + msg->set_uint64_value(std::numeric_limits::max()); + messages.push_back(msg); + } + { + auto msg = std::make_shared(); + msg->set_bool_value(false); + msg->set_byte_value(0); + msg->set_char_value(0); + msg->set_float32_value(-2.125f); + msg->set_float64_value(-2.125); + msg->set_int8_value(std::numeric_limits::min()); + msg->set_uint8_value(0); + msg->set_int16_value(std::numeric_limits::min()); + msg->set_uint16_value(0); + msg->set_int32_value(std::numeric_limits::min()); + msg->set_uint32_value(0); + msg->set_int64_value(std::numeric_limits::min()); + msg->set_uint64_value(0); + messages.push_back(msg); + } + { + auto msg = std::make_shared(); + msg->set_bool_value(true); + msg->set_byte_value(1); + msg->set_char_value(1); + msg->set_float32_value(1.0f); + msg->set_float64_value(1); + msg->set_int8_value(1); + msg->set_uint8_value(1); + msg->set_int16_value(1); + msg->set_uint16_value(1); + msg->set_int32_value(1); + msg->set_uint32_value(1); + msg->set_int64_value(1); + msg->set_uint64_value(1); + messages.push_back(msg); + } + return messages; +} + +static inline std::vector +get_proto_messages_constants() +{ + std::vector messages; + { + auto msg = std::make_shared(); + messages.push_back(msg); + } + return messages; +} + +static inline std::vector +get_proto_messages_defaults() +{ + std::vector messages; + { + auto msg = std::make_shared(); + messages.push_back(msg); + } + return messages; +} + +static inline std::vector +get_proto_messages_strings() +{ + std::vector messages; + { + auto msg = std::make_shared(); + msg->set_string_value(""); + msg->set_bounded_string_value(""); + messages.push_back(msg); + } + { + auto msg = std::make_shared(); + msg->set_string_value("Hello world!"); + msg->set_bounded_string_value("Hello world!"); + messages.push_back(msg); + } + { + auto msg = std::make_shared(); + msg->set_string_value( + rosidl_typeadapter_protobuf_test::from_u8string(u8"Hell\u00F6 W\u00F6rld!")); // using umlaut + msg->set_bounded_string_value( + rosidl_typeadapter_protobuf_test::from_u8string(u8"Hell\u00F6 W\u00F6rld!")); // using umlaut + messages.push_back(msg); + } + { + auto msg = std::make_shared(); + msg->set_string_value(""); + msg->set_bounded_string_value(""); + for (size_t i = 0; i < 20000; ++i) { + msg->set_string_value(msg->string_value() + std::to_string(i % 10)); + } + for (size_t i = 0; i < 22; ++i) { + msg->set_bounded_string_value(msg->bounded_string_value() + std::to_string(i % 10)); + } + messages.push_back(msg); + } + return messages; +} + +static inline std::vector +get_proto_messages_arrays() +{ + auto basic_types_msgs = get_proto_messages_basic_types(); + std::vector messages; + { + auto msg = std::make_shared(); + + msg->add_bool_values(false); + msg->add_bool_values(true); + msg->add_bool_values(false); + + std::string values("000"); + values[0] = 0; + values[1] = 255; + values[2] = 0; + msg->set_byte_values(values); + + values[0] = 0; + values[1] = 255; + values[2] = 0; + msg->set_char_values(values); + + msg->add_float32_values(0.0f); + msg->add_float32_values(1.125f); + msg->add_float32_values(-2.125f); + + msg->add_float64_values(0); + msg->add_float64_values(1.125); + msg->add_float64_values(-2.125); + + values[0] = 0; + values[1] = std::numeric_limits::max(); + values[2] = std::numeric_limits::min(); + msg->set_int8_values(values); + + values[0] = 0; + values[1] = std::numeric_limits::max(); + values[2] = 0; + msg->set_uint8_values(values); + + msg->add_int16_values(0); + msg->add_int16_values(std::numeric_limits::max()); + msg->add_int16_values(std::numeric_limits::min()); + + msg->add_uint16_values(0); + msg->add_uint16_values(std::numeric_limits::max()); + msg->add_uint16_values(0); + + msg->add_int32_values(static_cast(0)); + msg->add_int32_values(std::numeric_limits::max()); + msg->add_int32_values(std::numeric_limits::min()); + + msg->add_uint32_values(0); + msg->add_uint32_values(std::numeric_limits::max()); + msg->add_uint32_values(0); + + msg->add_int64_values(0); + msg->add_int64_values(std::numeric_limits::max()); + msg->add_int64_values(std::numeric_limits::min()); + + msg->add_uint64_values(0); + msg->add_uint64_values(std::numeric_limits::max()); + msg->add_uint64_values(0); + + msg->add_string_values(""); + msg->add_string_values("max value"); + msg->add_string_values("min value"); + + msg->add_basic_types_values()->CopyFrom(*basic_types_msgs[0]); + msg->add_basic_types_values()->CopyFrom(*basic_types_msgs[1]); + msg->add_basic_types_values()->CopyFrom(*basic_types_msgs[2]); + + messages.push_back(msg); + } + return messages; +} + +static inline std::vector +get_proto_messages_unbounded_sequences() +{ + auto basic_types_msgs = get_proto_messages_basic_types(); + std::vector messages; + { + auto msg = std::make_shared(); + msg->add_bool_values(true); + msg->set_byte_values(std::string(1, 0xff)); + msg->set_char_values(std::string(1, 255)); + msg->add_float32_values(1.125f); + msg->add_float64_values(1.125); + msg->set_int8_values(std::string(1, std::numeric_limits::max())); + msg->set_uint8_values(std::string(1, std::numeric_limits::max())); + msg->add_int16_values(std::numeric_limits::max()); + msg->add_uint16_values(std::numeric_limits::max()); + msg->add_int32_values(std::numeric_limits::max()); + msg->add_uint32_values(std::numeric_limits::max()); + msg->add_int64_values(std::numeric_limits::max()); + msg->add_uint64_values(std::numeric_limits::max()); + msg->add_string_values("max value"); + msg->add_basic_types_values()->CopyFrom(*basic_types_msgs[0]); + msg->set_alignment_check(1); + messages.push_back(msg); + } + { + auto msg = std::make_shared(); + msg->add_bool_values(false); + msg->add_bool_values(true); + + std::string values; + values[0] = 0; + values[1] = 0xff; + msg->set_byte_values(values); + + values[0] = 0; + values[1] = 255; + msg->set_char_values(values); + + msg->add_float32_values(0.0f); + msg->add_float32_values(1.125f); + msg->add_float32_values(-2.125f); + + msg->add_float64_values(0); + msg->add_float64_values(1.125); + msg->add_float64_values(-2.125); + + values[0] = 0; + values[1] = std::numeric_limits::max(); + values[2] = std::numeric_limits::min(); + msg->set_int8_values(values); + + values[0] = 0; + values[1] = std::numeric_limits::max(); + msg->set_uint8_values(values); + + msg->add_int16_values(0); + msg->add_int16_values(std::numeric_limits::max()); + msg->add_int16_values(std::numeric_limits::min()); + + msg->add_uint16_values(0); + msg->add_uint16_values(std::numeric_limits::max()); + + // The narrowing static cast is required to avoid build errors on Windows. + msg->add_int32_values(static_cast(0)); + msg->add_int32_values(std::numeric_limits::max()); + msg->add_int32_values(std::numeric_limits::min()); + + msg->add_uint32_values(0); + msg->add_uint32_values(std::numeric_limits::max()); + + msg->add_int64_values(0); + msg->add_int64_values(std::numeric_limits::max()); + msg->add_int64_values(std::numeric_limits::min()); + + msg->add_uint64_values(0); + msg->add_uint64_values(std::numeric_limits::max()); + + msg->add_string_values(""); + msg->add_string_values("max value"); + msg->add_string_values("optional min value"); + + msg->add_basic_types_values()->CopyFrom(*basic_types_msgs[0]); + msg->add_basic_types_values()->CopyFrom(*basic_types_msgs[1]); + msg->add_basic_types_values()->CopyFrom(*basic_types_msgs[2]); + msg->set_alignment_check(2); + messages.push_back(msg); + } + // { + // auto msg = std::make_shared(); + // // check sequences with more then 100 elements + // const size_t size = 1000; + // msg->set_bool_values.resize(size); + // msg->set_byte_values.resize(size); + // msg->set_char_values.resize(size); + // msg->set_float32_values.resize(size); + // msg->add_float64_values.resize(size); + // msg->set_int8_values.resize(size); + // msg->set_uint8_values.resize(size); + // msg->set_int16_values.resize(size); + // msg->set_uint16_values.resize(size); + // msg->set_int32_values.resize(size); + // msg->set_uint32_values.resize(size); + // msg->set_int64_values.resize(size); + // msg->set_uint64_values.resize(size); + // msg->set_string_values.resize(size); + // msg->set_basic_types_values.resize(size); + // for (size_t i = 0; i < size; ++i) { + // msg->set_bool_values[i] = (i % 2 != 0) ? true : false; + // msg->set_byte_values[i] = static_cast(i); + // msg->set_char_values[i] = static_cast(i % (1 << 8)); + // msg->set_float32_values[i] = 1.125f * i; + // msg->add_float64_values[i] = 1.125 * i; + // msg->set_int8_values[i] = static_cast(i); + // msg->set_uint8_values[i] = static_cast(i); + // msg->set_int16_values[i] = static_cast(i); + // msg->set_uint16_values[i] = static_cast(i); + // msg->set_int32_values[i] = static_cast(i); + // msg->set_uint32_values[i] = static_cast(i); + // msg->set_int64_values[i] = i; + // msg->set_uint64_values[i] = i; + // msg->set_string_values[i] = std::to_string(i); + // msg->set_basic_types_values[i] = *basic_types_msgs[i % basic_types_msgs.size()]; + // } + // msg->set_alignment_check = 3; + // messages.push_back(msg); + // } + { + auto msg = std::make_shared(); + // check default sequences + msg->set_alignment_check(4); + messages.push_back(msg); + } + return messages; +} + +static inline std::vector +get_proto_messages_bounded_plain_sequences() +{ + auto basic_types_msgs = get_proto_messages_basic_types(); + auto msg = std::make_shared(); + std::vector messages; + { + auto msg = std::make_shared(); + msg->add_bool_values(false); + msg->add_bool_values(true); + msg->add_bool_values(false); + + std::string values; + values[0] = 0; + values[1] = 1; + values[2] = 0xff; + msg->set_byte_values(values); + + values[0] = 0; + values[1] = 1; + values[2] = 255; + msg->set_char_values(values); + + msg->add_float32_values(0.0f); + msg->add_float32_values(1.125f); + msg->add_float32_values(-2.125f); + + msg->add_float64_values(0); + msg->add_float64_values(1.125); + msg->add_float64_values(-2.125); + + values[0] = 0; + values[1] = std::numeric_limits::max(); + values[2] = std::numeric_limits::min(); + msg->set_int8_values(values); + + values[0] = 0; + values[1] = 1; + values[2] = std::numeric_limits::min(); + msg->set_uint8_values(values); + + msg->add_int16_values(0); + msg->add_int16_values(std::numeric_limits::max()); + msg->add_int16_values(std::numeric_limits::min()); + + msg->add_uint16_values(0); + msg->add_uint16_values(1); + msg->add_uint16_values(std::numeric_limits::max()); + + // The narrowing static cast is required to avoid build errors on Windows. + msg->add_int32_values(static_cast(0)); + msg->add_int32_values(std::numeric_limits::max()); + msg->add_int32_values(std::numeric_limits::min()); + + msg->add_uint32_values(0); + msg->add_uint32_values(1); + msg->add_uint32_values(std::numeric_limits::max()); + + msg->add_int64_values(0); + msg->add_int64_values(std::numeric_limits::max()); + msg->add_int64_values(std::numeric_limits::min()); + + msg->add_uint64_values(0); + msg->add_uint64_values(1); + msg->add_uint64_values(std::numeric_limits::max()); + + msg->add_basic_types_values()->CopyFrom(*basic_types_msgs[0]); + msg->add_basic_types_values()->CopyFrom(*basic_types_msgs[1]); + msg->add_basic_types_values()->CopyFrom(*basic_types_msgs[2]); + msg->set_alignment_check(2); + messages.push_back(msg); + } + { + auto msg = std::make_shared(); + // check default sequences + msg->set_alignment_check(4); + messages.push_back(msg); + } + return messages; +} + +static inline std::vector +get_proto_messages_bounded_sequences() +{ + auto basic_types_msgs = get_proto_messages_basic_types(); + auto msg = std::make_shared(); + std::vector messages; + { + auto msg = std::make_shared(); + msg->add_bool_values(false); + msg->add_bool_values(true); + msg->add_bool_values(false); + + std::string values; + values[0] = 0; + values[1] = 1; + values[2] = 0xff; + msg->set_byte_values(values); + + values[0] = 0; + values[1] = 1; + values[2] = 255; + msg->set_char_values(values); + + msg->add_float32_values(0.0f); + msg->add_float32_values(1.125f); + msg->add_float32_values(-2.125f); + + msg->add_float64_values(0); + msg->add_float64_values(1.125); + msg->add_float64_values(-2.125); + + values[0] = 0; + values[1] = std::numeric_limits::max(); + values[2] = std::numeric_limits::min(); + msg->set_int8_values(values); + + values[0] = 0; + values[1] = 1; + values[2] = std::numeric_limits::min(); + msg->set_uint8_values(values); + + msg->add_int16_values(0); + msg->add_int16_values(std::numeric_limits::max()); + msg->add_int16_values(std::numeric_limits::min()); + + msg->add_uint16_values(0); + msg->add_uint16_values(1); + msg->add_uint16_values(std::numeric_limits::max()); + + // The narrowing static cast is required to avoid build errors on Windows. + msg->add_int32_values(static_cast(0)); + msg->add_int32_values(std::numeric_limits::max()); + msg->add_int32_values(std::numeric_limits::min()); + + msg->add_uint32_values(0); + msg->add_uint32_values(1); + msg->add_uint32_values(std::numeric_limits::max()); + + msg->add_int64_values(0); + msg->add_int64_values(std::numeric_limits::max()); + msg->add_int64_values(std::numeric_limits::min()); + + msg->add_uint64_values(0); + msg->add_uint64_values(1); + msg->add_uint64_values(std::numeric_limits::max()); + + msg->add_basic_types_values()->CopyFrom(*basic_types_msgs[0]); + msg->add_basic_types_values()->CopyFrom(*basic_types_msgs[1]); + msg->add_basic_types_values()->CopyFrom(*basic_types_msgs[2]); + msg->set_alignment_check(2); + messages.push_back(msg); + } + { + auto msg = std::make_shared(); + // check default sequences + msg->set_alignment_check(4); + messages.push_back(msg); + } + return messages; +} + +static inline std::vector +get_proto_messages_multi_nested() +{ + auto arrays_msgs = get_proto_messages_arrays(); + auto bounded_sequences_msgs = get_proto_messages_bounded_sequences(); + auto unbounded_sequences_msgs = get_proto_messages_unbounded_sequences(); + const std::size_t num_arrays = arrays_msgs.size(); + const std::size_t num_bounded_sequences = bounded_sequences_msgs.size(); + const std::size_t num_unbounded_sequences = unbounded_sequences_msgs.size(); + std::vector messages; + { + auto msg = std::make_shared(); + for (std::size_t i = 0u; i < msg->array_of_arrays_size(); ++i) { + msg->mutable_array_of_arrays(i)->CopyFrom(*arrays_msgs[i % num_arrays]); + } + for (std::size_t i = 0u; i < msg->array_of_bounded_sequences_size(); ++i) { + msg->mutable_array_of_bounded_sequences(i)->CopyFrom( + *bounded_sequences_msgs[i % num_bounded_sequences]); + } + for (std::size_t i = 0u; i < msg->array_of_unbounded_sequences_size(); ++i) { + msg->mutable_array_of_unbounded_sequences(i)->CopyFrom( + *unbounded_sequences_msgs[i % num_unbounded_sequences]); + } + const std::size_t sequence_size = 3u; + for (std::size_t i = 0u; i < sequence_size; ++i) { + msg->add_bounded_sequence_of_arrays()->CopyFrom(*arrays_msgs[i % num_arrays]); + } + for (std::size_t i = 0u; i < sequence_size; ++i) { + msg->add_bounded_sequence_of_bounded_sequences()->CopyFrom( + *bounded_sequences_msgs[i % num_bounded_sequences]); + } + for (std::size_t i = 0u; i < sequence_size; ++i) { + msg->add_bounded_sequence_of_unbounded_sequences()->CopyFrom( + *unbounded_sequences_msgs[i % num_unbounded_sequences]); + } + for (std::size_t i = 0u; i < sequence_size; ++i) { + msg->add_unbounded_sequence_of_arrays()->CopyFrom(*arrays_msgs[i % num_arrays]); + } + for (std::size_t i = 0u; i < sequence_size; ++i) { + msg->add_unbounded_sequence_of_bounded_sequences()->CopyFrom( + *bounded_sequences_msgs[i % num_bounded_sequences]); + } + for (std::size_t i = 0u; i < sequence_size; ++i) { + msg->add_unbounded_sequence_of_unbounded_sequences()->CopyFrom( + *unbounded_sequences_msgs[i % num_unbounded_sequences]); + } + messages.push_back(msg); + } + return messages; +} + +static inline std::vector +get_proto_messages_nested() +{ + std::vector messages; + auto basic_types_msgs = get_proto_messages_basic_types(); + for (auto basic_types_msg : basic_types_msgs) { + auto msg = std::make_shared(); + msg->mutable_basic_types_value()->CopyFrom(*basic_types_msg); + messages.push_back(msg); + } + return messages; +} + +static inline std::vector +get_proto_messages_builtins() +{ + std::vector messages; + { + auto msg = std::make_shared(); + msg->mutable_duration_value()->set_sec(-1234567890); + msg->mutable_duration_value()->set_nanosec(123456789); + msg->mutable_time_value()->set_sec(-1234567890); + msg->mutable_time_value()->set_nanosec(987654321); + messages.push_back(msg); + } + return messages; +} + +static inline std::vector +get_proto_messages_wstrings() +{ + using rosidl_typesupport_protobuf_cpp::write_to_string; + std::string actual; + std::vector messages; + { + auto msg = std::make_shared(); + msg->add_array_of_wstrings(""); + msg->add_array_of_wstrings(""); + msg->add_array_of_wstrings(""); + msg->set_wstring_value(""); + write_to_string(std::u16string(u"1"), actual); + msg->set_array_of_wstrings(0, actual); + write_to_string(std::u16string(u"two"), actual); + msg->set_array_of_wstrings(1, actual); + write_to_string(std::u16string(u"三"), actual); // "One" in Japanese + msg->set_array_of_wstrings(2, actual); + msg->add_bounded_sequence_of_wstrings(); + msg->add_bounded_sequence_of_wstrings(); + write_to_string(std::u16string(u"one"), actual); + msg->set_bounded_sequence_of_wstrings(0, actual); + write_to_string(std::u16string(u"二"), actual); // "Two" in Japanese + msg->set_bounded_sequence_of_wstrings(1, actual); + msg->add_unbounded_sequence_of_wstrings(); + msg->add_unbounded_sequence_of_wstrings(); + msg->add_unbounded_sequence_of_wstrings(); + msg->add_unbounded_sequence_of_wstrings(); + write_to_string(std::u16string(u"."), actual); + msg->set_unbounded_sequence_of_wstrings(0, actual); + write_to_string(std::u16string(u".."), actual); + msg->set_unbounded_sequence_of_wstrings(1, actual); + write_to_string(std::u16string(u"..."), actual); + msg->set_unbounded_sequence_of_wstrings(2, actual); + write_to_string(std::u16string(u"四"), actual); + msg->set_unbounded_sequence_of_wstrings(3, actual); // "Four" in Japanese + messages.push_back(msg); + } + { + auto msg = std::make_shared(); + write_to_string(std::u16string(u"ascii"), actual); + msg->set_wstring_value(actual); + messages.push_back(msg); + } + { + auto msg = std::make_shared(); + write_to_string(std::u16string(u"Hell\u00F6 W\u00F6rld!"), actual); // using umlaut + msg->set_wstring_value(actual); + messages.push_back(msg); + } + { + auto msg = std::make_shared(); + write_to_string(std::u16string(u"ハローワールド"), actual); // "Hello world" in Japanese + msg->set_wstring_value(actual); + messages.push_back(msg); + } + return messages; +} + +#endif // ROSIDL_TYPEADAPTER_PROTOBUF_TEST__TYPEADAPT_MESSAGE_FIXTURES_HPP_ diff --git a/rosidl_typeadapter_protobuf_test/package.xml b/rosidl_typeadapter_protobuf_test/package.xml new file mode 100644 index 0000000..331d9fd --- /dev/null +++ b/rosidl_typeadapter_protobuf_test/package.xml @@ -0,0 +1,44 @@ + + + + rosidl_typeadapter_protobuf_test + 0.19.1 + Protobuff type adapter test + + Gonzalo de Pedro + + Apache License 2.0 + + Gonzalo de Pedro + + rosidl_default_generators + + ament_cmake_auto + + rosidl_default_runtime + + + ament_cmake + ament_cmake_gtest + ament_lint_auto + ament_lint_common + launch + launch_testing + launch_testing_ament_cmake + osrf_testing_tools_cpp + rcl + rclcpp + rclcpp_action + rclpy + rcpputils + rmw_implementation + rmw_implementation_cmake + ros2cli + test_msgs + rosidl_typesupport_protobuf_cpp + + + + ament_cmake + + \ No newline at end of file diff --git a/rosidl_typeadapter_protobuf_test/test/subscribe_array_types.cpp b/rosidl_typeadapter_protobuf_test/test/subscribe_array_types.cpp new file mode 100644 index 0000000..a600d4b --- /dev/null +++ b/rosidl_typeadapter_protobuf_test/test/subscribe_array_types.cpp @@ -0,0 +1,92 @@ +// Copyright 2015 Open Source Robotics Foundation, Inc. +// +// 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 "rclcpp/rclcpp.hpp" + +#include "test_msgs/rosidl_adapter_proto__visibility_control.h" +#include "builtin_interfaces/rosidl_adapter_proto__visibility_control.h" +#include "test_msgs/msg/arrays__typeadapter_protobuf_cpp.hpp" +#include "test_msgs/msg/bounded_plain_sequences__typeadapter_protobuf_cpp.hpp" +#include "test_msgs/msg/bounded_sequences__typeadapter_protobuf_cpp.hpp" +#include "test_msgs/msg/multi_nested__typeadapter_protobuf_cpp.hpp" +#include "test_msgs/msg/nested__typeadapter_protobuf_cpp.hpp" +#include "test_msgs/msg/unbounded_sequences__typeadapter_protobuf_cpp.hpp" + + +#include "subscribe_array_types.hpp" +#include "subscribe_helper.hpp" + +rclcpp::SubscriptionBase::SharedPtr subscribe_arrays( + rclcpp::Node::SharedPtr node, + const std::string & message_type, + const std::vector> & expected_messages, + std::vector & received_messages) +{ + return subscribe( + node, message_type, expected_messages, received_messages); +} + +rclcpp::SubscriptionBase::SharedPtr subscribe_unbounded_sequences( + rclcpp::Node::SharedPtr node, + const std::string & message_type, + const std::vector> & expected_messages, + std::vector & received_messages) +{ + return subscribe( + node, message_type, expected_messages, received_messages); +} + +rclcpp::SubscriptionBase::SharedPtr subscribe_bounded_plain_sequences( + rclcpp::Node::SharedPtr node, + const std::string & message_type, + const std::vector> & expected_messages, + std::vector & received_messages) +{ + return subscribe( + node, message_type, expected_messages, received_messages); +} + +rclcpp::SubscriptionBase::SharedPtr subscribe_bounded_sequences( + rclcpp::Node::SharedPtr node, + const std::string & message_type, + const std::vector> & expected_messages, + std::vector & received_messages) +{ + return subscribe( + node, message_type, expected_messages, received_messages); +} + +rclcpp::SubscriptionBase::SharedPtr subscribe_multi_nested( + rclcpp::Node::SharedPtr node, + const std::string & message_type, + const std::vector> & expected_messages, + std::vector & received_messages) +{ + return subscribe( + node, message_type, expected_messages, received_messages); +} + +rclcpp::SubscriptionBase::SharedPtr subscribe_nested( + rclcpp::Node::SharedPtr node, + const std::string & message_type, + const std::vector> & expected_messages, + std::vector & received_messages) +{ + return subscribe( + node, message_type, expected_messages, received_messages); +} diff --git a/rosidl_typeadapter_protobuf_test/test/subscribe_array_types.hpp b/rosidl_typeadapter_protobuf_test/test/subscribe_array_types.hpp new file mode 100644 index 0000000..ba83f1c --- /dev/null +++ b/rosidl_typeadapter_protobuf_test/test/subscribe_array_types.hpp @@ -0,0 +1,68 @@ +// Copyright 2015 Open Source Robotics Foundation, Inc. +// +// 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. + +#ifndef SUBSCRIBE_ARRAY_TYPES_HPP_ +#define SUBSCRIBE_ARRAY_TYPES_HPP_ + +#include +#include +#include + +#include "rclcpp/rclcpp.hpp" +#include "test_msgs/rosidl_adapter_proto__visibility_control.h" +#include "builtin_interfaces/rosidl_adapter_proto__visibility_control.h" +#include "test_msgs/msg/Arrays.pb.h" +#include "test_msgs/msg/UnboundedSequences.pb.h" +#include "test_msgs/msg/BoundedPlainSequences.pb.h" +#include "test_msgs/msg/BoundedSequences.pb.h" +#include "test_msgs/msg/MultiNested.pb.h" +#include "test_msgs/msg/Nested.pb.h" + +rclcpp::SubscriptionBase::SharedPtr subscribe_arrays( + rclcpp::Node::SharedPtr node, + const std::string & message_type, + const std::vector> & expected_messages, + std::vector & received_messages); + +rclcpp::SubscriptionBase::SharedPtr subscribe_unbounded_sequences( + rclcpp::Node::SharedPtr node, + const std::string & message_type, + const std::vector> & expected_messages, + std::vector & received_messages); + +rclcpp::SubscriptionBase::SharedPtr subscribe_bounded_plain_sequences( + rclcpp::Node::SharedPtr node, + const std::string & message_type, + const std::vector> & expected_messages, + std::vector & received_messages); + +rclcpp::SubscriptionBase::SharedPtr subscribe_bounded_sequences( + rclcpp::Node::SharedPtr node, + const std::string & message_type, + const std::vector> & expected_messages, + std::vector & received_messages); + +rclcpp::SubscriptionBase::SharedPtr subscribe_multi_nested( + rclcpp::Node::SharedPtr node, + const std::string & message_type, + const std::vector> & expected_messages, + std::vector & received_messages); + +rclcpp::SubscriptionBase::SharedPtr subscribe_nested( + rclcpp::Node::SharedPtr node, + const std::string & message_type, + const std::vector> & expected_messages, + std::vector & received_messages); + +#endif // SUBSCRIBE_ARRAY_TYPES_HPP_ diff --git a/rosidl_typeadapter_protobuf_test/test/subscribe_basic_types.cpp b/rosidl_typeadapter_protobuf_test/test/subscribe_basic_types.cpp new file mode 100644 index 0000000..cb11280 --- /dev/null +++ b/rosidl_typeadapter_protobuf_test/test/subscribe_basic_types.cpp @@ -0,0 +1,80 @@ +// Copyright 2015 Open Source Robotics Foundation, Inc. +// +// 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 "rclcpp/rclcpp.hpp" + +#include "test_msgs/rosidl_adapter_proto__visibility_control.h" +#include "builtin_interfaces/rosidl_adapter_proto__visibility_control.h" +#include "test_msgs/msg/basic_types__typeadapter_protobuf_cpp.hpp" +#include "test_msgs/msg/builtins__typeadapter_protobuf_cpp.hpp" +#include "test_msgs/msg/constants__typeadapter_protobuf_cpp.hpp" +#include "test_msgs/msg/defaults__typeadapter_protobuf_cpp.hpp" +#include "test_msgs/msg/empty__typeadapter_protobuf_cpp.hpp" + +#include "subscribe_basic_types.hpp" +#include "subscribe_helper.hpp" + +rclcpp::SubscriptionBase::SharedPtr subscribe_empty( + rclcpp::Node::SharedPtr node, + const std::string & message_type, + const std::vector> & messages_expected, + std::vector & received_messages) +{ + return subscribe( + node, message_type, messages_expected, received_messages); +} + +rclcpp::SubscriptionBase::SharedPtr subscribe_basic_types( + rclcpp::Node::SharedPtr node, + const std::string & message_type, + const std::vector> & messages_expected, + std::vector & received_messages) +{ + return subscribe( + node, message_type, messages_expected, received_messages); +} + +rclcpp::SubscriptionBase::SharedPtr subscribe_builtins( + rclcpp::Node::SharedPtr node, + const std::string & message_type, + const std::vector> & messages_expected, + std::vector & received_messages) +{ + return subscribe( + node, message_type, messages_expected, received_messages); +} + +rclcpp::SubscriptionBase::SharedPtr subscribe_constants( + rclcpp::Node::SharedPtr node, + const std::string & message_type, + const std::vector> & messages_expected, + std::vector & received_messages) +{ + return subscribe( + node, message_type, messages_expected, received_messages); +} + +rclcpp::SubscriptionBase::SharedPtr subscribe_defaults( + rclcpp::Node::SharedPtr node, + const std::string & message_type, + const std::vector> & messages_expected, + std::vector & received_messages) +{ + return subscribe( + node, message_type, messages_expected, received_messages); +} diff --git a/rosidl_typeadapter_protobuf_test/test/subscribe_basic_types.hpp b/rosidl_typeadapter_protobuf_test/test/subscribe_basic_types.hpp new file mode 100644 index 0000000..8b489d4 --- /dev/null +++ b/rosidl_typeadapter_protobuf_test/test/subscribe_basic_types.hpp @@ -0,0 +1,70 @@ +// Copyright 2015 Open Source Robotics Foundation, Inc. +// +// 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. + +#ifndef SUBSCRIBE_BASIC_TYPES_HPP_ +#define SUBSCRIBE_BASIC_TYPES_HPP_ + +#include +#include +#include + +#include "rclcpp/rclcpp.hpp" +#include "test_msgs/rosidl_adapter_proto__visibility_control.h" +#include "builtin_interfaces/rosidl_adapter_proto__visibility_control.h" +#include "test_msgs/msg/Arrays.pb.h" +#include "test_msgs/msg/BasicTypes.pb.h" +#include "test_msgs/msg/BoundedPlainSequences.pb.h" +#include "test_msgs/msg/BoundedSequences.pb.h" +#include "test_msgs/msg/Builtins.pb.h" +#include "test_msgs/msg/Constants.pb.h" +#include "test_msgs/msg/Defaults.pb.h" +#include "test_msgs/msg/Empty.pb.h" +#include "test_msgs/msg/MultiNested.pb.h" +#include "test_msgs/msg/Nested.pb.h" +#include "test_msgs/msg/Strings.pb.h" +#include "test_msgs/msg/UnboundedSequences.pb.h" +#include "test_msgs/msg/WStrings.pb.h" + + +rclcpp::SubscriptionBase::SharedPtr subscribe_empty( + rclcpp::Node::SharedPtr node, + const std::string & message_type, + const std::vector> & messages_expected, + std::vector & received_messages); + +rclcpp::SubscriptionBase::SharedPtr subscribe_basic_types( + rclcpp::Node::SharedPtr node, + const std::string & message_type, + const std::vector> & messages_expected, + std::vector & received_messages); + +rclcpp::SubscriptionBase::SharedPtr subscribe_builtins( + rclcpp::Node::SharedPtr node, + const std::string & message_type, + const std::vector> & messages_expected, + std::vector & received_messages); + +rclcpp::SubscriptionBase::SharedPtr subscribe_constants( + rclcpp::Node::SharedPtr node, + const std::string & message_type, + const std::vector> & messages_expected, + std::vector & received_messages); + +rclcpp::SubscriptionBase::SharedPtr subscribe_defaults( + rclcpp::Node::SharedPtr node, + const std::string & message_type, + const std::vector> & messages_expected, + std::vector & received_messages); + +#endif // SUBSCRIBE_BASIC_TYPES_HPP_ diff --git a/rosidl_typeadapter_protobuf_test/test/subscribe_helper.hpp b/rosidl_typeadapter_protobuf_test/test/subscribe_helper.hpp new file mode 100644 index 0000000..4d62cb5 --- /dev/null +++ b/rosidl_typeadapter_protobuf_test/test/subscribe_helper.hpp @@ -0,0 +1,88 @@ +// Copyright 2015 Open Source Robotics Foundation, Inc. +// +// 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. + +#ifndef SUBSCRIBE_HELPER_HPP_ +#define SUBSCRIBE_HELPER_HPP_ + +#include + +#include +#include +#include +#include +#include + +#include "rclcpp/rclcpp.hpp" + +template +rclcpp::SubscriptionBase::SharedPtr subscribe( + rclcpp::Node::SharedPtr node, + const std::string & message_type, + const std::vector::custom_type>> + & expected_messages, + std::vector & received_messages) +{ + received_messages.assign(expected_messages.size(), false); + + auto callback = + [&expected_messages, &received_messages]( + const std::shared_ptr::custom_type> received_message + ) -> void + { + google::protobuf::util::MessageDifferencer mdiff; + mdiff.set_message_field_comparison( + google::protobuf::util::MessageDifferencer::MessageFieldComparison::EQUAL); + mdiff.set_scope(google::protobuf::util::MessageDifferencer::Scope::PARTIAL); + + // find received message in vector of expected messages + auto received = received_messages.begin(); + bool known_message = false; + size_t index = 0; + for (auto expected_message : expected_messages) { + if (!expected_message->ByteSize()) { + if (!received_message->ByteSize() ) { + *received = true; + printf("received message #%zu of %zu\n", index + 1, expected_messages.size()); + known_message = true; + break; + } + } else if (mdiff.Compare(*expected_message, *received_message)) { + *received = true; + printf("received message #%zu of %zu\n", index + 1, expected_messages.size()); + known_message = true; + break; + } + ++received; + ++index; + } + if (!known_message) { + throw std::runtime_error("received message does not match any expected message"); + } + + // shutdown node when all expected messages have been received + for (auto received_msg : received_messages) { + if (!received_msg) { + return; + } + } + rclcpp::shutdown(); + }; + + auto qos = rclcpp::QoS(rclcpp::KeepLast(expected_messages.size())); + + return + node->create_subscription(std::string("test/message/") + message_type, qos, callback); +} + +#endif // SUBSCRIBE_HELPER_HPP_ diff --git a/rosidl_typeadapter_protobuf_test/test/subscribe_string_types.cpp b/rosidl_typeadapter_protobuf_test/test/subscribe_string_types.cpp new file mode 100644 index 0000000..3af82b9 --- /dev/null +++ b/rosidl_typeadapter_protobuf_test/test/subscribe_string_types.cpp @@ -0,0 +1,48 @@ +// Copyright 2015 Open Source Robotics Foundation, Inc. +// +// 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 "rclcpp/rclcpp.hpp" + +#include "test_msgs/rosidl_adapter_proto__visibility_control.h" +#include "builtin_interfaces/rosidl_adapter_proto__visibility_control.h" +#include "test_msgs/msg/strings__typeadapter_protobuf_cpp.hpp" +#include "test_msgs/msg/w_strings__typeadapter_protobuf_cpp.hpp" + + +#include "subscribe_helper.hpp" +#include "subscribe_string_types.hpp" + +rclcpp::SubscriptionBase::SharedPtr subscribe_strings( + rclcpp::Node::SharedPtr node, + const std::string & message_type, + const std::vector> & expected_messages, + std::vector & received_messages) +{ + return subscribe( + node, message_type, expected_messages, received_messages); +} + +rclcpp::SubscriptionBase::SharedPtr subscribe_wstrings( + rclcpp::Node::SharedPtr node, + const std::string & message_type, + const std::vector> & expected_messages, + std::vector & received_messages) +{ + return subscribe( + node, message_type, expected_messages, received_messages); +} diff --git a/rosidl_typeadapter_protobuf_test/test/subscribe_string_types.hpp b/rosidl_typeadapter_protobuf_test/test/subscribe_string_types.hpp new file mode 100644 index 0000000..d819abd --- /dev/null +++ b/rosidl_typeadapter_protobuf_test/test/subscribe_string_types.hpp @@ -0,0 +1,41 @@ +// Copyright 2015 Open Source Robotics Foundation, Inc. +// +// 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. + +#ifndef SUBSCRIBE_STRING_TYPES_HPP_ +#define SUBSCRIBE_STRING_TYPES_HPP_ + +#include +#include +#include + +#include "rclcpp/rclcpp.hpp" +#include "test_msgs/rosidl_adapter_proto__visibility_control.h" +#include "builtin_interfaces/rosidl_adapter_proto__visibility_control.h" +#include "test_msgs/msg/Strings.pb.h" +#include "test_msgs/msg/WStrings.pb.h" + + +rclcpp::SubscriptionBase::SharedPtr subscribe_strings( + rclcpp::Node::SharedPtr node, + const std::string & message_type, + const std::vector> & expected_messages, + std::vector & received_messages); + +rclcpp::SubscriptionBase::SharedPtr subscribe_wstrings( + rclcpp::Node::SharedPtr node, + const std::string & message_type, + const std::vector> & expected_messages, + std::vector & received_messages); + +#endif // SUBSCRIBE_STRING_TYPES_HPP_ diff --git a/rosidl_typeadapter_protobuf_test/test/test_proto_typeadapt.cpp b/rosidl_typeadapter_protobuf_test/test/test_proto_typeadapt.cpp new file mode 100644 index 0000000..ddb3c7c --- /dev/null +++ b/rosidl_typeadapter_protobuf_test/test/test_proto_typeadapt.cpp @@ -0,0 +1,182 @@ +// Copyright 2021 Open Source Robotics Foundation, Inc. +// +// 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 "rclcpp/rclcpp.hpp" + +#include "rcpputils/scope_exit.hpp" + +#include "test_msgs/message_fixtures.hpp" +#include "rosidl_typeadapter_protobuf_test/typeadapt_message_fixtures.hpp" + +#include "subscribe_array_types.hpp" +#include "subscribe_basic_types.hpp" +#include "subscribe_string_types.hpp" + +template +void publish( + rclcpp::Node::SharedPtr node, + const std::string & message_type, + std::vector::custom_type>> messages, + size_t number_of_cycles = 100) +{ + auto qos = rclcpp::QoS(rclcpp::KeepLast(messages.size())); + + auto publisher = node->create_publisher>( + std::string("test/message/") + message_type, qos); + + try { + rclcpp::WallRate cycle_rate(10); + rclcpp::WallRate message_rate(100); + size_t cycle_index = 0; + // publish all messages up to number_of_cycles times, longer sleep between each cycle + while (rclcpp::ok() && cycle_index < number_of_cycles) { + size_t message_index = 0; + // publish all messages one by one, shorter sleep between each message + while (rclcpp::ok() && message_index < messages.size()) { + printf("publishing message #%zu\n", message_index + 1); + publisher->publish(*messages[message_index]); + ++message_index; + message_rate.sleep(); + } + ++cycle_index; + cycle_rate.sleep(); + } + } catch (const std::exception & ex) { + // It is expected to get into invalid context during the sleep, since rclcpp::shutdown() + // might be called earlier (e.g. by subscribe() routine or when running *AfterShutdown case) + if (ex.what() != std::string("context cannot be slept with because it's invalid")) { + printf("ERROR: got unexpected exception: %s\n", ex.what()); + throw ex; + } + } +} + +int main(int argc, char ** argv) +{ + rclcpp::init(argc, argv); + RCPPUTILS_SCOPE_EXIT( + { + rclcpp::shutdown(); + }); + if (argc != 2) { + fprintf(stderr, "Wrong number of arguments, pass one message type\n"); + return 1; + } + + auto start = std::chrono::steady_clock::now(); + + std::string message = argv[1]; + auto node = rclcpp::Node::make_shared(std::string("test_publisher_subscriber_") + message); + + rclcpp::SubscriptionBase::SharedPtr subscriber; + std::vector received_messages; // collect flags about received messages + + auto messages_empty = get_proto_messages_empty(); + auto messages_basic_types = get_proto_messages_basic_types(); + auto messages_arrays = get_proto_messages_arrays(); + auto messages_bounded_plain_sequences = get_proto_messages_bounded_plain_sequences(); + auto messages_bounded_sequences = get_proto_messages_bounded_sequences(); + auto messages_unbounded_sequences = get_proto_messages_unbounded_sequences(); + auto messages_multi_nested = get_proto_messages_multi_nested(); + auto messages_nested = get_proto_messages_nested(); + auto messages_builtins = get_proto_messages_builtins(); + auto messages_constants = get_proto_messages_constants(); + auto messages_defaults = get_proto_messages_defaults(); + auto messages_strings = get_proto_messages_strings(); + auto messages_wstrings = get_proto_messages_wstrings(); + + std::thread spin_thread([node]() { + rclcpp::spin(node); + }); + + + if (message == "Empty") { + subscriber = subscribe_empty(node, message, messages_empty, received_messages); + publish( + node, message, messages_empty); + } else if (message == "BasicTypes") { + subscriber = subscribe_basic_types(node, message, messages_basic_types, received_messages); + publish( + node, message, messages_basic_types); + } else if (message == "Arrays") { + subscriber = subscribe_arrays(node, message, messages_arrays, received_messages); + publish( + node, message, messages_arrays); + } else if (message == "UnboundedSequences") { + subscriber = subscribe_unbounded_sequences( + node, message, messages_unbounded_sequences, received_messages); + publish( + node, message, messages_unbounded_sequences); + } else if (message == "BoundedPlainSequences") { + subscriber = subscribe_bounded_plain_sequences( + node, message, messages_bounded_plain_sequences, received_messages); + publish( + node, message, messages_bounded_plain_sequences); + } else if (message == "BoundedSequences") { + subscriber = subscribe_bounded_sequences( + node, message, messages_bounded_sequences, received_messages); + publish( + node, message, messages_bounded_sequences); + } else if (message == "MultiNested") { + subscriber = subscribe_multi_nested(node, message, messages_multi_nested, received_messages); + publish( + node, message, messages_multi_nested); + } else if (message == "Nested") { + subscriber = subscribe_nested(node, message, messages_nested, received_messages); + publish( + node, message, messages_nested); + } else if (message == "Builtins") { + subscriber = subscribe_builtins(node, message, messages_builtins, received_messages); + publish( + node, message, messages_builtins); + } else if (message == "Constants") { + subscriber = subscribe_constants(node, message, messages_constants, received_messages); + publish( + node, message, messages_constants); + } else if (message == "Defaults") { + subscriber = subscribe_defaults(node, message, messages_defaults, received_messages); + publish( + node, message, messages_defaults); + } else if (message == "Strings") { + subscriber = subscribe_strings(node, message, messages_strings, received_messages); + publish( + node, message, messages_strings); + } else if (message == "WStrings") { + subscriber = subscribe_wstrings(node, message, messages_wstrings, received_messages); + publish( + node, message, messages_wstrings); + } else { + fprintf(stderr, "Unknown message argument '%s'\n", message.c_str()); + return 1; + } + + spin_thread.join(); + + auto end = std::chrono::steady_clock::now(); + std::chrono::duration diff = (end - start); + printf("published and subscribed for %f seconds\n", diff.count()); + + for (auto received : received_messages) { + if (!received) { + return 1; + } + } + + return 0; +} diff --git a/rosidl_typesupport_protobuf_c/CMakeLists.txt b/rosidl_typesupport_protobuf_c/CMakeLists.txt index ae150f0..c843619 100644 --- a/rosidl_typesupport_protobuf_c/CMakeLists.txt +++ b/rosidl_typesupport_protobuf_c/CMakeLists.txt @@ -106,6 +106,17 @@ ament_target_dependencies(${PROJECT_NAME} rosidl_typesupport_protobuf) ament_index_register_resource("rosidl_typesupport_c") +if(BUILD_TESTING) + # find_package(ament_lint_auto REQUIRED) + # ament_lint_auto_find_test_dependencies() + find_package(ament_cmake_gtest REQUIRED) + ament_add_gtest(test_wstring_conversion test/test_wstring_conversion.cpp) + if(TARGET test_wstring_conversion) + target_link_libraries(test_wstring_conversion + ${PROJECT_NAME}) + endif() +endif() + ament_package( CONFIG_EXTRAS "cmake/rosidl_typesupport_protobuf_c-extras.cmake.in" ) diff --git a/rosidl_typesupport_protobuf_c/package.xml b/rosidl_typesupport_protobuf_c/package.xml index 9994de9..f61936a 100644 --- a/rosidl_typesupport_protobuf_c/package.xml +++ b/rosidl_typesupport_protobuf_c/package.xml @@ -29,6 +29,8 @@ rosidl_parser rosidl_typesupport_interface + ament_cmake_gtest + rosidl_typesupport_c_packages diff --git a/rosidl_typesupport_protobuf_c/test/test_wstring_conversion.cpp b/rosidl_typesupport_protobuf_c/test/test_wstring_conversion.cpp new file mode 100644 index 0000000..0b8f88e --- /dev/null +++ b/rosidl_typesupport_protobuf_c/test/test_wstring_conversion.cpp @@ -0,0 +1,76 @@ +/* ================================ Apache 2.0 ================================= + * + * Copyright (C) 2021 Continental + * + * 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. + * + * ================================ Apache 2.0 ================================= + */ + +#include + +#include "gtest/gtest.h" + +#include "rosidl_runtime_c/u16string_functions.h" + +#include "rosidl_typesupport_protobuf_c/wstring_conversion.hpp" + +using rosidl_typesupport_protobuf_c::write_to_string; +using rosidl_typesupport_protobuf_c::write_to_u16string; + +TEST(test_wstring_conversion, u16string_to_string) { + std::string actual; + rosidl_runtime_c__U16String input; + ASSERT_TRUE(rosidl_runtime_c__U16String__init(&input)); + + // Default string + write_to_string(input, actual); + EXPECT_EQ(std::string(), actual); + + // Empty String + ASSERT_TRUE( + rosidl_runtime_c__U16String__assign(&input, (const uint16_t *)u"")); + write_to_string(input, actual); + EXPECT_EQ(std::string(""), actual); + + // Non-empty string + ASSERT_TRUE(rosidl_runtime_c__U16String__assign( + &input, (const uint16_t *)u"Hello World")); + write_to_string(input, actual); + const char byteArray[] = {'H', 0x00, 'e', 0x00, 'l', 0x00, 'l', 0x00, + 'o', 0x00, ' ', 0x00, 'W', 0x00, 'o', 0x00, + 'r', 0x00, 'l', 0x00, 'd', 0x00}; + std::string expected(byteArray, sizeof(byteArray)); + EXPECT_EQ(expected, actual); +} + +TEST(test_wstring_conversion, string_to_u16string) { + rosidl_runtime_c__U16String actual; + ASSERT_TRUE(rosidl_runtime_c__U16String__init(&actual)); + + // Default string + write_to_u16string(std::string(), actual); + EXPECT_EQ(0, memcmp(u"", actual.data, actual.size)); + + // Empty String + write_to_u16string(std::string(""), actual); + EXPECT_EQ(0, memcmp(u"", actual.data, actual.size)); + + // Non-empty string + const char byteArray_input[] = {'H', 0x00, 'e', 0x00, 'l', 0x00, 'l', 0x00, + 'o', 0x00, ' ', 0x00, 'W', 0x00, 'o', 0x00, + 'r', 0x00, 'l', 0x00, 'd', 0x00}; + std::string input_string(byteArray_input, sizeof(byteArray_input)); + write_to_u16string(input_string, actual); + EXPECT_EQ(0, memcmp(u"Hello World", actual.data, actual.size)); +} \ No newline at end of file diff --git a/rosidl_typesupport_protobuf_cpp/CMakeLists.txt b/rosidl_typesupport_protobuf_cpp/CMakeLists.txt index cc6ebcc..2413e03 100644 --- a/rosidl_typesupport_protobuf_cpp/CMakeLists.txt +++ b/rosidl_typesupport_protobuf_cpp/CMakeLists.txt @@ -89,6 +89,15 @@ ament_export_targets(${PROJECT_NAME}) ament_index_register_resource("rosidl_typesupport_cpp") +if(BUILD_TESTING) + find_package(ament_cmake_gtest REQUIRED) + ament_add_gtest(test_wstring_conversion test/test_wstring_conversion.cpp) + if(TARGET test_wstring_conversion) + target_link_libraries(test_wstring_conversion + ${PROJECT_NAME}) + endif() +endif() + ament_package(CONFIG_EXTRAS "cmake/rosidl_typesupport_protobuf_cpp-extras.cmake.in") install( diff --git a/rosidl_typesupport_protobuf_cpp/package.xml b/rosidl_typesupport_protobuf_cpp/package.xml index 9503bdd..485900b 100644 --- a/rosidl_typesupport_protobuf_cpp/package.xml +++ b/rosidl_typesupport_protobuf_cpp/package.xml @@ -28,6 +28,8 @@ rosidl_typesupport_interface rosidl_typesupport_protobuf + ament_cmake_gtest + rosidl_typesupport_cpp_packages diff --git a/rosidl_typesupport_protobuf_cpp/resource/msg__type_support.cpp.em b/rosidl_typesupport_protobuf_cpp/resource/msg__type_support.cpp.em index 5aad196..cca61fa 100644 --- a/rosidl_typesupport_protobuf_cpp/resource/msg__type_support.cpp.em +++ b/rosidl_typesupport_protobuf_cpp/resource/msg__type_support.cpp.em @@ -107,7 +107,7 @@ bool convert_to_ros(const @(proto_type) &pb_msg, @(ros_type) &ros_msg) @[ if isinstance(member.type, AbstractNestedType)]@ @[ if isinstance(member.type.value_type, BasicType) or isinstance(member.type.value_type, AbstractString)]@ @[ if isinstance(member.type, Array)]@ - std::copy_n(pb_msg.@(member.name)().begin(), ros_msg.@(member.name).size(), ros_msg.@(member.name).begin()); + std::copy_n(pb_msg.@(member.name)().begin(), pb_msg.@(member.name)().size(), ros_msg.@(member.name).begin()); @[ else]@ @[ if isinstance(member.type.value_type, BasicType) and member.type.value_type.typename == BOOLEAN_TYPE]@ for(auto val : pb_msg.@(member.name)()) diff --git a/rosidl_typesupport_protobuf_cpp/test/test_wstring_conversion.cpp b/rosidl_typesupport_protobuf_cpp/test/test_wstring_conversion.cpp new file mode 100644 index 0000000..611f928 --- /dev/null +++ b/rosidl_typesupport_protobuf_cpp/test/test_wstring_conversion.cpp @@ -0,0 +1,69 @@ +/* ================================ Apache 2.0 ================================= + * + * Copyright (C) 2021 Continental + * + * 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. + * + * ================================ Apache 2.0 ================================= + */ + +#include + +#include "gtest/gtest.h" +#include + +#include "rosidl_typesupport_protobuf_cpp/wstring_conversion.hpp" + +using rosidl_typesupport_protobuf_cpp::write_to_string; +using rosidl_typesupport_protobuf_cpp::write_to_u16string; + +TEST(test_wstring_conversion, u16string_to_string) { + std::string actual; + + // Default string + write_to_string(std::u16string(), actual); + EXPECT_EQ(std::string(), actual); + + // Empty string + write_to_string(std::u16string(u""), actual); + EXPECT_EQ(std::string(""), actual); + + // Non-empty string + write_to_string(std::u16string(u"Hello World"), actual); + const char byteArray[] = {'H', 0x00, 'e', 0x00, 'l', 0x00, 'l', 0x00, + 'o', 0x00, ' ', 0x00, 'W', 0x00, 'o', 0x00, + 'r', 0x00, 'l', 0x00, 'd', 0x00}; + std::string expected(byteArray, sizeof(byteArray)); + EXPECT_EQ(expected, actual); +} + +TEST(test_wstring_conversion, string_to_u16string) { + std::u16string actual; + + // Default string + write_to_u16string(std::string(), actual); + EXPECT_EQ(std::u16string(), actual); + + // Empty string + write_to_u16string(std::string(""), actual); + EXPECT_EQ(std::u16string(u""), actual); + + // Non-empty string + const char byteArray_input[] = {'H', 0x00, 'e', 0x00, 'l', 0x00, 'l', 0x00, + 'o', 0x00, ' ', 0x00, 'W', 0x00, 'o', 0x00, + 'r', 0x00, 'l', 0x00, 'd', 0x00}; + std::string input_string(byteArray_input, sizeof(byteArray_input)); + write_to_u16string(input_string, actual); + std::u16string expected(u"Hello World"); + EXPECT_EQ(expected, actual); +} \ No newline at end of file