Compare commits

...

36 Commits
2.2.0 ... 4.0.0

Author SHA1 Message Date
Jacob Perron
4b57fb2b8e 4.0.0 2020-07-09 12:24:16 -07:00
Michel Hidalgo
84ae5a1897 Fix rclcpp::NodeOptions::operator= (#1211)
Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
2020-07-02 16:08:40 -03:00
Dirk Thomas
05e6b96847 link against thread library where necessary (#1210)
Signed-off-by: Dirk Thomas <dirk-thomas@users.noreply.github.com>
2020-07-01 13:22:33 -07:00
brawner
860a9e0e4d Unit tests for node interfaces (#1202)
* Unit tests for node interfaces

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Address PR Feedback

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Address PR feedback

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Adjusting comment

Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-07-01 12:48:41 -07:00
Ivan Santiago Paunovic
f125c78fa8 Remove usage of domain id in node options (#1205)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-07-01 13:16:56 -03:00
Claire Wang
a8cd936239 remove deprecated set_on_parameters_set_callback function (#1199)
Signed-off-by: claireyywang <22240514+claireyywang@users.noreply.github.com>
2020-06-29 15:24:12 -07:00
Johannes Meyer
c92f3b7ff9 Fix conversion of negative durations to messages (#1188)
* Fix conversion from negative Duration or Time to the respective message type and throw in Duration::to_rmw_time() if the duration is negative.
rmw_time_t cannot represent negative durations.

Constructors and assignment operators can be just defaulted.

Other changes are mainly cosmetical, to make conversions between signed
and unsigned types and between 32-bit and 64-bit types more explicit.

Signed-off-by: Johannes Meyer <johannes@intermodalics.eu>

* Add -Wconversion compiler option and fix implicit conversions that might alter the value

Signed-off-by: Johannes Meyer <johannes@intermodalics.eu>

* Fix usage of fixture class in some unit tests by using gtest macro TEST_F() instead of TEST().

Signed-off-by: Johannes Meyer <johannes@intermodalics.eu>

* Add compiler option -Wno-sign-conversion to fix build with Clang on macOS

Signed-off-by: Johannes Meyer <johannes@intermodalics.eu>
2020-06-29 12:44:19 -03:00
Johannes Meyer
c0b96616bb Fix implementation of NodeOptions::use_global_arguments() (#1176)
`this->node_options_` might still be `nullptr` for a default initialized NodeOptions instance.
`use_global_arguments()` must return `this->use_global_arguments_`, in analogy to `NodeOptions::enable_rosout()`.

Signed-off-by: Johannes Meyer <johannes@intermodalics.eu>
2020-06-29 10:47:23 -03:00
Alejandro Hernández Cordero
55fccffc89 Bump to QD to level 3 and fixed links (#1158)
* Update quality level and links to doc

Signed-off-by: ahcorde <ahcorde@gmail.com>

* Added feedback

Signed-off-by: ahcorde <ahcorde@gmail.com>

* Fixed wording and links

Signed-off-by: ahcorde <ahcorde@gmail.com>

* Bump QD to level 3 and fixed links

Signed-off-by: ahcorde <ahcorde@gmail.com>

* Added missing dependency rcpputils to rclcpp_components

Signed-off-by: ahcorde <ahcorde@gmail.com>

* Added missing dependency rmw to rclcpp_lifecycle

Signed-off-by: ahcorde <ahcorde@gmail.com>

* Added feedback

Signed-off-by: ahcorde <ahcorde@gmail.com>

* changed ci_linux_coverage to nightly_linux_coverage

Signed-off-by: ahcorde <ahcorde@gmail.com>
2020-06-29 08:43:34 +02:00
Dirk Thomas
873a3d5cd0 fix race in test_lifecycle_service_client (#1204)
Signed-off-by: Dirk Thomas <dirk-thomas@users.noreply.github.com>
2020-06-26 16:00:31 -07:00
Michel Hidalgo
a9d5a3feb9 Fix pub/sub count API tests. (#1203)
Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
2020-06-26 20:00:14 -03:00
Martijn Buijs
c23572fa14 Include original exception in ComponentManagerException (#1157)
* Include original exception in ComponentManagerException

Signed-off-by: Martijn Buijs <martijn.buijs@gmail.com>

* Update rclcpp_components/src/component_manager.cpp

Co-authored-by: tomoya <Tomoya.Fujita@sony.com>
Signed-off-by: Martijn Buijs <martijn.buijs@gmail.com>

Co-authored-by: tomoya <Tomoya.Fujita@sony.com>
2020-06-26 10:41:23 -05:00
Christophe Bedard
8245808c0e Update tracetools' QL to 2 in rclcpp's QD (#1187)
Signed-off-by: Christophe Bedard <bedard.christophe@gmail.com>
2020-06-25 15:52:19 +02:00
tomoya
35c27e8250 fix exception message on rcl_clock_init. (#1182)
Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>
2020-06-23 13:42:35 -03:00
brawner
8a62104ea7 Throw exception if rcl_timer_init fails (#1179)
* Throw exception if rcl_timer_init fails

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Add bad-argument tests for GenericTimer

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Add comments

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Address feedback

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Address feedback

Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-06-22 14:25:51 -07:00
brawner
c63060c42d Unit tests for some header-only functions/classes (#1181)
* Unit tests for header-only functions/classes

Adds coverage for:
  * any_service_callback.hpp
  * any_subscription_callback.hpp
  * create_subscription.hpp
  * create_timer.hpp

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Address PR feedback

Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-06-22 13:37:54 -07:00
tomoya
2a7b722d5f callback should be perfectly-forwarded. (#1183)
Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>
2020-06-22 15:25:59 -03:00
brawner
a6741a4f8e Add unit tests for logging functionality (#1184)
Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-06-19 13:22:06 -07:00
brawner
40f0040f0d Add create_publisher include to create_subscription (#1180)
Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-06-19 10:57:06 -07:00
Ivan Santiago Paunovic
4f14a0cc14 3.0.0 2020-06-18 21:11:09 +00:00
Ivan Santiago Paunovic
83b086a9ef Changelogs
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-06-18 21:10:46 +00:00
brawner
2ed85420d5 Check period duration in create_wall_timer (#1178)
* Check period duration in create_wall_timer

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Adding comments

Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-06-18 14:00:31 -07:00
Jacob Perron
cc65905efa Fix get_node_time_source_interface() docstring (#988)
Signed-off-by: Jacob Perron <jacob@openrobotics.org>
2020-06-18 09:51:03 -07:00
Ivan Santiago Paunovic
88768eaabd Add message lost subscription event (#1164)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-06-17 18:58:39 -03:00
tomoya
696d9ed1be add rcl_action_client_options when creating action client. (#1133)
* add rcl_action_client_options for create_client.

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>

* Capitalize comments and keep the default rcl_action_client_options.

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>

* delete unnecessary default rcl_action_client_options_t.

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>
2020-06-16 15:03:35 -07:00
Ivan Santiago Paunovic
74daff052b Add spin_all method to Executor (#1156)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-06-16 16:07:11 -03:00
brawner
a667583821 Reorganize test directory and split CMakeLists.txt (#1173)
Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-06-12 11:40:15 -07:00
Ivan Santiago Paunovic
552c1a8deb Check if context is valid when looping in spin_some (#1167)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-06-11 17:17:39 -03:00
Devin Bonnie
5cecbf99bb Add check for invalid topic statistics publish period (#1151)
* Add check for invalid topic statistics publish period

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Update documentation

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Address review comments

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Address doc formatting comments

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Update doc spacing

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>
2020-06-11 11:08:38 -07:00
DongheeYe
f703314f95 Fix spin_until_future_complete: check spinning value (#1023)
Signed-off-by: Donghee Ye <donghee.ye@samsung.com>
2020-06-11 14:25:02 -03:00
Ivan Santiago Paunovic
0fa68d54e7 Revert "Revert "Allow spin_until_future_complete to accept std::future (#1113)" (#1159)" (#1160)
This reverts commit bba9dce253.

Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-06-10 13:39:38 -03:00
Alejandro Hernández Cordero
cbde45481e Fixed doxygen warnings (#1163)
Signed-off-by: ahcorde <ahcorde@gmail.com>
2020-06-10 17:03:09 +02:00
Christophe Bedard
2a653c47f8 Fix reference to rclcpp in its QD (#1161)
Signed-off-by: Christophe Bedard <bedard.christophe@gmail.com>
2020-06-10 09:40:17 +02:00
Dirk Thomas
bba9dce253 Revert "Allow spin_until_future_complete to accept std::future (#1113)" (#1159)
This reverts commit 898a30e0e2.
2020-06-08 21:38:52 -07:00
Sarthak Mittal
898a30e0e2 Allow spin_until_future_complete to accept std::future (#1113)
Signed-off-by: Sarthak Mittal <sarthakmittal2608@gmail.com>
2020-06-08 16:39:46 -03:00
Michel Hidalgo
6e8aaa2ae6 Increase rclcpp_action test coverage (#1153)
Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
2020-06-08 11:03:34 -03:00
129 changed files with 3436 additions and 1551 deletions

View File

@@ -2,6 +2,41 @@
Changelog for package rclcpp
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4.0.0 (2020-07-09)
------------------
* Fix rclcpp::NodeOptions::operator= (`#1211 <https://github.com/ros2/rclcpp/issues/1211>`_)
* Link against thread library where necessary (`#1210 <https://github.com/ros2/rclcpp/issues/1210>`_)
* Unit tests for node interfaces (`#1202 <https://github.com/ros2/rclcpp/issues/1202>`_)
* Remove usage of domain id in node options (`#1205 <https://github.com/ros2/rclcpp/issues/1205>`_)
* Remove deprecated set_on_parameters_set_callback function (`#1199 <https://github.com/ros2/rclcpp/issues/1199>`_)
* Fix conversion of negative durations to messages (`#1188 <https://github.com/ros2/rclcpp/issues/1188>`_)
* Fix implementation of NodeOptions::use_global_arguments() (`#1176 <https://github.com/ros2/rclcpp/issues/1176>`_)
* Bump to QD to level 3 and fixed links (`#1158 <https://github.com/ros2/rclcpp/issues/1158>`_)
* Fix pub/sub count API tests (`#1203 <https://github.com/ros2/rclcpp/issues/1203>`_)
* Update tracetools' QL to 2 in rclcpp's QD (`#1187 <https://github.com/ros2/rclcpp/issues/1187>`_)
* Fix exception message on rcl_clock_init (`#1182 <https://github.com/ros2/rclcpp/issues/1182>`_)
* Throw exception if rcl_timer_init fails (`#1179 <https://github.com/ros2/rclcpp/issues/1179>`_)
* Unit tests for some header-only functions/classes (`#1181 <https://github.com/ros2/rclcpp/issues/1181>`_)
* Callback should be perfectly-forwarded (`#1183 <https://github.com/ros2/rclcpp/issues/1183>`_)
* Add unit tests for logging functionality (`#1184 <https://github.com/ros2/rclcpp/issues/1184>`_)
* Add create_publisher include to create_subscription (`#1180 <https://github.com/ros2/rclcpp/issues/1180>`_)
* Contributors: Alejandro Hernández Cordero, Christophe Bedard, Claire Wang, Dirk Thomas, Ivan Santiago Paunovic, Johannes Meyer, Michel Hidalgo, Stephen Brawner, tomoya
3.0.0 (2020-06-18)
------------------
* Check period duration in create_wall_timer (`#1178 <https://github.com/ros2/rclcpp/issues/1178>`_)
* Fix get_node_time_source_interface() docstring (`#988 <https://github.com/ros2/rclcpp/issues/988>`_)
* Add message lost subscription event (`#1164 <https://github.com/ros2/rclcpp/issues/1164>`_)
* Add spin_all method to Executor (`#1156 <https://github.com/ros2/rclcpp/issues/1156>`_)
* Reorganize test directory and split CMakeLists.txt (`#1173 <https://github.com/ros2/rclcpp/issues/1173>`_)
* Check if context is valid when looping in spin_some (`#1167 <https://github.com/ros2/rclcpp/issues/1167>`_)
* Add check for invalid topic statistics publish period (`#1151 <https://github.com/ros2/rclcpp/issues/1151>`_)
* Fix spin_until_future_complete: check spinning value (`#1023 <https://github.com/ros2/rclcpp/issues/1023>`_)
* Fix doxygen warnings (`#1163 <https://github.com/ros2/rclcpp/issues/1163>`_)
* Fix reference to rclcpp in its Quality declaration (`#1161 <https://github.com/ros2/rclcpp/issues/1161>`_)
* Allow spin_until_future_complete to accept any future like object (`#1113 <https://github.com/ros2/rclcpp/issues/1113>`_)
* Contributors: Alejandro Hernández Cordero, Christophe Bedard, Devin Bonnie, Dirk Thomas, DongheeYe, Ivan Santiago Paunovic, Jacob Perron, Sarthak Mittal, brawner, tomoya
2.0.0 (2020-06-01)
------------------
* Added missing virtual destructors. (`#1149 <https://github.com/ros2/rclcpp/issues/1149>`_)

View File

@@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 3.5)
project(rclcpp)
find_package(Threads REQUIRED)
find_package(ament_cmake_ros REQUIRED)
find_package(builtin_interfaces REQUIRED)
find_package(libstatistics_collector REQUIRED)
@@ -23,7 +25,11 @@ if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 14)
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic -Wnon-virtual-dtor -Woverloaded-virtual)
# About -Wno-sign-conversion: With Clang, -Wconversion implies -Wsign-conversion. There are a number of
# implicit sign conversions in rclcpp and gtest.cc, see https://ci.ros2.org/job/ci_osx/9265/.
# Hence disabling -Wsign-conversion for now until all those have eventually been fixed.
# (from https://github.com/ros2/rclcpp/pull/1188#issuecomment-650229140)
add_compile_options(-Wall -Wextra -Wconversion -Wno-sign-conversion -Wpedantic -Wnon-virtual-dtor -Woverloaded-virtual)
endif()
set(${PROJECT_NAME}_SRCS
@@ -166,6 +172,7 @@ target_include_directories(${PROJECT_NAME} PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>"
"$<INSTALL_INTERFACE:include>")
target_link_libraries(${PROJECT_NAME} ${CMAKE_THREAD_LIBS_INIT})
# specific order: dependents before dependencies
ament_target_dependencies(${PROJECT_NAME}
"libstatistics_collector"
@@ -212,442 +219,10 @@ ament_export_dependencies(statistics_msgs)
ament_export_dependencies(tracetools)
if(BUILD_TESTING)
find_package(ament_cmake_gtest REQUIRED)
find_package(ament_lint_auto REQUIRED)
ament_lint_auto_find_test_dependencies()
find_package(rmw_implementation_cmake REQUIRED)
find_package(rosidl_default_generators REQUIRED)
find_package(test_msgs REQUIRED)
include(cmake/rclcpp_add_build_failure_test.cmake)
add_definitions(-DTEST_RESOURCES_DIRECTORY="${CMAKE_CURRENT_BINARY_DIR}/test/resources")
rosidl_generate_interfaces(${PROJECT_NAME}_test_msgs
test/msg/Header.msg
test/msg/MessageWithHeader.msg
DEPENDENCIES builtin_interfaces
LIBRARY_NAME ${PROJECT_NAME}
SKIP_INSTALL
)
ament_add_gtest(test_client test/test_client.cpp)
if(TARGET test_client)
ament_target_dependencies(test_client
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_client ${PROJECT_NAME})
endif()
ament_add_gtest(test_create_timer test/test_create_timer.cpp)
if(TARGET test_create_timer)
ament_target_dependencies(test_create_timer
"rcl_interfaces"
"rmw"
"rcl"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_create_timer ${PROJECT_NAME})
target_include_directories(test_create_timer PRIVATE test/)
endif()
ament_add_gtest(test_expand_topic_or_service_name test/test_expand_topic_or_service_name.cpp)
if(TARGET test_expand_topic_or_service_name)
ament_target_dependencies(test_expand_topic_or_service_name
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_expand_topic_or_service_name ${PROJECT_NAME})
endif()
ament_add_gtest(test_function_traits test/test_function_traits.cpp)
if(TARGET test_function_traits)
target_include_directories(test_function_traits PUBLIC include)
ament_target_dependencies(test_function_traits
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
endif()
ament_add_gmock(test_intra_process_manager test/test_intra_process_manager.cpp)
if(TARGET test_intra_process_manager)
ament_target_dependencies(test_intra_process_manager
"rcl"
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_intra_process_manager ${PROJECT_NAME})
endif()
ament_add_gtest(test_ring_buffer_implementation test/test_ring_buffer_implementation.cpp)
if(TARGET test_ring_buffer_implementation)
ament_target_dependencies(test_ring_buffer_implementation
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_ring_buffer_implementation ${PROJECT_NAME})
endif()
ament_add_gtest(test_intra_process_buffer test/test_intra_process_buffer.cpp)
if(TARGET test_intra_process_buffer)
ament_target_dependencies(test_intra_process_buffer
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_intra_process_buffer ${PROJECT_NAME})
endif()
ament_add_gtest(test_loaned_message test/test_loaned_message.cpp)
ament_target_dependencies(test_loaned_message
"test_msgs"
)
target_link_libraries(test_loaned_message ${PROJECT_NAME})
ament_add_gtest(test_node test/test_node.cpp TIMEOUT 240)
if(TARGET test_node)
ament_target_dependencies(test_node
"rcl_interfaces"
"rcpputils"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_node ${PROJECT_NAME})
endif()
ament_add_gtest(test_node_interfaces__get_node_interfaces
test/node_interfaces/test_get_node_interfaces.cpp)
if(TARGET test_node_interfaces__get_node_interfaces)
target_link_libraries(test_node_interfaces__get_node_interfaces ${PROJECT_NAME})
endif()
# TODO(wjwwood): reenable these build failure tests when I can get Jenkins to ignore their output
# rclcpp_add_build_failure_test(build_failure__get_node_topics_interface_const_ref_rclcpp_node
# test/node_interfaces/test_does_not_compile/get_node_topics_interface_const_ref_rclcpp_node.cpp)
# target_link_libraries(build_failure__get_node_topics_interface_const_ref_rclcpp_node
# ${PROJECT_NAME})
# rclcpp_add_build_failure_test(build_failure__get_node_topics_interface_const_ptr_rclcpp_node
# test/node_interfaces/test_does_not_compile/get_node_topics_interface_const_ptr_rclcpp_node.cpp)
# target_link_libraries(build_failure__get_node_topics_interface_const_ptr_rclcpp_node
# ${PROJECT_NAME})
# rclcpp_add_build_failure_test(build_failure__get_node_topics_interface_const_ref_wrapped_node
# test/node_interfaces/test_does_not_compile/get_node_topics_interface_const_ref_wrapped_node.cpp)
# target_link_libraries(build_failure__get_node_topics_interface_const_ref_rclcpp_node
# ${PROJECT_NAME})
# rclcpp_add_build_failure_test(build_failure__get_node_topics_interface_const_ptr_wrapped_node
# test/node_interfaces/test_does_not_compile/get_node_topics_interface_const_ptr_wrapped_node.cpp)
# target_link_libraries(build_failure__get_node_topics_interface_const_ptr_rclcpp_node
# ${PROJECT_NAME})
ament_add_gtest(test_node_global_args test/test_node_global_args.cpp)
if(TARGET test_node_global_args)
ament_target_dependencies(test_node_global_args
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_node_global_args ${PROJECT_NAME})
endif()
ament_add_gtest(test_node_options test/test_node_options.cpp)
if(TARGET test_node_options)
ament_target_dependencies(test_node_options "rcl")
target_link_libraries(test_node_options ${PROJECT_NAME})
endif()
ament_add_gtest(test_parameter_client test/test_parameter_client.cpp)
if(TARGET test_parameter_client)
ament_target_dependencies(test_parameter_client
"rcl_interfaces"
)
target_link_libraries(test_parameter_client ${PROJECT_NAME})
endif()
ament_add_gtest(test_parameter_events_filter test/test_parameter_events_filter.cpp)
if(TARGET test_parameter_events_filter)
ament_target_dependencies(test_parameter_events_filter
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_parameter_events_filter ${PROJECT_NAME})
endif()
ament_add_gtest(test_parameter test/test_parameter.cpp)
if(TARGET test_parameter)
ament_target_dependencies(test_parameter
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_parameter ${PROJECT_NAME})
endif()
ament_add_gtest(test_parameter_map test/test_parameter_map.cpp)
if(TARGET test_parameter_map)
target_link_libraries(test_parameter_map ${PROJECT_NAME})
endif()
ament_add_gtest(test_publisher test/test_publisher.cpp)
if(TARGET test_publisher)
ament_target_dependencies(test_publisher
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_publisher ${PROJECT_NAME})
endif()
ament_add_gtest(test_publisher_subscription_count_api test/test_publisher_subscription_count_api.cpp)
if(TARGET test_publisher_subscription_count_api)
ament_target_dependencies(test_publisher_subscription_count_api
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_publisher_subscription_count_api ${PROJECT_NAME})
endif()
ament_add_gtest(test_qos test/test_qos.cpp)
if(TARGET test_qos)
ament_target_dependencies(test_qos
"rmw"
)
target_link_libraries(test_qos
${PROJECT_NAME}
)
endif()
ament_add_gtest(test_qos_event test/test_qos_event.cpp)
if(TARGET test_qos_event)
ament_target_dependencies(test_qos_event
"rmw"
"test_msgs"
)
target_link_libraries(test_qos_event
${PROJECT_NAME}
)
endif()
ament_add_gtest(test_rate test/test_rate.cpp)
if(TARGET test_rate)
ament_target_dependencies(test_rate
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_rate
${PROJECT_NAME}
)
endif()
ament_add_gtest(test_serialized_message_allocator test/test_serialized_message_allocator.cpp)
if(TARGET test_serialized_message_allocator)
ament_target_dependencies(test_serialized_message_allocator
test_msgs
)
target_link_libraries(test_serialized_message_allocator
${PROJECT_NAME}
)
endif()
ament_add_gtest(test_serialized_message test/test_serialized_message.cpp)
if(TARGET test_serialized_message)
ament_target_dependencies(test_serialized_message
test_msgs
)
target_link_libraries(test_serialized_message
${PROJECT_NAME}
)
endif()
ament_add_gtest(test_service test/test_service.cpp)
if(TARGET test_service)
ament_target_dependencies(test_service
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_service ${PROJECT_NAME})
endif()
ament_add_gtest(test_subscription test/test_subscription.cpp)
if(TARGET test_subscription)
ament_target_dependencies(test_subscription
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_subscription ${PROJECT_NAME})
endif()
ament_add_gtest(test_subscription_publisher_count_api test/test_subscription_publisher_count_api.cpp)
if(TARGET test_subscription_publisher_count_api)
ament_target_dependencies(test_subscription_publisher_count_api
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_subscription_publisher_count_api ${PROJECT_NAME})
endif()
ament_add_gtest(test_subscription_traits test/test_subscription_traits.cpp)
if(TARGET test_subscription_traits)
ament_target_dependencies(test_subscription_traits
"rcl"
"test_msgs"
)
target_link_libraries(test_subscription_traits ${PROJECT_NAME})
endif()
ament_add_gtest(test_find_weak_nodes test/test_find_weak_nodes.cpp)
if(TARGET test_find_weak_nodes)
ament_target_dependencies(test_find_weak_nodes
"rcl"
)
target_link_libraries(test_find_weak_nodes ${PROJECT_NAME})
endif()
set(append_library_dirs "${CMAKE_CURRENT_BINARY_DIR}")
if(WIN32)
set(append_library_dirs "${append_library_dirs}/$<CONFIG>")
endif()
ament_add_gtest(test_externally_defined_services test/test_externally_defined_services.cpp)
ament_target_dependencies(test_externally_defined_services
"rcl"
"test_msgs"
)
target_link_libraries(test_externally_defined_services ${PROJECT_NAME})
ament_add_gtest(test_duration test/test_duration.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_duration)
ament_target_dependencies(test_duration
"rcl")
target_link_libraries(test_duration ${PROJECT_NAME})
endif()
ament_add_gtest(test_executor test/test_executor.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_executor)
ament_target_dependencies(test_executor
"rcl")
target_link_libraries(test_executor ${PROJECT_NAME})
endif()
ament_add_gtest(test_logger test/test_logger.cpp)
target_link_libraries(test_logger ${PROJECT_NAME})
ament_add_gmock(test_logging test/test_logging.cpp)
target_link_libraries(test_logging ${PROJECT_NAME})
ament_add_gtest(test_time test/test_time.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_time)
ament_target_dependencies(test_time
"rcl")
target_link_libraries(test_time ${PROJECT_NAME})
endif()
ament_add_gtest(test_timer test/test_timer.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_timer)
ament_target_dependencies(test_timer
"rcl")
target_link_libraries(test_timer ${PROJECT_NAME})
endif()
ament_add_gtest(test_time_source test/test_time_source.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_time_source)
ament_target_dependencies(test_time_source
"rcl")
target_link_libraries(test_time_source ${PROJECT_NAME})
endif()
ament_add_gtest(test_utilities test/test_utilities.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_utilities)
ament_target_dependencies(test_utilities
"rcl")
target_link_libraries(test_utilities ${PROJECT_NAME})
endif()
ament_add_gtest(test_init test/test_init.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_init)
ament_target_dependencies(test_init
"rcl")
target_link_libraries(test_init ${PROJECT_NAME})
endif()
ament_add_gtest(test_interface_traits test/test_interface_traits.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_interface_traits)
ament_target_dependencies(test_interface_traits
"rcl")
target_link_libraries(test_interface_traits ${PROJECT_NAME})
endif()
ament_add_gtest(test_multi_threaded_executor test/executors/test_multi_threaded_executor.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_multi_threaded_executor)
ament_target_dependencies(test_multi_threaded_executor
"rcl")
target_link_libraries(test_multi_threaded_executor ${PROJECT_NAME})
endif()
ament_add_gtest(test_guard_condition test/test_guard_condition.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_guard_condition)
target_link_libraries(test_guard_condition ${PROJECT_NAME})
endif()
ament_add_gtest(test_wait_set test/test_wait_set.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_wait_set)
ament_target_dependencies(test_wait_set "test_msgs")
target_link_libraries(test_wait_set ${PROJECT_NAME})
endif()
ament_add_gtest(test_subscription_topic_statistics test/topic_statistics/test_subscription_topic_statistics.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}"
)
if(TARGET test_subscription_topic_statistics)
ament_target_dependencies(test_subscription_topic_statistics
"builtin_interfaces"
"libstatistics_collector"
"rcl_interfaces"
"rcutils"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"statistics_msgs"
"test_msgs")
rosidl_target_interfaces(test_subscription_topic_statistics ${PROJECT_NAME}_test_msgs "rosidl_typesupport_cpp")
target_link_libraries(test_subscription_topic_statistics ${PROJECT_NAME})
endif()
ament_add_gtest(test_subscription_options test/test_subscription_options.cpp)
if(TARGET test_subscription_options)
ament_target_dependencies(test_subscription_options "rcl")
target_link_libraries(test_subscription_options ${PROJECT_NAME})
endif()
# Install test resources
install(
DIRECTORY test/resources
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/test)
add_subdirectory(test)
endif()
ament_package()

View File

@@ -1,8 +1,8 @@
This document is a declaration of software quality for the `rclcpp` package, based on the guidelines in [REP-2004](https://www.ros.org/reps/rep-2004.html).
# `rclcpp` Quality Declaration
# rclcpp Quality Declaration
The package `rclcpp` claims to be in the **Quality Level 4** category.
The package `rclcpp` claims to be in the **Quality Level 3** category.
Below are the rationales, notes, and caveats for this claim, organized by each requirement listed in the [Package Quality Categories in REP-2004](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#package-quality-categories) of the ROS2 developer guide.
@@ -10,7 +10,7 @@ Below are the rationales, notes, and caveats for this claim, organized by each r
### Version Scheme [1.i]
`rclcpp` uses `semver` according to the recommendation for ROS Core packages in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#versioning)
`rclcpp` uses `semver` according to the recommendation for ROS Core packages in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#versioning).
### Version Stability [1.ii]
@@ -76,19 +76,19 @@ All pull requests must resolve related documentation changes before merging.
### Public API Documentation [3.ii]
The API is publicly available in the [ROS 2 API documentation](http://docs.ros2.org/latest/api/rclcpp/).
The API is publicly available in its [ROS 2 API documentation](http://docs.ros2.org/latest/api/rclcpp/).
### License [3.iii]
The license for `rclcpp` is Apache 2.0, and a summary is in each source file, the type is declared in the [`package.xml`](./package.xml) manifest file, and a full copy of the license is in the [`LICENSE`](../LICENSE) file.
There is an automated test which runs a linter that ensures each file has a license statement. [Here](http://build.ros2.org/view/Epr/job/Epr__rclcpp__ubuntu_bionic_amd64/lastBuild/testReport/rclcpp/) can be found a list with the latest results of the various linters being run on the package.
There is an automated test which runs a linter that ensures each file has a license statement. [Here](http://build.ros2.org/view/Fpr/job/Fpr__rclcpp__ubuntu_focal_amd64/lastSuccessfulBuild/testReport/rclcpp/) can be found a list with the latest results of the various linters being run on the package.
### Copyright Statements [3.iv]
The copyright holders each provide a statement of copyright in each source code file in `rclcpp`.
There is an automated test which runs a linter that ensures each file has at least one copyright statement. Latest linter result report can be seen [here](http://build.ros2.org/view/Epr/job/Epr__rclcpp__ubuntu_bionic_amd64/lastBuild/testReport/rclcpp/copyright/).
There is an automated test which runs a linter that ensures each file has at least one copyright statement. Latest linter result report can be seen [here](http://build.ros2.org/view/Fpr/job/Fpr__rclcpp__ubuntu_focal_amd64/lastSuccessfulBuild/testReport/rclcpp/copyright/).
## Testing [4]
@@ -121,6 +121,8 @@ This includes:
Changes are required to make a best effort to keep or increase coverage before being accepted, but decreases are allowed if properly justified and accepted by reviewers.
Current coverage statistics can be viewed [here](https://ci.ros2.org/job/nightly_linux_coverage/lastSuccessfulBuild/cobertura/src_ros2_rclcpp_rclcpp_src_rclcpp/). A description of how coverage statistics are calculated is summarized in this page ["ROS 2 Onboarding Guide"](https://index.ros.org/doc/ros2/Contributing/ROS-2-On-boarding-Guide/#note-on-coverage-runs).
### Performance [4.iv]
It is not yet defined if this package requires performance testing and how addresses this topic.
@@ -151,49 +153,49 @@ It also has several test dependencies, which do not affect the resulting quality
The `libstatistics_collector` package provides lightweight aggregation utilities to collect statistics and measure message metrics.
It is **Quality Level 4**, see its [Quality Declaration document](https://github.com/ros-tooling/libstatistics_collector/tree/master/QUALITY_DECLARATION.md).
It is **Quality Level 3**, see its [Quality Declaration document](https://github.com/ros-tooling/libstatistics_collector/tree/master/QUALITY_DECLARATION.md).
#### `rcl`
`rcl` a library to support implementation of language specific ROS 2 Client Libraries.
It is **Quality Level 4**, see its [Quality Declaration document](https://github.com/ros2/rcl/blob/master/rcl/QUALITY_DECLARATION.md).
It is **Quality Level 3**, see its [Quality Declaration document](https://github.com/ros2/rcl/blob/master/rcl/QUALITY_DECLARATION.md).
#### `rcl_yaml_param_parser`
The `rcl_yaml_param_parser` package provides an API that is used to parse YAML configuration files which may be used to configure ROS and specific nodes.
It is **Quality Level 4**, see its [Quality Declaration document](https://github.com/ros2/rcl/tree/master/rcl_yaml_param_parser/QUALITY_DECLARATION.md).
It is **Quality Level 3**, see its [Quality Declaration document](https://github.com/ros2/rcl/tree/master/rcl_yaml_param_parser/QUALITY_DECLARATION.md).
#### `rcpputils`
The `rcpputils` package provides an API which contains common utilities and data structures useful when programming in C++.
It is **Quality Level 4**, see its [Quality Declaration document](https://github.com/ros2/rcpputils/blob/master/QUALITY_DECLARATION.md).
It is **Quality Level 2**, see its [Quality Declaration document](https://github.com/ros2/rcpputils/blob/master/QUALITY_DECLARATION.md).
#### `rcutils`
The `rcutils` package provides an API which contains common utilities and data structures useful when programming in C.
It is **Quality Level 4**, see its [Quality Declaration document](https://github.com/ros2/rcutils/blob/master/QUALITY_DECLARATION.md).
It is **Quality Level 2**, see its [Quality Declaration document](https://github.com/ros2/rcutils/blob/master/QUALITY_DECLARATION.md).
#### `rmw`
`rmw` is the ROS 2 middleware library.
It is **Quality Level 4**, see its [Quality Declaration document](https://github.com/ros2/rmw/blob/master/rmw/QUALITY_DECLARATION.md).
It is **Quality Level 2**, see its [Quality Declaration document](https://github.com/ros2/rmw/blob/master/rmw/QUALITY_DECLARATION.md).
#### `statistics_msgs`
The `statistics_msgs` package contains ROS 2 message definitions for reporting statistics for topics and system resources.
It is **Quality Level 4**, see its [Quality Declaration document](https://github.com/ros2/rcl_interfaces/blob/master/statistics_msgs/QUALITY_DECLARATION.md).
It is **Quality Level 3**, see its [Quality Declaration document](https://github.com/ros2/rcl_interfaces/blob/master/statistics_msgs/QUALITY_DECLARATION.md).
#### `tracetools`
The `tracetools` package provides utilities for instrumenting the code in `rcl` so that it may be traced for debugging and performance analysis.
The `tracetools` package provides utilities for instrumenting the code in `rclcpp` so that it may be traced for debugging and performance analysis.
It is **Quality Level 4**, see its [Quality Declaration document](https://gitlab.com/micro-ROS/ros_tracing/ros2_tracing/-/blob/master/tracetools/QUALITY_DECLARATION.md).
It is **Quality Level 2**, see its [Quality Declaration document](https://gitlab.com/micro-ROS/ros_tracing/ros2_tracing/-/blob/master/tracetools/QUALITY_DECLARATION.md).
### Direct Runtime non-ROS Dependency [5.iii]

View File

@@ -6,4 +6,4 @@ Visit the [rclcpp API documentation](http://docs.ros2.org/latest/api/rclcpp/) fo
## Quality Declaration
This package claims to be in the **Quality Level 4** category, see the [Quality Declaration](QUALITY_DECLARATION.md) for more details.
This package claims to be in the **Quality Level 3** category, see the [Quality Declaration](QUALITY_DECLARATION.md) for more details.

View File

@@ -361,7 +361,8 @@ public:
SharedPromiseWithRequest promise = std::make_shared<PromiseWithRequest>();
SharedFutureWithRequest future_with_request(promise->get_future());
auto wrapping_cb = [future_with_request, promise, request, &cb](SharedFuture future) {
auto wrapping_cb = [future_with_request, promise, request,
cb = std::forward<CallbackWithRequestType>(cb)](SharedFuture future) {
auto response = future.get();
promise->set_value(std::make_pair(request, response));
cb(future_with_request);

View File

@@ -115,9 +115,9 @@ public:
*
* Function is only applicable if the clock_type is `RCL_ROS_TIME`
*
* \param pre_callback. Must be non-throwing
* \param post_callback. Must be non-throwing.
* \param threshold. Callbacks will be triggered if the time jump is greater
* \param pre_callback Must be non-throwing
* \param post_callback Must be non-throwing.
* \param threshold Callbacks will be triggered if the time jump is greater
* then the threshold.
* \throws anything rclcpp::exceptions::throw_from_rcl_error can throw.
* \throws std::bad_alloc if the allocation of the JumpHandler fails.

View File

@@ -18,6 +18,7 @@
#include <chrono>
#include <functional>
#include <memory>
#include <stdexcept>
#include <string>
#include <utility>
@@ -28,6 +29,7 @@
#include "rclcpp/node_interfaces/node_timers_interface.hpp"
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
#include "rclcpp/create_publisher.hpp"
#include "rclcpp/create_timer.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/subscription_factory.hpp"
@@ -44,6 +46,23 @@ namespace rclcpp
* The NodeT type only needs to have a method called get_node_topics_interface()
* which returns a shared_ptr to a NodeTopicsInterface, or be a
* NodeTopicsInterface pointer itself.
*
* \tparam MessageT
* \tparam CallbackT
* \tparam AllocatorT
* \tparam CallbackMessageT
* \tparam SubscriptionT
* \tparam MessageMemoryStrategyT
* \tparam NodeT
* \param node
* \param topic_name
* \param qos
* \param callback
* \param options
* \param msg_mem_strat
* \return the created subscription
* \throws std::invalid_argument if topic statistics is enabled and the publish period is
* less than or equal to zero.
*/
template<
typename MessageT,
@@ -81,6 +100,13 @@ create_subscription(
options,
*node_topics->get_node_base_interface()))
{
if (options.topic_stats_options.publish_period <= std::chrono::milliseconds(0)) {
throw std::invalid_argument(
"topic_stats_options.publish_period must be greater than 0, specified value of " +
std::to_string(options.topic_stats_options.publish_period.count()) +
" ms");
}
std::shared_ptr<Publisher<statistics_msgs::msg::MetricsMessage>> publisher =
create_publisher<statistics_msgs::msg::MetricsMessage>(
node,

View File

@@ -76,14 +76,14 @@ create_timer(
* \tparam DurationRepT
* \tparam DurationT
* \tparam CallbackT
* \param period period to exectute callback
* \param period period to execute callback. This duration must be 0 <= period < nanoseconds::max()
* \param callback callback to execute via the timer period
* \param group
* \param node_base
* \param node_timers
* \return
* \throws std::invalid argument if either node_base or node_timers
* are null
* are null, or period is negative or too large
*/
template<typename DurationRepT, typename DurationT, typename CallbackT>
typename rclcpp::WallTimer<CallbackT>::SharedPtr
@@ -102,10 +102,38 @@ create_wall_timer(
throw std::invalid_argument{"input node_timers cannot be null"};
}
if (period < std::chrono::duration<DurationRepT, DurationT>::zero()) {
throw std::invalid_argument{"timer period cannot be negative"};
}
// Casting to a double representation might lose precision and allow the check below to succeed
// but the actual cast to nanoseconds fail. Using 1 DurationT worth of nanoseconds less than max.
constexpr auto maximum_safe_cast_ns =
std::chrono::nanoseconds::max() - std::chrono::duration<DurationRepT, DurationT>(1);
// If period is greater than nanoseconds::max(), the duration_cast to nanoseconds will overflow
// a signed integer, which is undefined behavior. Checking whether any std::chrono::duration is
// greater than nanoseconds::max() is a difficult general problem. This is a more conservative
// version of Howard Hinnant's (the <chrono> guy>) response here:
// https://stackoverflow.com/a/44637334/2089061
// However, this doesn't solve the issue for all possible duration types of period.
// Follow-up issue: https://github.com/ros2/rclcpp/issues/1177
constexpr auto ns_max_as_double =
std::chrono::duration_cast<std::chrono::duration<double, std::chrono::nanoseconds::period>>(
maximum_safe_cast_ns);
if (period > ns_max_as_double) {
throw std::invalid_argument{
"timer period must be less than std::chrono::nanoseconds::max()"};
}
const auto period_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(period);
if (period_ns < std::chrono::nanoseconds::zero()) {
throw std::runtime_error{
"Casting timer period to nanoseconds resulted in integer overflow."};
}
auto timer = rclcpp::WallTimer<CallbackT>::make_shared(
std::chrono::duration_cast<std::chrono::nanoseconds>(period),
std::move(callback),
node_base->get_context());
period_ns, std::move(callback), node_base->get_context());
node_timers->add_timer(timer, group);
return timer;
}

View File

@@ -72,7 +72,7 @@ public:
operator=(const Duration & rhs);
Duration &
operator=(const builtin_interfaces::msg::Duration & Duration_msg);
operator=(const builtin_interfaces::msg::Duration & duration_msg);
bool
operator==(const rclcpp::Duration & rhs) const;

View File

@@ -37,6 +37,7 @@
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/utilities.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rclcpp/scope_exit.hpp"
namespace rclcpp
{
@@ -159,7 +160,7 @@ public:
void
spin_node_some(std::shared_ptr<rclcpp::Node> node);
/// Complete all available queued work without blocking.
/// Collect work once and execute all available work, optionally within a duration.
/**
* This function can be overridden. The default implementation is suitable for a
* single-threaded model of execution.
@@ -174,6 +175,23 @@ public:
virtual void
spin_some(std::chrono::nanoseconds max_duration = std::chrono::nanoseconds(0));
/// Collect and execute work repeatedly within a duration or until no more work is available.
/**
* This function can be overridden. The default implementation is suitable for a
* single-threaded model of execution.
* Adding subscriptions, timers, services, etc. with blocking callbacks will cause this function
* to block (which may have unintended consequences).
* If the time that waitables take to be executed is longer than the period on which new waitables
* become ready, this method will execute work repeatedly until `max_duration` has elapsed.
*
* \param[in] max_duration The maximum amount of time to spend executing work. Must be positive.
* Note that spin_all() may take longer than this time as it only returns once max_duration has
* been exceeded.
*/
RCLCPP_PUBLIC
virtual void
spin_all(std::chrono::nanoseconds max_duration);
RCLCPP_PUBLIC
virtual void
spin_once(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));
@@ -188,10 +206,10 @@ public:
* code.
* \return The return code, one of `SUCCESS`, `INTERRUPTED`, or `TIMEOUT`.
*/
template<typename ResponseT, typename TimeRepT = int64_t, typename TimeT = std::milli>
template<typename FutureT, typename TimeRepT = int64_t, typename TimeT = std::milli>
FutureReturnCode
spin_until_future_complete(
const std::shared_future<ResponseT> & future,
const FutureT & future,
std::chrono::duration<TimeRepT, TimeT> timeout = std::chrono::duration<TimeRepT, TimeT>(-1))
{
// TODO(wjwwood): does not work recursively; can't call spin_node_until_future_complete
@@ -212,9 +230,14 @@ public:
}
std::chrono::nanoseconds timeout_left = timeout_ns;
while (rclcpp::ok(this->context_)) {
if (spinning.exchange(true)) {
throw std::runtime_error("spin_until_future_complete() called while already spinning");
}
RCLCPP_SCOPE_EXIT(this->spinning.store(false); );
while (rclcpp::ok(this->context_) && spinning.load()) {
// Do one item of work.
spin_once(timeout_left);
spin_once_impl(timeout_left);
// Check if the future is set, return SUCCESS if it is.
status = future.wait_for(std::chrono::seconds(0));
if (status == std::future_status::ready) {
@@ -264,6 +287,10 @@ protected:
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node,
std::chrono::nanoseconds timeout);
RCLCPP_PUBLIC
void
spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive);
/// Find the next available executable and do the work associated with it.
/**
* \param[in] any_exec Union structure that can hold any executable type (timer, subscription,
@@ -336,6 +363,10 @@ protected:
RCLCPP_DISABLE_COPY(Executor)
RCLCPP_PUBLIC
void
spin_once_impl(std::chrono::nanoseconds timeout);
std::list<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr> weak_nodes_;
std::list<const rcl_guard_condition_t *> guard_conditions_;
};

View File

@@ -66,12 +66,12 @@ using rclcpp::executors::SingleThreadedExecutor;
* If the time spent inside the blocking loop exceeds this timeout, return a `TIMEOUT` return code.
* \return The return code, one of `SUCCESS`, `INTERRUPTED`, or `TIMEOUT`.
*/
template<typename ResponseT, typename TimeRepT = int64_t, typename TimeT = std::milli>
template<typename FutureT, typename TimeRepT = int64_t, typename TimeT = std::milli>
rclcpp::FutureReturnCode
spin_node_until_future_complete(
rclcpp::Executor & executor,
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
const std::shared_future<ResponseT> & future,
const FutureT & future,
std::chrono::duration<TimeRepT, TimeT> timeout = std::chrono::duration<TimeRepT, TimeT>(-1))
{
// TODO(wjwwood): does not work recursively; can't call spin_node_until_future_complete
@@ -82,13 +82,13 @@ spin_node_until_future_complete(
return retcode;
}
template<typename NodeT = rclcpp::Node, typename ResponseT, typename TimeRepT = int64_t,
template<typename NodeT = rclcpp::Node, typename FutureT, typename TimeRepT = int64_t,
typename TimeT = std::milli>
rclcpp::FutureReturnCode
spin_node_until_future_complete(
rclcpp::Executor & executor,
std::shared_ptr<NodeT> node_ptr,
const std::shared_future<ResponseT> & future,
const FutureT & future,
std::chrono::duration<TimeRepT, TimeT> timeout = std::chrono::duration<TimeRepT, TimeT>(-1))
{
return rclcpp::executors::spin_node_until_future_complete(
@@ -104,7 +104,7 @@ template<typename FutureT, typename TimeRepT = int64_t, typename TimeT = std::mi
rclcpp::FutureReturnCode
spin_until_future_complete(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
const std::shared_future<FutureT> & future,
const FutureT & future,
std::chrono::duration<TimeRepT, TimeT> timeout = std::chrono::duration<TimeRepT, TimeT>(-1))
{
rclcpp::executors::SingleThreadedExecutor executor;
@@ -116,7 +116,7 @@ template<typename NodeT = rclcpp::Node, typename FutureT, typename TimeRepT = in
rclcpp::FutureReturnCode
spin_until_future_complete(
std::shared_ptr<NodeT> node_ptr,
const std::shared_future<FutureT> & future,
const FutureT & future,
std::chrono::duration<TimeRepT, TimeT> timeout = std::chrono::duration<TimeRepT, TimeT>(-1))
{
return rclcpp::spin_until_future_complete(node_ptr->get_node_base_interface(), future, timeout);

View File

@@ -49,6 +49,7 @@ public:
* \param number_of_threads number of threads to have in the thread pool,
* the default 0 will use the number of cpu cores found instead
* \param yield_before_execute if true std::this_thread::yield() is called
* \param timeout maximum time to wait
*/
RCLCPP_PUBLIC
MultiThreadedExecutor(

View File

@@ -143,10 +143,10 @@ public:
* exec.add_node(node);
* exec.spin_until_future_complete(future);
*/
template<typename ResponseT, typename TimeRepT = int64_t, typename TimeT = std::milli>
template<typename FutureT, typename TimeRepT = int64_t, typename TimeT = std::milli>
rclcpp::FutureReturnCode
spin_until_future_complete(
std::shared_future<ResponseT> & future,
FutureT & future,
std::chrono::duration<TimeRepT, TimeT> timeout = std::chrono::duration<TimeRepT, TimeT>(-1))
{
std::future_status status = future.wait_for(std::chrono::seconds(0));

View File

@@ -235,7 +235,7 @@ public:
/// Create and return a Client.
/**
* \param[in] service_name The topic to service on.
* \param[in] rmw_qos_profile_t Quality of service profile for client.
* \param[in] qos_profile rmw_qos_profile_t Quality of service profile for client.
* \param[in] group Callback group to call the service.
* \return Shared pointer to the created client.
*/
@@ -250,7 +250,7 @@ public:
/**
* \param[in] service_name The topic to service on.
* \param[in] callback User-defined callback function.
* \param[in] rmw_qos_profile_t Quality of service profile for client.
* \param[in] qos_profile rmw_qos_profile_t Quality of service profile for client.
* \param[in] group Callback group to call the service.
* \return Shared pointer to the created service.
*/
@@ -842,26 +842,6 @@ public:
void
remove_on_set_parameters_callback(const OnSetParametersCallbackHandle * const handler);
/// Register a callback to be called anytime a parameter is about to be changed.
/**
* \deprecated Use add_on_set_parameters_callback instead.
* With this method, only one callback can be set at a time. The callback that was previously
* set by this method is returned or `nullptr` if no callback was previously set.
*
* The callbacks added with `add_on_set_parameters_callback` are stored in a different place.
* `remove_on_set_parameters_callback` can't be used with the callbacks registered with this
* method. For removing it, use `set_on_parameters_set_callback(nullptr)`.
*
* \param[in] callback The callback to be called when the value for a
* parameter is about to be set.
* \return The previous callback that was registered, if there was one,
* otherwise nullptr.
*/
[[deprecated("use add_on_set_parameters_callback(OnParametersSetCallbackType callback) instead")]]
RCLCPP_PUBLIC
OnParametersSetCallbackType
set_on_parameters_set_callback(rclcpp::Node::OnParametersSetCallbackType callback);
/// Get the fully-qualified names of all available nodes.
/**
* The fully-qualified name includes the local namespace and name of the node.
@@ -891,7 +871,8 @@ public:
/// Return the number of publishers that are advertised on a given topic.
/**
* \param[in] topic_name the topic_name on which to count the publishers.
* \param[in] node_name the node_name on which to count the publishers.
* \param[in] namespace_ the namespace of the node associated with the name
* \return number of publishers that are advertised on a given topic.
* \throws std::runtime_error if publishers could not be counted
*/
@@ -1062,7 +1043,7 @@ public:
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr
get_node_parameters_interface();
/// Return the Node's internal NodeParametersInterface implementation.
/// Return the Node's internal NodeTimeSourceInterface implementation.
RCLCPP_PUBLIC
rclcpp::node_interfaces::NodeTimeSourceInterface::SharedPtr
get_node_time_source_interface();

View File

@@ -167,11 +167,6 @@ public:
void
remove_on_set_parameters_callback(const OnSetParametersCallbackHandle * const handler) override;
[[deprecated("use add_on_set_parameters_callback(OnParametersSetCallbackType callback) instead")]]
RCLCPP_PUBLIC
OnParametersSetCallbackType
set_on_parameters_set_callback(OnParametersSetCallbackType callback) override;
RCLCPP_PUBLIC
const std::map<std::string, rclcpp::ParameterValue> &
get_parameter_overrides() const override;

View File

@@ -191,17 +191,6 @@ public:
void
remove_on_set_parameters_callback(const OnSetParametersCallbackHandle * const handler) = 0;
/// Register a callback for when parameters are being set, return an existing one.
/**
* \deprecated Use add_on_set_parameters_callback instead.
* \sa rclcpp::Node::set_on_parameters_set_callback
*/
[[deprecated("use add_on_set_parameters_callback(OnParametersSetCallbackType callback) instead")]]
RCLCPP_PUBLIC
virtual
OnParametersSetCallbackType
set_on_parameters_set_callback(OnParametersSetCallbackType callback) = 0;
/// Return the initial parameter values used by the NodeParameters to override default values.
RCLCPP_PUBLIC
virtual

View File

@@ -327,11 +327,6 @@ public:
NodeOptions &
allocator(rcl_allocator_t allocator);
protected:
/// Retrieve the ROS_DOMAIN_ID environment variable and populate options.
size_t
get_domain_id_from_env() const;
private:
// This is mutable to allow for a const accessor which lazily creates the node options instance.
/// Underlying rcl_node_options structure.

View File

@@ -48,13 +48,13 @@ public:
/// Create an async parameters client.
/**
* \param node_base_interface[in] The node base interface of the corresponding node.
* \param node_topics_interface[in] Node topic base interface.
* \param node_graph_interface[in] The node graph interface of the corresponding node.
* \param node_services_interface[in] Node service interface.
* \param remote_node_name[in] (optional) name of the remote node
* \param qos_profile[in] (optional) The rmw qos profile to use to subscribe
* \param group[in] (optional) The async parameter client will be added to this callback group.
* \param[in] node_base_interface The node base interface of the corresponding node.
* \param[in] node_topics_interface Node topic base interface.
* \param[in] node_graph_interface The node graph interface of the corresponding node.
* \param[in] node_services_interface Node service interface.
* \param[in] remote_node_name (optional) name of the remote node
* \param[in] qos_profile (optional) The rmw qos profile to use to subscribe
* \param[in] group (optional) The async parameter client will be added to this callback group.
*/
RCLCPP_PUBLIC
AsyncParametersClient(
@@ -68,10 +68,10 @@ public:
/// Constructor
/**
* \param node[in] The async paramters client will be added to this node.
* \param remote_node_name[in] (optional) name of the remote node
* \param qos_profile[in] (optional) The rmw qos profile to use to subscribe
* \param group[in] (optional) The async parameter client will be added to this callback group.
* \param[in] node The async paramters client will be added to this node.
* \param[in] remote_node_name (optional) name of the remote node
* \param[in] qos_profile (optional) The rmw qos profile to use to subscribe
* \param[in] group (optional) The async parameter client will be added to this callback group.
*/
RCLCPP_PUBLIC
AsyncParametersClient(
@@ -82,10 +82,10 @@ public:
/// Constructor
/**
* \param node[in] The async paramters client will be added to this node.
* \param remote_node_name[in] (optional) name of the remote node
* \param qos_profile[in] (optional) The rmw qos profile to use to subscribe
* \param group[in] (optional) The async parameter client will be added to this callback group.
* \param[in] node The async paramters client will be added to this node.
* \param[in] remote_node_name (optional) name of the remote node
* \param[in] qos_profile (optional) The rmw qos profile to use to subscribe
* \param[in] group (optional) The async parameter client will be added to this callback group.
*/
RCLCPP_PUBLIC
AsyncParametersClient(

View File

@@ -68,7 +68,7 @@ public:
* \param[in] node_base NodeBaseInterface pointer that is used in part of the setup.
* \param[in] topic Name of the topic to publish to.
* \param[in] qos QoS profile for Subcription.
* \param[in] options options for the subscription.
* \param[in] options Options for the subscription.
*/
Publisher(
rclcpp::node_interfaces::NodeBaseInterface * node_base,

View File

@@ -34,6 +34,7 @@ using QOSDeadlineRequestedInfo = rmw_requested_deadline_missed_status_t;
using QOSDeadlineOfferedInfo = rmw_offered_deadline_missed_status_t;
using QOSLivelinessChangedInfo = rmw_liveliness_changed_status_t;
using QOSLivelinessLostInfo = rmw_liveliness_lost_status_t;
using QOSMessageLostInfo = rmw_message_lost_status_t;
using QOSOfferedIncompatibleQoSInfo = rmw_offered_qos_incompatible_event_status_t;
using QOSRequestedIncompatibleQoSInfo = rmw_requested_qos_incompatible_event_status_t;
@@ -41,6 +42,7 @@ using QOSDeadlineRequestedCallbackType = std::function<void (QOSDeadlineRequeste
using QOSDeadlineOfferedCallbackType = std::function<void (QOSDeadlineOfferedInfo &)>;
using QOSLivelinessChangedCallbackType = std::function<void (QOSLivelinessChangedInfo &)>;
using QOSLivelinessLostCallbackType = std::function<void (QOSLivelinessLostInfo &)>;
using QOSMessageLostCallbackType = std::function<void (QOSMessageLostInfo &)>;
using QOSOfferedIncompatibleQoSCallbackType = std::function<void (QOSOfferedIncompatibleQoSInfo &)>;
using QOSRequestedIncompatibleQoSCallbackType =
std::function<void (QOSRequestedIncompatibleQoSInfo &)>;
@@ -59,6 +61,7 @@ struct SubscriptionEventCallbacks
QOSDeadlineRequestedCallbackType deadline_callback;
QOSLivelinessChangedCallbackType liveliness_callback;
QOSRequestedIncompatibleQoSCallbackType incompatible_qos_callback;
QOSMessageLostCallbackType message_lost_callback;
};
class UnsupportedEventTypeException : public exceptions::RCLErrorBase, public std::runtime_error

View File

@@ -60,7 +60,7 @@ public:
/// Serialize a ROS2 message to a serialized stream
/**
* \param[in] message The ROS2 message which is read and serialized by rmw.
* \param[in] ros_message The ROS2 message which is read and serialized by rmw.
* \param[out] serialized_message The serialized message.
*/
void serialize_message(
@@ -69,7 +69,7 @@ public:
/// Deserialize a serialized stream to a ROS message
/**
* \param[in] serialized_message The serialized message to be converted to ROS2 by rmw.
* \param[out] message The deserialized ROS2 message.
* \param[out] ros_message The deserialized ROS2 message.
*/
void deserialize_message(
const SerializedMessage * serialized_message, void * ros_message) const;

View File

@@ -237,7 +237,7 @@ public:
* rclcpp::create_service().
*
* \param[in] node_handle NodeBaseInterface pointer that is used in part of the setup.
* \param[in] service_name Name of the topic to publish to.
* \param[in] service_handle service handle.
* \param[in] any_callback User defined callback to call when a client request is received.
*/
Service(
@@ -272,7 +272,7 @@ public:
* rclcpp::create_service().
*
* \param[in] node_handle NodeBaseInterface pointer that is used in part of the setup.
* \param[in] service_name Name of the topic to publish to.
* \param[in] service_handle service handle.
* \param[in] any_callback User defined callback to call when a client request is received.
*/
Service(

View File

@@ -92,7 +92,7 @@ public:
* \param[in] topic_name Name of the topic to subscribe to.
* \param[in] qos QoS profile for Subcription.
* \param[in] callback User defined callback to call when a message is received.
* \param[in] options options for the subscription.
* \param[in] options Options for the subscription.
* \param[in] message_memory_strategy The memory strategy to be used for managing message memory.
* \param[in] subscription_topic_statistics Optional pointer to a topic statistics subcription.
* \throws std::invalid_argument if the QoS is uncompatible with intra-process (if one
@@ -144,6 +144,11 @@ public:
// pass
}
}
if (options.event_callbacks.message_lost_callback) {
this->add_event_handler(
options.event_callbacks.message_lost_callback,
RCL_SUBSCRIPTION_MESSAGE_LOST);
}
// Setup intra process publishing if requested.
if (rclcpp::detail::resolve_use_intra_process(options, *node_base)) {

View File

@@ -66,7 +66,7 @@ public:
* \param[in] node_base NodeBaseInterface pointer used in parts of the setup.
* \param[in] type_support_handle rosidl type support struct, for the Message type of the topic.
* \param[in] topic_name Name of the topic to subscribe to.
* \param[in] subscription_options options for the subscription.
* \param[in] subscription_options Options for the subscription.
* \param[in] is_serialized is true if the message will be delivered still serialized
*/
RCLCPP_PUBLIC

View File

@@ -68,7 +68,7 @@ struct SubscriptionFactory
* \param[in] callback The user-defined callback function to receive a message
* \param[in] options Additional options for the creation of the Subscription.
* \param[in] msg_mem_strat The message memory strategy to use for allocating messages.
* \param[in] subscription_topic_Optinal stats callback for topic_statistics
* \param[in] subscription_topic_stats Optional stats callback for topic_statistics
*/
template<
typename MessageT,

View File

@@ -66,7 +66,8 @@ struct SubscriptionOptionsBase
// Topic to which topic statistics get published when enabled. Defaults to /statistics.
std::string publish_topic = "/statistics";
// Topic statistics publication period in ms. Defaults to one minute.
// Topic statistics publication period in ms. Defaults to one second.
// Only values greater than zero are allowed.
std::chrono::milliseconds publish_period{std::chrono::seconds(1)};
};

View File

@@ -51,7 +51,7 @@ public:
* \param clock_type clock type
*/
RCLCPP_PUBLIC
explicit Time(int64_t nanoseconds = 0, rcl_clock_type_t clock = RCL_SYSTEM_TIME);
explicit Time(int64_t nanoseconds = 0, rcl_clock_type_t clock_type = RCL_SYSTEM_TIME);
/// Copy constructor
RCLCPP_PUBLIC
@@ -66,12 +66,11 @@ public:
RCLCPP_PUBLIC
Time(
const builtin_interfaces::msg::Time & time_msg,
rcl_clock_type_t ros_time = RCL_ROS_TIME);
rcl_clock_type_t clock_type = RCL_ROS_TIME);
/// Time constructor
/**
* \param time_point rcl_time_point_t structure to copy
* \param clock_type clock type
*/
RCLCPP_PUBLIC
explicit Time(const rcl_time_point_t & time_point);
@@ -91,6 +90,12 @@ public:
Time &
operator=(const Time & rhs);
/**
* Assign Time from a builtin_interfaces::msg::Time instance.
* The clock_type will be reset to RCL_ROS_TIME.
* Equivalent to *this = Time(time_msg, RCL_ROS_TIME).
* \throws std::runtime_error if seconds are negative
*/
RCLCPP_PUBLIC
Time &
operator=(const builtin_interfaces::msg::Time & time_msg);

View File

@@ -166,6 +166,7 @@ public:
* \param[in] clock The clock providing the current time.
* \param[in] period The interval at which the timer fires.
* \param[in] callback User-specified callback function.
* \param[in] context custom context to be used.
*/
explicit GenericTimer(
Clock::SharedPtr clock, std::chrono::nanoseconds period, FunctorT && callback,

View File

@@ -116,7 +116,7 @@ public:
/// Set the timer used to publish statistics messages.
/**
* \param measurement_timer the timer to fire the publisher, created by the node
* \param publisher_timer the timer to fire the publisher, created by the node
*/
void set_publisher_timer(rclcpp::TimerBase::SharedPtr publisher_timer)
{

View File

@@ -61,6 +61,8 @@ public:
* \param[in] subscriptions Vector of subscriptions to be added.
* \param[in] guard_conditions Vector of guard conditions to be added.
* \param[in] timers Vector of timers to be added.
* \param[in] clients Vector of clients and their associated entity to be added.
* \param[in] services Vector of services and their associated entity to be added.
* \param[in] waitables Vector of waitables and their associated entity to be added.
* \param[in] context Custom context to be used, defaults to global default.
* \throws std::invalid_argument If context is nullptr.

View File

@@ -123,7 +123,7 @@ public:
RCLCPP_PUBLIC
virtual
bool
is_ready(rcl_wait_set_t *) = 0;
is_ready(rcl_wait_set_t * wait_set) = 0;
/// Execute any entities of the Waitable that are ready.
/**

View File

@@ -2,7 +2,7 @@
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
<name>rclcpp</name>
<version>2.0.0</version>
<version>4.0.0</version>
<description>The ROS client library in C++.</description>
<maintainer email="dthomas@osrfoundation.org">Dirk Thomas</maintainer>
<license>Apache License 2.0</license>

View File

@@ -32,7 +32,7 @@ public:
{
rcl_ret_t ret = rcl_clock_init(clock_type, &rcl_clock_, &allocator_);
if (ret != RCL_RET_OK) {
exceptions::throw_from_rcl_error(ret, "could not get current time stamp");
exceptions::throw_from_rcl_error(ret, "failed to initialize rcl clock");
}
}

View File

@@ -47,17 +47,14 @@ Duration::Duration(std::chrono::nanoseconds nanoseconds)
rcl_duration_.nanoseconds = nanoseconds.count();
}
Duration::Duration(const Duration & rhs)
{
rcl_duration_.nanoseconds = rhs.rcl_duration_.nanoseconds;
}
Duration::Duration(const Duration & rhs) = default;
Duration::Duration(
const builtin_interfaces::msg::Duration & duration_msg)
{
rcl_duration_.nanoseconds =
static_cast<rcl_duration_value_t>(RCL_S_TO_NS(duration_msg.sec));
rcl_duration_.nanoseconds += duration_msg.nanosec;
RCL_S_TO_NS(static_cast<rcl_duration_value_t>(duration_msg.sec));
rcl_duration_.nanoseconds += static_cast<rcl_duration_value_t>(duration_msg.nanosec);
}
Duration::Duration(const rcl_duration_t & duration)
@@ -69,24 +66,25 @@ Duration::Duration(const rcl_duration_t & duration)
Duration::operator builtin_interfaces::msg::Duration() const
{
builtin_interfaces::msg::Duration msg_duration;
msg_duration.sec = static_cast<std::int32_t>(RCL_NS_TO_S(rcl_duration_.nanoseconds));
msg_duration.nanosec =
static_cast<std::uint32_t>(rcl_duration_.nanoseconds % (1000 * 1000 * 1000));
constexpr rcl_duration_value_t kDivisor = RCL_S_TO_NS(1);
const auto result = std::div(rcl_duration_.nanoseconds, kDivisor);
if (result.rem >= 0) {
msg_duration.sec = static_cast<std::int32_t>(result.quot);
msg_duration.nanosec = static_cast<std::uint32_t>(result.rem);
} else {
msg_duration.sec = static_cast<std::int32_t>(result.quot - 1);
msg_duration.nanosec = static_cast<std::uint32_t>(kDivisor + result.rem);
}
return msg_duration;
}
Duration &
Duration::operator=(const Duration & rhs)
{
rcl_duration_.nanoseconds = rhs.rcl_duration_.nanoseconds;
return *this;
}
Duration::operator=(const Duration & rhs) = default;
Duration &
Duration::operator=(const builtin_interfaces::msg::Duration & duration_msg)
{
rcl_duration_.nanoseconds = RCL_S_TO_NS(static_cast<int64_t>(duration_msg.sec));
rcl_duration_.nanoseconds += duration_msg.nanosec;
*this = Duration(duration_msg);
return *this;
}
@@ -230,6 +228,10 @@ Duration::seconds() const
rmw_time_t
Duration::to_rmw_time() const
{
if (rcl_duration_.nanoseconds < 0) {
throw std::runtime_error("rmw_time_t cannot be negative");
}
// reuse conversion logic from msg creation
builtin_interfaces::msg::Duration msg = *this;
rmw_time_t result;

View File

@@ -28,6 +28,8 @@
#include "rcutils/logging_macros.h"
using namespace std::chrono_literals;
using rclcpp::exceptions::throw_from_rcl_error;
using rclcpp::AnyExecutable;
using rclcpp::Executor;
@@ -212,8 +214,21 @@ Executor::spin_node_some(std::shared_ptr<rclcpp::Node> node)
this->spin_node_some(node->get_node_base_interface());
}
void Executor::spin_some(std::chrono::nanoseconds max_duration)
{
return this->spin_some_impl(max_duration, false);
}
void Executor::spin_all(std::chrono::nanoseconds max_duration)
{
if (max_duration <= 0ns) {
throw std::invalid_argument("max_duration must be positive");
}
return this->spin_some_impl(max_duration, true);
}
void
Executor::spin_some(std::chrono::nanoseconds max_duration)
Executor::spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive)
{
auto start = std::chrono::steady_clock::now();
auto max_duration_not_elapsed = [max_duration, start]() {
@@ -232,18 +247,33 @@ Executor::spin_some(std::chrono::nanoseconds max_duration)
throw std::runtime_error("spin_some() called while already spinning");
}
RCLCPP_SCOPE_EXIT(this->spinning.store(false); );
// non-blocking call to pre-load all available work
wait_for_work(std::chrono::milliseconds::zero());
while (spinning.load() && max_duration_not_elapsed()) {
bool work_available = false;
while (rclcpp::ok(context_) && spinning.load() && max_duration_not_elapsed()) {
AnyExecutable any_exec;
if (!work_available) {
wait_for_work(std::chrono::milliseconds::zero());
}
if (get_next_ready_executable(any_exec)) {
execute_any_executable(any_exec);
work_available = true;
} else {
break;
if (!work_available || !exhaustive) {
break;
}
work_available = false;
}
}
}
void
Executor::spin_once_impl(std::chrono::nanoseconds timeout)
{
AnyExecutable any_exec;
if (get_next_executable(any_exec, timeout)) {
execute_any_executable(any_exec);
}
}
void
Executor::spin_once(std::chrono::nanoseconds timeout)
{
@@ -251,10 +281,7 @@ Executor::spin_once(std::chrono::nanoseconds timeout)
throw std::runtime_error("spin_once() called while already spinning");
}
RCLCPP_SCOPE_EXIT(this->spinning.store(false); );
AnyExecutable any_exec;
if (get_next_executable(any_exec, timeout)) {
execute_any_executable(any_exec);
}
spin_once_impl(timeout);
}
void

View File

@@ -328,28 +328,6 @@ Node::remove_on_set_parameters_callback(const OnSetParametersCallbackHandle * co
return node_parameters_->remove_on_set_parameters_callback(callback);
}
// suppress deprecated function warning
#if !defined(_WIN32)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#else // !defined(_WIN32)
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
rclcpp::Node::OnParametersSetCallbackType
Node::set_on_parameters_set_callback(rclcpp::Node::OnParametersSetCallbackType callback)
{
return node_parameters_->set_on_parameters_set_callback(callback);
}
// remove warning suppression
#if !defined(_WIN32)
# pragma GCC diagnostic pop
#else // !defined(_WIN32)
# pragma warning(pop)
#endif
std::vector<std::string>
Node::get_node_names() const
{

View File

@@ -159,7 +159,7 @@ __lockless_has_parameter(
// see https://en.cppreference.com/w/cpp/types/numeric_limits/epsilon
RCLCPP_LOCAL
bool
__are_doubles_equal(double x, double y, size_t ulp = 100)
__are_doubles_equal(double x, double y, double ulp = 100.0)
{
return std::abs(x - y) <= std::numeric_limits<double>::epsilon() * std::abs(x + y) * ulp;
}
@@ -874,18 +874,6 @@ NodeParameters::add_on_set_parameters_callback(OnParametersSetCallbackType callb
return handle;
}
NodeParameters::OnParametersSetCallbackType
NodeParameters::set_on_parameters_set_callback(OnParametersSetCallbackType callback)
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
auto existing_callback = on_parameters_set_callback_;
on_parameters_set_callback_ = callback;
return existing_callback;
}
const std::map<std::string, rclcpp::ParameterValue> &
NodeParameters::get_parameter_overrides() const
{

View File

@@ -79,6 +79,7 @@ NodeOptions::operator=(const NodeOptions & other)
this->allow_undeclared_parameters_ = other.allow_undeclared_parameters_;
this->automatically_declare_parameters_from_overrides_ =
other.automatically_declare_parameters_from_overrides_;
this->node_options_.reset();
}
return *this;
}
@@ -92,7 +93,6 @@ NodeOptions::get_rcl_node_options() const
*node_options_ = rcl_node_get_default_options();
node_options_->allocator = this->allocator_;
node_options_->use_global_arguments = this->use_global_arguments_;
node_options_->domain_id = this->get_domain_id_from_env();
node_options_->enable_rosout = this->enable_rosout_;
int c_argc = 0;
@@ -176,7 +176,7 @@ NodeOptions::parameter_overrides(const std::vector<rclcpp::Parameter> & paramete
bool
NodeOptions::use_global_arguments() const
{
return this->node_options_->use_global_arguments;
return this->use_global_arguments_;
}
NodeOptions &
@@ -322,36 +322,4 @@ NodeOptions::allocator(rcl_allocator_t allocator)
return *this;
}
// TODO(wjwwood): reuse rcutils_get_env() to avoid code duplication.
// See also: https://github.com/ros2/rcl/issues/119
size_t
NodeOptions::get_domain_id_from_env() const
{
// Determine the domain id based on the options and the ROS_DOMAIN_ID env variable.
size_t domain_id = std::numeric_limits<size_t>::max();
char * ros_domain_id = nullptr;
const char * env_var = "ROS_DOMAIN_ID";
#ifndef _WIN32
ros_domain_id = getenv(env_var);
#else
size_t ros_domain_id_size;
_dupenv_s(&ros_domain_id, &ros_domain_id_size, env_var);
#endif
if (ros_domain_id) {
uint32_t number = strtoul(ros_domain_id, NULL, 0);
if (number == (std::numeric_limits<uint32_t>::max)()) {
#ifdef _WIN32
// free the ros_domain_id before throwing, if getenv was used on Windows
free(ros_domain_id);
#endif
throw std::runtime_error("failed to interpret ROS_DOMAIN_ID as integral number");
}
domain_id = static_cast<size_t>(number);
#ifdef _WIN32
free(ros_domain_id);
#endif
}
return domain_id;
}
} // namespace rclcpp

View File

@@ -63,17 +63,13 @@ Time::Time(int64_t nanoseconds, rcl_clock_type_t clock_type)
rcl_time_.nanoseconds = nanoseconds;
}
Time::Time(const Time & rhs)
: rcl_time_(rhs.rcl_time_)
{
rcl_time_.nanoseconds = rhs.rcl_time_.nanoseconds;
}
Time::Time(const Time & rhs) = default;
Time::Time(
const builtin_interfaces::msg::Time & time_msg,
rcl_clock_type_t ros_time)
rcl_clock_type_t clock_type)
: rcl_time_(init_time_point(clock_type))
{
rcl_time_ = init_time_point(ros_time);
if (time_msg.sec < 0) {
throw std::runtime_error("cannot store a negative time point in rclcpp::Time");
}
@@ -95,31 +91,25 @@ Time::~Time()
Time::operator builtin_interfaces::msg::Time() const
{
builtin_interfaces::msg::Time msg_time;
msg_time.sec = static_cast<std::int32_t>(RCL_NS_TO_S(rcl_time_.nanoseconds));
msg_time.nanosec = static_cast<std::uint32_t>(rcl_time_.nanoseconds % (1000 * 1000 * 1000));
constexpr rcl_time_point_value_t kRemainder = RCL_S_TO_NS(1);
const auto result = std::div(rcl_time_.nanoseconds, kRemainder);
if (result.rem >= 0) {
msg_time.sec = static_cast<std::int32_t>(result.quot);
msg_time.nanosec = static_cast<std::uint32_t>(result.rem);
} else {
msg_time.sec = static_cast<std::int32_t>(result.quot - 1);
msg_time.nanosec = static_cast<std::uint32_t>(kRemainder + result.rem);
}
return msg_time;
}
Time &
Time::operator=(const Time & rhs)
{
rcl_time_ = rhs.rcl_time_;
return *this;
}
Time::operator=(const Time & rhs) = default;
Time &
Time::operator=(const builtin_interfaces::msg::Time & time_msg)
{
if (time_msg.sec < 0) {
throw std::runtime_error("cannot store a negative time point in rclcpp::Time");
}
rcl_clock_type_t ros_time = RCL_ROS_TIME;
rcl_time_ = init_time_point(ros_time); // TODO(tfoote) hard coded ROS here
rcl_time_.nanoseconds = RCL_S_TO_NS(static_cast<int64_t>(time_msg.sec));
rcl_time_.nanoseconds += time_msg.nanosec;
*this = Time(time_msg);
return *this;
}

View File

@@ -61,15 +61,11 @@ TimerBase::TimerBase(
rcl_clock_t * clock_handle = clock_->get_clock_handle();
{
std::lock_guard<std::mutex> clock_guard(clock_->get_clock_mutex());
if (
rcl_timer_init(
timer_handle_.get(), clock_handle, rcl_context.get(), period.count(), nullptr,
rcl_get_default_allocator()) != RCL_RET_OK)
{
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"Couldn't initialize rcl timer handle: %s\n", rcl_get_error_string().str);
rcl_reset_error();
rcl_ret_t ret = rcl_timer_init(
timer_handle_.get(), clock_handle, rcl_context.get(), period.count(), nullptr,
rcl_get_default_allocator());
if (ret != RCL_RET_OK) {
rclcpp::exceptions::throw_from_rcl_error(ret, "Couldn't initialize rcl timer handle");
}
}
}

501
rclcpp/test/CMakeLists.txt Normal file
View File

@@ -0,0 +1,501 @@
find_package(ament_cmake_gtest REQUIRED)
find_package(rmw_implementation_cmake REQUIRED)
find_package(rosidl_default_generators REQUIRED)
find_package(test_msgs REQUIRED)
include(cmake/rclcpp_add_build_failure_test.cmake)
add_definitions(-DTEST_RESOURCES_DIRECTORY="${CMAKE_CURRENT_BINARY_DIR}/resources")
rosidl_generate_interfaces(${PROJECT_NAME}_test_msgs
msg/Header.msg
msg/MessageWithHeader.msg
DEPENDENCIES builtin_interfaces
LIBRARY_NAME ${PROJECT_NAME}
SKIP_INSTALL
)
ament_add_gtest(test_any_service_callback rclcpp/test_any_service_callback.cpp)
if(TARGET test_any_service_callback)
ament_target_dependencies(test_any_service_callback
"test_msgs"
)
target_link_libraries(test_any_service_callback ${PROJECT_NAME})
endif()
ament_add_gtest(test_any_subscription_callback rclcpp/test_any_subscription_callback.cpp)
if(TARGET test_any_subscription_callback)
ament_target_dependencies(test_any_subscription_callback
"test_msgs"
)
target_link_libraries(test_any_subscription_callback ${PROJECT_NAME})
endif()
ament_add_gtest(test_client rclcpp/test_client.cpp)
if(TARGET test_client)
ament_target_dependencies(test_client
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_client ${PROJECT_NAME})
endif()
ament_add_gtest(test_create_timer rclcpp/test_create_timer.cpp)
if(TARGET test_create_timer)
ament_target_dependencies(test_create_timer
"rcl_interfaces"
"rmw"
"rcl"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_create_timer ${PROJECT_NAME})
target_include_directories(test_create_timer PRIVATE rclcpp/)
endif()
ament_add_gtest(test_create_subscription rclcpp/test_create_subscription.cpp)
if(TARGET test_create_subscription)
target_link_libraries(test_create_subscription ${PROJECT_NAME})
ament_target_dependencies(test_create_subscription
"test_msgs"
)
endif()
ament_add_gtest(test_expand_topic_or_service_name rclcpp/test_expand_topic_or_service_name.cpp)
if(TARGET test_expand_topic_or_service_name)
ament_target_dependencies(test_expand_topic_or_service_name
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_expand_topic_or_service_name ${PROJECT_NAME})
endif()
ament_add_gtest(test_function_traits rclcpp/test_function_traits.cpp)
if(TARGET test_function_traits)
target_include_directories(test_function_traits PUBLIC ../include)
ament_target_dependencies(test_function_traits
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
endif()
ament_add_gmock(test_intra_process_manager rclcpp/test_intra_process_manager.cpp)
if(TARGET test_intra_process_manager)
ament_target_dependencies(test_intra_process_manager
"rcl"
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_intra_process_manager ${PROJECT_NAME})
endif()
ament_add_gtest(test_ring_buffer_implementation rclcpp/test_ring_buffer_implementation.cpp)
if(TARGET test_ring_buffer_implementation)
ament_target_dependencies(test_ring_buffer_implementation
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_ring_buffer_implementation ${PROJECT_NAME})
endif()
ament_add_gtest(test_intra_process_buffer rclcpp/test_intra_process_buffer.cpp)
if(TARGET test_intra_process_buffer)
ament_target_dependencies(test_intra_process_buffer
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_intra_process_buffer ${PROJECT_NAME})
endif()
ament_add_gtest(test_loaned_message rclcpp/test_loaned_message.cpp)
ament_target_dependencies(test_loaned_message
"test_msgs"
)
target_link_libraries(test_loaned_message ${PROJECT_NAME})
ament_add_gtest(test_node rclcpp/test_node.cpp TIMEOUT 240)
if(TARGET test_node)
ament_target_dependencies(test_node
"rcl_interfaces"
"rcpputils"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_node ${PROJECT_NAME})
endif()
ament_add_gtest(test_node_interfaces__get_node_interfaces
rclcpp/node_interfaces/test_get_node_interfaces.cpp)
if(TARGET test_node_interfaces__get_node_interfaces)
target_link_libraries(test_node_interfaces__get_node_interfaces ${PROJECT_NAME})
endif()
ament_add_gtest(test_node_interfaces__node_base
rclcpp/node_interfaces/test_node_base.cpp)
if(TARGET test_node_interfaces__node_base)
target_link_libraries(test_node_interfaces__node_base ${PROJECT_NAME})
endif()
ament_add_gtest(test_node_interfaces__node_clock
rclcpp/node_interfaces/test_node_clock.cpp)
if(TARGET test_node_interfaces__node_clock)
target_link_libraries(test_node_interfaces__node_clock ${PROJECT_NAME})
endif()
ament_add_gtest(test_node_interfaces__node_graph
rclcpp/node_interfaces/test_node_graph.cpp)
if(TARGET test_node_interfaces__node_graph)
ament_target_dependencies(
test_node_interfaces__node_graph
"test_msgs")
target_link_libraries(test_node_interfaces__node_graph ${PROJECT_NAME})
endif()
ament_add_gtest(test_node_interfaces__node_parameters
rclcpp/node_interfaces/test_node_parameters.cpp)
if(TARGET test_node_interfaces__node_parameters)
target_link_libraries(test_node_interfaces__node_parameters ${PROJECT_NAME})
endif()
ament_add_gtest(test_node_interfaces__node_services
rclcpp/node_interfaces/test_node_services.cpp)
if(TARGET test_node_interfaces__node_services)
target_link_libraries(test_node_interfaces__node_services ${PROJECT_NAME})
endif()
ament_add_gtest(test_node_interfaces__node_timers
rclcpp/node_interfaces/test_node_timers.cpp)
if(TARGET test_node_interfaces__node_timers)
target_link_libraries(test_node_interfaces__node_timers ${PROJECT_NAME})
endif()
ament_add_gtest(test_node_interfaces__node_topics
rclcpp/node_interfaces/test_node_topics.cpp)
if(TARGET test_node_interfaces__node_topics)
ament_target_dependencies(
test_node_interfaces__node_topics
"test_msgs")
target_link_libraries(test_node_interfaces__node_topics ${PROJECT_NAME})
endif()
ament_add_gtest(test_node_interfaces__node_waitables
rclcpp/node_interfaces/test_node_waitables.cpp)
if(TARGET test_node_interfaces__node_waitables)
target_link_libraries(test_node_interfaces__node_waitables ${PROJECT_NAME})
endif()
# TODO(wjwwood): reenable these build failure tests when I can get Jenkins to ignore their output
# rclcpp_add_build_failure_test(build_failure__get_node_topics_interface_const_ref_rclcpp_node
# rclcpp/node_interfaces/test_does_not_compile/get_node_topics_interface_const_ref_rclcpp_node.cpp)
# target_link_libraries(build_failure__get_node_topics_interface_const_ref_rclcpp_node
# ${PROJECT_NAME})
# rclcpp_add_build_failure_test(build_failure__get_node_topics_interface_const_ptr_rclcpp_node
# rclcpp/node_interfaces/test_does_not_compile/get_node_topics_interface_const_ptr_rclcpp_node.cpp)
# target_link_libraries(build_failure__get_node_topics_interface_const_ptr_rclcpp_node
# ${PROJECT_NAME})
# rclcpp_add_build_failure_test(build_failure__get_node_topics_interface_const_ref_wrapped_node
# rclcpp/node_interfaces/test_does_not_compile/get_node_topics_interface_const_ref_wrapped_node.cpp)
# target_link_libraries(build_failure__get_node_topics_interface_const_ref_rclcpp_node
# ${PROJECT_NAME})
# rclcpp_add_build_failure_test(build_failure__get_node_topics_interface_const_ptr_wrapped_node
# rclcpp/node_interfaces/test_does_not_compile/get_node_topics_interface_const_ptr_wrapped_node.cpp)
# target_link_libraries(build_failure__get_node_topics_interface_const_ptr_rclcpp_node
# ${PROJECT_NAME})
ament_add_gtest(test_node_global_args rclcpp/test_node_global_args.cpp)
if(TARGET test_node_global_args)
ament_target_dependencies(test_node_global_args
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_node_global_args ${PROJECT_NAME})
endif()
ament_add_gtest(test_node_options rclcpp/test_node_options.cpp)
if(TARGET test_node_options)
ament_target_dependencies(test_node_options "rcl")
target_link_libraries(test_node_options ${PROJECT_NAME})
endif()
ament_add_gtest(test_parameter_client rclcpp/test_parameter_client.cpp)
if(TARGET test_parameter_client)
ament_target_dependencies(test_parameter_client
"rcl_interfaces"
)
target_link_libraries(test_parameter_client ${PROJECT_NAME})
endif()
ament_add_gtest(test_parameter_events_filter rclcpp/test_parameter_events_filter.cpp)
if(TARGET test_parameter_events_filter)
ament_target_dependencies(test_parameter_events_filter
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_parameter_events_filter ${PROJECT_NAME})
endif()
ament_add_gtest(test_parameter rclcpp/test_parameter.cpp)
if(TARGET test_parameter)
ament_target_dependencies(test_parameter
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_parameter ${PROJECT_NAME})
endif()
ament_add_gtest(test_parameter_map rclcpp/test_parameter_map.cpp)
if(TARGET test_parameter_map)
target_link_libraries(test_parameter_map ${PROJECT_NAME})
endif()
ament_add_gtest(test_publisher rclcpp/test_publisher.cpp)
if(TARGET test_publisher)
ament_target_dependencies(test_publisher
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_publisher ${PROJECT_NAME})
endif()
ament_add_gtest(test_publisher_subscription_count_api rclcpp/test_publisher_subscription_count_api.cpp)
if(TARGET test_publisher_subscription_count_api)
ament_target_dependencies(test_publisher_subscription_count_api
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_publisher_subscription_count_api ${PROJECT_NAME})
endif()
ament_add_gtest(test_qos rclcpp/test_qos.cpp)
if(TARGET test_qos)
ament_target_dependencies(test_qos
"rmw"
)
target_link_libraries(test_qos
${PROJECT_NAME}
)
endif()
ament_add_gtest(test_qos_event rclcpp/test_qos_event.cpp)
if(TARGET test_qos_event)
ament_target_dependencies(test_qos_event
"rmw"
"test_msgs"
)
target_link_libraries(test_qos_event
${PROJECT_NAME}
)
endif()
ament_add_gtest(test_rate rclcpp/test_rate.cpp)
if(TARGET test_rate)
ament_target_dependencies(test_rate
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_rate
${PROJECT_NAME}
)
endif()
ament_add_gtest(test_serialized_message_allocator rclcpp/test_serialized_message_allocator.cpp)
if(TARGET test_serialized_message_allocator)
ament_target_dependencies(test_serialized_message_allocator
test_msgs
)
target_link_libraries(test_serialized_message_allocator
${PROJECT_NAME}
)
endif()
ament_add_gtest(test_serialized_message rclcpp/test_serialized_message.cpp)
if(TARGET test_serialized_message)
ament_target_dependencies(test_serialized_message
test_msgs
)
target_link_libraries(test_serialized_message
${PROJECT_NAME}
)
endif()
ament_add_gtest(test_service rclcpp/test_service.cpp)
if(TARGET test_service)
ament_target_dependencies(test_service
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_service ${PROJECT_NAME})
endif()
ament_add_gtest(test_subscription rclcpp/test_subscription.cpp)
if(TARGET test_subscription)
ament_target_dependencies(test_subscription
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_subscription ${PROJECT_NAME})
endif()
ament_add_gtest(test_subscription_publisher_count_api rclcpp/test_subscription_publisher_count_api.cpp)
if(TARGET test_subscription_publisher_count_api)
ament_target_dependencies(test_subscription_publisher_count_api
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_subscription_publisher_count_api ${PROJECT_NAME})
endif()
ament_add_gtest(test_subscription_traits rclcpp/test_subscription_traits.cpp)
if(TARGET test_subscription_traits)
ament_target_dependencies(test_subscription_traits
"rcl"
"test_msgs"
)
target_link_libraries(test_subscription_traits ${PROJECT_NAME})
endif()
ament_add_gtest(test_find_weak_nodes rclcpp/test_find_weak_nodes.cpp)
if(TARGET test_find_weak_nodes)
ament_target_dependencies(test_find_weak_nodes
"rcl"
)
target_link_libraries(test_find_weak_nodes ${PROJECT_NAME})
endif()
set(append_library_dirs "${CMAKE_CURRENT_BINARY_DIR}")
if(WIN32)
set(append_library_dirs "${append_library_dirs}/$<CONFIG>")
endif()
ament_add_gtest(test_externally_defined_services rclcpp/test_externally_defined_services.cpp)
ament_target_dependencies(test_externally_defined_services
"rcl"
"test_msgs"
)
target_link_libraries(test_externally_defined_services ${PROJECT_NAME})
ament_add_gtest(test_duration rclcpp/test_duration.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_duration)
ament_target_dependencies(test_duration
"rcl")
target_link_libraries(test_duration ${PROJECT_NAME})
endif()
ament_add_gtest(test_executor rclcpp/test_executor.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_executor)
ament_target_dependencies(test_executor
"rcl")
target_link_libraries(test_executor ${PROJECT_NAME})
endif()
ament_add_gtest(test_logger rclcpp/test_logger.cpp)
target_link_libraries(test_logger ${PROJECT_NAME})
ament_add_gmock(test_logging rclcpp/test_logging.cpp)
target_link_libraries(test_logging ${PROJECT_NAME})
ament_add_gtest(test_time rclcpp/test_time.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_time)
ament_target_dependencies(test_time
"rcl")
target_link_libraries(test_time ${PROJECT_NAME})
endif()
ament_add_gtest(test_timer rclcpp/test_timer.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_timer)
ament_target_dependencies(test_timer
"rcl")
target_link_libraries(test_timer ${PROJECT_NAME})
endif()
ament_add_gtest(test_time_source rclcpp/test_time_source.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_time_source)
ament_target_dependencies(test_time_source
"rcl")
target_link_libraries(test_time_source ${PROJECT_NAME})
endif()
ament_add_gtest(test_utilities rclcpp/test_utilities.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_utilities)
ament_target_dependencies(test_utilities
"rcl")
target_link_libraries(test_utilities ${PROJECT_NAME})
endif()
ament_add_gtest(test_init rclcpp/test_init.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_init)
ament_target_dependencies(test_init
"rcl")
target_link_libraries(test_init ${PROJECT_NAME})
endif()
ament_add_gtest(test_interface_traits rclcpp/test_interface_traits.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_interface_traits)
ament_target_dependencies(test_interface_traits
"rcl")
target_link_libraries(test_interface_traits ${PROJECT_NAME})
endif()
ament_add_gtest(test_multi_threaded_executor rclcpp/executors/test_multi_threaded_executor.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_multi_threaded_executor)
ament_target_dependencies(test_multi_threaded_executor
"rcl")
target_link_libraries(test_multi_threaded_executor ${PROJECT_NAME})
endif()
ament_add_gtest(test_guard_condition rclcpp/test_guard_condition.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_guard_condition)
target_link_libraries(test_guard_condition ${PROJECT_NAME})
endif()
ament_add_gtest(test_wait_set rclcpp/test_wait_set.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_wait_set)
ament_target_dependencies(test_wait_set "test_msgs")
target_link_libraries(test_wait_set ${PROJECT_NAME})
endif()
ament_add_gtest(test_subscription_topic_statistics rclcpp/topic_statistics/test_subscription_topic_statistics.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}"
)
if(TARGET test_subscription_topic_statistics)
ament_target_dependencies(test_subscription_topic_statistics
"builtin_interfaces"
"libstatistics_collector"
"rcl_interfaces"
"rcutils"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"statistics_msgs"
"test_msgs")
rosidl_target_interfaces(test_subscription_topic_statistics ${PROJECT_NAME}_test_msgs "rosidl_typesupport_cpp")
target_link_libraries(test_subscription_topic_statistics ${PROJECT_NAME})
endif()
ament_add_gtest(test_subscription_options rclcpp/test_subscription_options.cpp)
if(TARGET test_subscription_options)
ament_target_dependencies(test_subscription_options "rcl")
target_link_libraries(test_subscription_options ${PROJECT_NAME})
endif()
# Install test resources
install(
DIRECTORY resources
DESTINATION ${CMAKE_CURRENT_BINARY_DIR})

View File

@@ -83,7 +83,7 @@ TEST_F(TestMultiThreadedExecutor, timer_over_take) {
{
std::lock_guard<std::mutex> lock(last_mutex);
double diff = std::abs((now - last).nanoseconds()) / 1.0e9;
double diff = static_cast<double>(std::abs((now - last).nanoseconds())) / 1.0e9;
last = now;
if (diff < PERIOD - TOLERANCE) {

View File

@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef NODE_INTERFACES__NODE_WRAPPER_HPP_
#define NODE_INTERFACES__NODE_WRAPPER_HPP_
#ifndef RCLCPP__NODE_INTERFACES__NODE_WRAPPER_HPP_
#define RCLCPP__NODE_INTERFACES__NODE_WRAPPER_HPP_
#include <memory>
#include <string>
@@ -61,4 +61,4 @@ private:
rclcpp::Node::SharedPtr node;
};
#endif // NODE_INTERFACES__NODE_WRAPPER_HPP_
#endif // RCLCPP__NODE_INTERFACES__NODE_WRAPPER_HPP_

View File

@@ -0,0 +1,60 @@
// Copyright 2020 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 <gtest/gtest.h>
#include <memory>
#include <string>
#include "rcl/node_options.h"
#include "rclcpp/node.hpp"
#include "rclcpp/node_interfaces/node_base.hpp"
#include "rclcpp/rclcpp.hpp"
class TestNodeBase : public ::testing::Test
{
public:
void SetUp()
{
rclcpp::init(0, nullptr);
}
void TearDown()
{
rclcpp::shutdown();
}
};
TEST_F(TestNodeBase, construct_from_node)
{
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node", "ns");
// This dynamic cast is not necessary for the unittest itself, but instead is used to ensure
// the proper type is being tested and covered.
auto * node_base =
dynamic_cast<rclcpp::node_interfaces::NodeBase *>(node->get_node_base_interface().get());
ASSERT_NE(nullptr, node_base);
EXPECT_STREQ("node", node_base->get_name());
EXPECT_STREQ("/ns", node_base->get_namespace());
EXPECT_STREQ("/ns/node", node_base->get_fully_qualified_name());
EXPECT_NE(nullptr, node_base->get_context());
EXPECT_NE(nullptr, node_base->get_rcl_node_handle());
EXPECT_NE(nullptr, node_base->get_shared_rcl_node_handle());
const auto * const_node_base = node_base;
EXPECT_NE(nullptr, const_node_base->get_rcl_node_handle());
EXPECT_NE(nullptr, const_node_base->get_shared_rcl_node_handle());
}

View File

@@ -0,0 +1,49 @@
// Copyright 2020 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 <gtest/gtest.h>
#include <memory>
#include "rclcpp/node_interfaces/node_clock.hpp"
#include "rclcpp/node.hpp"
class TestNodeClock : public ::testing::Test
{
public:
void SetUp()
{
rclcpp::init(0, nullptr);
}
void TearDown()
{
rclcpp::shutdown();
}
};
TEST_F(TestNodeClock, construct_from_node)
{
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node", "ns");
// This dynamic cast is not necessary for the unittest itself, but instead is used to ensure
// the proper type is being tested and covered.
auto * node_clock =
dynamic_cast<rclcpp::node_interfaces::NodeClock *>(node->get_node_clock_interface().get());
ASSERT_NE(nullptr, node_clock);
EXPECT_NE(nullptr, node_clock->get_clock());
const auto * const_node_clock = node_clock;
EXPECT_NE(nullptr, const_node_clock->get_clock());
}

View File

@@ -0,0 +1,186 @@
// Copyright 2020 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 <gtest/gtest.h>
#include <memory>
#include <utility>
#include "rcl/node_options.h"
#include "rclcpp/node.hpp"
#include "rclcpp/node_interfaces/node_base.hpp"
#include "rclcpp/node_interfaces/node_graph.hpp"
#include "rclcpp/rclcpp.hpp"
#include "test_msgs/msg/empty.hpp"
class TestNodeGraph : public ::testing::Test
{
public:
void SetUp()
{
rclcpp::init(0, nullptr);
}
void TearDown()
{
rclcpp::shutdown();
}
};
TEST_F(TestNodeGraph, construct_from_node)
{
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node", "ns");
// This dynamic cast is not necessary for the unittest itself, but instead is used to ensure
// the proper type is being tested and covered.
const auto * node_graph =
dynamic_cast<rclcpp::node_interfaces::NodeGraph *>(node->get_node_graph_interface().get());
ASSERT_NE(nullptr, node_graph);
auto topic_names_and_types = node_graph->get_topic_names_and_types(false);
EXPECT_LT(0u, topic_names_and_types.size());
auto service_names_and_types = node_graph->get_service_names_and_types();
EXPECT_LT(0u, service_names_and_types.size());
auto names = node_graph->get_node_names();
EXPECT_EQ(1u, names.size());
auto names_and_namespaces = node_graph->get_node_names_and_namespaces();
EXPECT_EQ(1u, names_and_namespaces.size());
EXPECT_EQ(0u, node_graph->count_publishers("not_a_topic"));
EXPECT_EQ(0u, node_graph->count_subscribers("not_a_topic"));
}
TEST_F(TestNodeGraph, get_topic_names_and_types)
{
auto node = std::make_shared<rclcpp::Node>("node2", "ns");
const auto * node_graph =
dynamic_cast<rclcpp::node_interfaces::NodeGraph *>(node->get_node_graph_interface().get());
ASSERT_NE(nullptr, node_graph);
auto topic_names_and_types = node_graph->get_topic_names_and_types();
EXPECT_LT(0u, topic_names_and_types.size());
}
TEST_F(TestNodeGraph, get_service_names_and_types)
{
auto node = std::make_shared<rclcpp::Node>("node2", "ns");
const auto * node_graph =
dynamic_cast<rclcpp::node_interfaces::NodeGraph *>(node->get_node_graph_interface().get());
ASSERT_NE(nullptr, node_graph);
auto service_names_and_types = node_graph->get_service_names_and_types();
EXPECT_LT(0u, service_names_and_types.size());
}
TEST_F(TestNodeGraph, get_service_names_and_types_by_node)
{
auto node1 = std::make_shared<rclcpp::Node>("node1", "ns");
auto node2 = std::make_shared<rclcpp::Node>("node2", "ns");
const auto * node_graph =
dynamic_cast<rclcpp::node_interfaces::NodeGraph *>(node1->get_node_graph_interface().get());
ASSERT_NE(nullptr, node_graph);
EXPECT_THROW(
node_graph->get_service_names_and_types_by_node("not_a_node", "not_absolute_namespace"),
std::runtime_error);
auto service_names_and_types1 = node_graph->get_service_names_and_types_by_node("node1", "/ns");
auto service_names_and_types2 = node_graph->get_service_names_and_types_by_node("node2", "/ns");
EXPECT_EQ(service_names_and_types1.size(), service_names_and_types2.size());
}
TEST_F(TestNodeGraph, get_node_names_and_namespaces)
{
auto node = std::make_shared<rclcpp::Node>("node", "ns");
const auto * node_graph =
dynamic_cast<rclcpp::node_interfaces::NodeGraph *>(node->get_node_graph_interface().get());
ASSERT_NE(nullptr, node_graph);
auto names_and_namespaces = node_graph->get_node_names_and_namespaces();
EXPECT_EQ(1u, names_and_namespaces.size());
}
TEST_F(TestNodeGraph, notify_shutdown)
{
auto node = std::make_shared<rclcpp::Node>("node", "ns");
auto * node_graph =
dynamic_cast<rclcpp::node_interfaces::NodeGraph *>(node->get_node_graph_interface().get());
ASSERT_NE(nullptr, node_graph);
EXPECT_NO_THROW(node_graph->notify_shutdown());
}
TEST_F(TestNodeGraph, wait_for_graph_change)
{
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node", "ns");
auto * node_graph =
dynamic_cast<rclcpp::node_interfaces::NodeGraph *>(node->get_node_graph_interface().get());
ASSERT_NE(nullptr, node_graph);
EXPECT_NO_THROW(node_graph->notify_graph_change());
EXPECT_THROW(
node_graph->wait_for_graph_change(nullptr, std::chrono::milliseconds(1)),
rclcpp::exceptions::InvalidEventError);
auto event = std::make_shared<rclcpp::Event>();
EXPECT_THROW(
node_graph->wait_for_graph_change(event, std::chrono::milliseconds(0)),
rclcpp::exceptions::EventNotRegisteredError);
}
TEST_F(TestNodeGraph, get_info_by_topic)
{
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node", "ns");
const rclcpp::QoS publisher_qos(1);
auto publisher = node->create_publisher<test_msgs::msg::Empty>("topic", publisher_qos);
auto callback = [](const test_msgs::msg::Empty::SharedPtr) {};
const rclcpp::QoS subscriber_qos(10);
auto subscription =
node->create_subscription<test_msgs::msg::Empty>(
"topic", subscriber_qos, std::move(callback));
const auto * node_graph =
dynamic_cast<rclcpp::node_interfaces::NodeGraph *>(node->get_node_graph_interface().get());
ASSERT_NE(nullptr, node_graph);
auto publishers = node_graph->get_publishers_info_by_topic("topic", false);
ASSERT_EQ(1u, publishers.size());
auto publisher_endpoint_info = publishers[0];
const auto const_publisher_endpoint_info = publisher_endpoint_info;
EXPECT_STREQ("node", publisher_endpoint_info.node_name().c_str());
EXPECT_STREQ("node", const_publisher_endpoint_info.node_name().c_str());
EXPECT_STREQ("/ns", publisher_endpoint_info.node_namespace().c_str());
EXPECT_STREQ("/ns", const_publisher_endpoint_info.node_namespace().c_str());
EXPECT_STREQ("test_msgs/msg/Empty", publisher_endpoint_info.topic_type().c_str());
EXPECT_STREQ("test_msgs/msg/Empty", const_publisher_endpoint_info.topic_type().c_str());
EXPECT_EQ(rclcpp::EndpointType::Publisher, publisher_endpoint_info.endpoint_type());
EXPECT_EQ(rclcpp::EndpointType::Publisher, const_publisher_endpoint_info.endpoint_type());
rclcpp::QoS actual_qos = publisher_endpoint_info.qos_profile();
EXPECT_EQ(0u, actual_qos.get_rmw_qos_profile().depth);
rclcpp::QoS const_actual_qos = const_publisher_endpoint_info.qos_profile();
EXPECT_EQ(0u, const_actual_qos.get_rmw_qos_profile().depth);
auto endpoint_gid = publisher_endpoint_info.endpoint_gid();
auto const_endpoint_gid = const_publisher_endpoint_info.endpoint_gid();
bool endpoint_gid_is_all_zeros = true;
for (size_t i = 0; i < RMW_GID_STORAGE_SIZE; ++i) {
endpoint_gid_is_all_zeros &= (endpoint_gid[i] == 0);
EXPECT_EQ(endpoint_gid[i], const_endpoint_gid[i]);
}
EXPECT_FALSE(endpoint_gid_is_all_zeros);
}

View File

@@ -0,0 +1,89 @@
// Copyright 2020 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.
/**
* NodeParameters is a complicated interface with lots of code, but it is tested elsewhere
* very thoroughly. This currently just includes unittests for the currently uncovered
* functionality.
*/
#include <gtest/gtest.h>
#include <algorithm>
#include <memory>
#include <string>
#include <vector>
#include "rclcpp/node.hpp"
#include "rclcpp/node_interfaces/node_parameters.hpp"
class TestNodeParameters : public ::testing::Test
{
public:
void SetUp()
{
rclcpp::init(0, nullptr);
}
void TearDown()
{
rclcpp::shutdown();
}
};
TEST_F(TestNodeParameters, list_parameters)
{
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node", "ns");
// This dynamic cast is not necessary for the unittest itself, but instead is used to ensure
// the proper type is being tested and covered.
auto * node_parameters =
dynamic_cast<rclcpp::node_interfaces::NodeParameters *>(
node->get_node_parameters_interface().get());
ASSERT_NE(nullptr, node_parameters);
std::vector<std::string> prefixes;
const auto list_result = node_parameters->list_parameters(prefixes, 1u);
// Currently the only default parameter is 'use_sim_time', but that may change.
size_t number_of_parameters = list_result.names.size();
EXPECT_GE(1u, number_of_parameters);
const std::string parameter_name = "new_parameter";
const rclcpp::ParameterValue value(true);
const rcl_interfaces::msg::ParameterDescriptor descriptor;
const auto added_parameter_value =
node_parameters->declare_parameter(parameter_name, value, descriptor, false);
EXPECT_EQ(value.get<bool>(), added_parameter_value.get<bool>());
auto list_result2 = node_parameters->list_parameters(prefixes, 1u);
EXPECT_EQ(number_of_parameters + 1u, list_result2.names.size());
EXPECT_NE(
std::find(list_result2.names.begin(), list_result2.names.end(), parameter_name),
list_result2.names.end());
}
TEST_F(TestNodeParameters, parameter_overrides)
{
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node", "ns");
auto * node_parameters =
dynamic_cast<rclcpp::node_interfaces::NodeParameters *>(
node->get_node_parameters_interface().get());
ASSERT_NE(nullptr, node_parameters);
const auto & parameter_overrides = node_parameters->get_parameter_overrides();
EXPECT_EQ(0u, parameter_overrides.size());
}

View File

@@ -0,0 +1,111 @@
// Copyright 2020 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 <gtest/gtest.h>
#include <memory>
#include <string>
#include "rcl/node_options.h"
#include "rclcpp/node.hpp"
#include "rclcpp/node_interfaces/node_services.hpp"
#include "rclcpp/rclcpp.hpp"
class TestService : public rclcpp::ServiceBase
{
public:
explicit TestService(rclcpp::Node * node)
: rclcpp::ServiceBase(node->get_node_base_interface()->get_shared_rcl_node_handle()) {}
std::shared_ptr<void> create_request() override {return nullptr;}
std::shared_ptr<rmw_request_id_t> create_request_header() override {return nullptr;}
void handle_request(std::shared_ptr<rmw_request_id_t>, std::shared_ptr<void>) override {}
};
class TestClient : public rclcpp::ClientBase
{
public:
explicit TestClient(rclcpp::Node * node)
: rclcpp::ClientBase(node->get_node_base_interface().get(), node->get_node_graph_interface()) {}
std::shared_ptr<void> create_response() override {return nullptr;}
std::shared_ptr<rmw_request_id_t> create_request_header() override {return nullptr;}
void handle_response(
std::shared_ptr<rmw_request_id_t>, std::shared_ptr<void>) override {}
};
class TestNodeService : public ::testing::Test
{
public:
void SetUp()
{
rclcpp::init(0, nullptr);
}
void TearDown()
{
rclcpp::shutdown();
}
};
TEST_F(TestNodeService, add_service)
{
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node", "ns");
// This dynamic cast is not necessary for the unittest itself, but instead is used to ensure
// the proper type is being tested and covered.
auto * node_services =
dynamic_cast<rclcpp::node_interfaces::NodeServices *>(
node->get_node_services_interface().get());
ASSERT_NE(nullptr, node_services);
auto service = std::make_shared<TestService>(node.get());
auto callback_group = node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
EXPECT_NO_THROW(
node_services->add_service(service, callback_group));
// Check that adding a service from node to a callback group of different_node throws exception.
std::shared_ptr<rclcpp::Node> different_node = std::make_shared<rclcpp::Node>("node2", "ns");
auto callback_group_in_different_node =
different_node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
EXPECT_THROW(
node_services->add_service(service, callback_group_in_different_node),
std::runtime_error);
}
TEST_F(TestNodeService, add_client)
{
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node", "ns");
// This dynamic cast is not necessary for the unittest itself, but instead is used to ensure
// the proper type is being tested and covered.
auto * node_services =
dynamic_cast<rclcpp::node_interfaces::NodeServices *>(
node->get_node_services_interface().get());
ASSERT_NE(nullptr, node_services);
auto client = std::make_shared<TestClient>(node.get());
auto callback_group = node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
EXPECT_NO_THROW(node_services->add_client(client, callback_group));
// Check that adding a client from node to a callback group of different_node throws exception.
std::shared_ptr<rclcpp::Node> different_node = std::make_shared<rclcpp::Node>("node2", "ns");
auto callback_group_in_different_node =
different_node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
EXPECT_THROW(
node_services->add_client(client, callback_group_in_different_node),
std::runtime_error);
}

View File

@@ -0,0 +1,71 @@
// Copyright 2020 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 <gtest/gtest.h>
#include <memory>
#include <string>
#include "rcl/node_options.h"
#include "rclcpp/node.hpp"
#include "rclcpp/node_interfaces/node_timers.hpp"
#include "rclcpp/rclcpp.hpp"
class TestTimer : public rclcpp::TimerBase
{
public:
explicit TestTimer(rclcpp::Node * node)
: TimerBase(node->get_clock(), std::chrono::nanoseconds(1),
node->get_node_base_interface()->get_context()) {}
void execute_callback() override {}
bool is_steady() override {return false;}
};
class TestNodeTimers : public ::testing::Test
{
public:
void SetUp()
{
rclcpp::init(0, nullptr);
}
void TearDown()
{
rclcpp::shutdown();
}
};
TEST_F(TestNodeTimers, add_timer)
{
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node", "ns");
// This dynamic cast is not necessary for the unittest itself, but instead is used to ensure
// the proper type is being tested and covered.
auto node_timers =
dynamic_cast<rclcpp::node_interfaces::NodeTimers *>(node->get_node_timers_interface().get());
ASSERT_NE(nullptr, node_timers);
auto timer = std::make_shared<TestTimer>(node.get());
auto callback_group = node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
EXPECT_NO_THROW(node_timers->add_timer(timer, callback_group));
// Check that adding timer from node to callback group in different_node throws exception.
std::shared_ptr<rclcpp::Node> different_node = std::make_shared<rclcpp::Node>("node2", "ns");
auto callback_group_in_different_node =
different_node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
EXPECT_THROW(
node_timers->add_timer(timer, callback_group_in_different_node),
std::runtime_error);
}

View File

@@ -0,0 +1,129 @@
// Copyright 2020 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 <gtest/gtest.h>
#include <memory>
#include <string>
#include <type_traits>
#include "rcl/node_options.h"
#include "rclcpp/node.hpp"
#include "rclcpp/node_interfaces/node_topics.hpp"
#include "rclcpp/rclcpp.hpp"
#include "test_msgs/msg/empty.hpp"
namespace
{
const rosidl_message_type_support_t EmptyTypeSupport()
{
return *rosidl_typesupport_cpp::get_message_type_support_handle<test_msgs::msg::Empty>();
}
const rcl_publisher_options_t PublisherOptions()
{
return rclcpp::PublisherOptionsWithAllocator<std::allocator<void>>().template
to_rcl_publisher_options<test_msgs::msg::Empty>(rclcpp::QoS(10));
}
const rcl_subscription_options_t SubscriptionOptions()
{
return rclcpp::SubscriptionOptionsWithAllocator<std::allocator<void>>().template
to_rcl_subscription_options<test_msgs::msg::Empty>(rclcpp::QoS(10));
}
} // namespace
class TestPublisher : public rclcpp::PublisherBase
{
public:
explicit TestPublisher(rclcpp::Node * node)
: rclcpp::PublisherBase(
node->get_node_base_interface().get(), "topic", EmptyTypeSupport(), PublisherOptions()) {}
};
class TestSubscription : public rclcpp::SubscriptionBase
{
public:
explicit TestSubscription(rclcpp::Node * node)
: rclcpp::SubscriptionBase(
node->get_node_base_interface().get(), EmptyTypeSupport(), "topic", SubscriptionOptions()) {}
std::shared_ptr<void> create_message() override {return nullptr;}
std::shared_ptr<rclcpp::SerializedMessage>
create_serialized_message() override {return nullptr;}
void handle_message(std::shared_ptr<void> &, const rclcpp::MessageInfo &) override {}
void handle_loaned_message(void *, const rclcpp::MessageInfo &) override {}
void return_message(std::shared_ptr<void> &) override {}
void return_serialized_message(std::shared_ptr<rclcpp::SerializedMessage> &) override {}
};
class TestNodeTopics : public ::testing::Test
{
public:
void SetUp()
{
rclcpp::init(0, nullptr);
}
void TearDown()
{
rclcpp::shutdown();
}
};
TEST_F(TestNodeTopics, add_publisher)
{
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node", "ns");
// This dynamic cast is not necessary for the unittest itself, but instead is used to ensure
// the proper type is being tested and covered.
auto * node_topics =
dynamic_cast<rclcpp::node_interfaces::NodeTopics *>(node->get_node_topics_interface().get());
ASSERT_NE(nullptr, node_topics);
auto publisher = std::make_shared<TestPublisher>(node.get());
auto callback_group = node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
EXPECT_NO_THROW(node_topics->add_publisher(publisher, callback_group));
// Check that adding publisher from node to a callback group in different_node throws exception.
std::shared_ptr<rclcpp::Node> different_node = std::make_shared<rclcpp::Node>("node2", "ns");
auto callback_group_in_different_node =
different_node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
EXPECT_THROW(
node_topics->add_publisher(publisher, callback_group_in_different_node),
std::runtime_error);
}
TEST_F(TestNodeTopics, add_subscription)
{
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node", "ns");
auto * node_topics =
dynamic_cast<rclcpp::node_interfaces::NodeTopics *>(node->get_node_topics_interface().get());
ASSERT_NE(nullptr, node_topics);
auto subscription = std::make_shared<TestSubscription>(node.get());
auto callback_group = node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
EXPECT_NO_THROW(node_topics->add_subscription(subscription, callback_group));
// Check that adding subscription from node to callback group in different_node throws exception.
std::shared_ptr<rclcpp::Node> different_node = std::make_shared<rclcpp::Node>("node2", "ns");
auto callback_group_in_different_node =
different_node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
EXPECT_THROW(
node_topics->add_subscription(subscription, callback_group_in_different_node),
std::runtime_error);
}

View File

@@ -0,0 +1,68 @@
// Copyright 2020 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 <gtest/gtest.h>
#include <memory>
#include <string>
#include "rcl/node_options.h"
#include "rclcpp/node.hpp"
#include "rclcpp/node_interfaces/node_waitables.hpp"
#include "rclcpp/rclcpp.hpp"
class TestWaitable : public rclcpp::Waitable
{
public:
bool add_to_wait_set(rcl_wait_set_t *) override {return false;}
bool is_ready(rcl_wait_set_t *) override {return false;}
void execute() override {}
};
class TestNodeWaitables : public ::testing::Test
{
public:
void SetUp()
{
rclcpp::init(0, nullptr);
}
void TearDown()
{
rclcpp::shutdown();
}
};
TEST_F(TestNodeWaitables, add_remove_waitable)
{
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node", "ns");
auto * node_waitables =
dynamic_cast<rclcpp::node_interfaces::NodeWaitables *>(
node->get_node_waitables_interface().get());
ASSERT_NE(nullptr, node_waitables);
std::shared_ptr<rclcpp::Node> node2 = std::make_shared<rclcpp::Node>("node2", "ns");
auto callback_group1 = node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
auto callback_group2 = node2->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
auto waitable = std::make_shared<TestWaitable>();
EXPECT_NO_THROW(
node_waitables->add_waitable(waitable, callback_group1));
EXPECT_THROW(
node_waitables->add_waitable(waitable, callback_group2),
std::runtime_error);
EXPECT_NO_THROW(node_waitables->remove_waitable(waitable, callback_group1));
EXPECT_NO_THROW(node_waitables->remove_waitable(waitable, callback_group2));
}

View File

@@ -0,0 +1,78 @@
// Copyright 2020 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.
// This file includes basic API tests for the AnyServiceCallback class.
// It is also tested in test_externally_defined_services.cpp
#include <gtest/gtest.h>
#include <functional>
#include <memory>
#include <utility>
#include "rclcpp/any_service_callback.hpp"
#include "test_msgs/srv/empty.hpp"
#include "test_msgs/srv/empty.h"
class TestAnyServiceCallback : public ::testing::Test
{
public:
void SetUp()
{
request_header_ = std::make_shared<rmw_request_id_t>();
request_ = std::make_shared<test_msgs::srv::Empty::Request>();
response_ = std::make_shared<test_msgs::srv::Empty::Response>();
}
protected:
rclcpp::AnyServiceCallback<test_msgs::srv::Empty> any_service_callback_;
std::shared_ptr<rmw_request_id_t> request_header_;
std::shared_ptr<test_msgs::srv::Empty::Request> request_;
std::shared_ptr<test_msgs::srv::Empty::Response> response_;
};
TEST_F(TestAnyServiceCallback, no_set_and_dispatch_throw) {
EXPECT_THROW(
any_service_callback_.dispatch(request_header_, request_, response_),
std::runtime_error);
}
TEST_F(TestAnyServiceCallback, set_and_dispatch_no_header) {
int callback_calls = 0;
auto callback = [&callback_calls](const std::shared_ptr<test_msgs::srv::Empty::Request>,
std::shared_ptr<test_msgs::srv::Empty::Response>) {
callback_calls++;
};
any_service_callback_.set(callback);
EXPECT_NO_THROW(
any_service_callback_.dispatch(request_header_, request_, response_));
EXPECT_EQ(callback_calls, 1);
}
TEST_F(TestAnyServiceCallback, set_and_dispatch_header) {
int callback_with_header_calls = 0;
auto callback_with_header =
[&callback_with_header_calls](const std::shared_ptr<rmw_request_id_t>,
const std::shared_ptr<test_msgs::srv::Empty::Request>,
std::shared_ptr<test_msgs::srv::Empty::Response>) {
callback_with_header_calls++;
};
any_service_callback_.set(callback_with_header);
EXPECT_NO_THROW(
any_service_callback_.dispatch(request_header_, request_, response_));
EXPECT_EQ(callback_with_header_calls, 1);
}

View File

@@ -0,0 +1,205 @@
// Copyright 2020 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 <gtest/gtest.h>
#include <functional>
#include <memory>
#include <utility>
#include "rclcpp/any_subscription_callback.hpp"
#include "test_msgs/msg/empty.hpp"
#include "test_msgs/msg/empty.h"
class TestAnySubscriptionCallback : public ::testing::Test
{
public:
TestAnySubscriptionCallback()
: any_subscription_callback_(allocator_) {}
void SetUp()
{
msg_shared_ptr_ = std::make_shared<test_msgs::msg::Empty>();
msg_const_shared_ptr_ = std::make_shared<const test_msgs::msg::Empty>();
msg_unique_ptr_ = std::make_unique<test_msgs::msg::Empty>();
}
protected:
std::shared_ptr<std::allocator<void>> allocator_;
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty, std::allocator<void>>
any_subscription_callback_;
std::shared_ptr<test_msgs::msg::Empty> msg_shared_ptr_;
std::shared_ptr<const test_msgs::msg::Empty> msg_const_shared_ptr_;
std::unique_ptr<test_msgs::msg::Empty> msg_unique_ptr_;
rclcpp::MessageInfo message_info_;
};
TEST_F(TestAnySubscriptionCallback, construct_destruct) {
}
TEST_F(TestAnySubscriptionCallback, unset_dispatch_throw) {
EXPECT_THROW(
any_subscription_callback_.dispatch(msg_shared_ptr_, message_info_),
std::runtime_error);
EXPECT_THROW(
any_subscription_callback_.dispatch_intra_process(msg_const_shared_ptr_, message_info_),
std::runtime_error);
EXPECT_THROW(
any_subscription_callback_.dispatch_intra_process(std::move(msg_unique_ptr_), message_info_),
std::runtime_error);
}
TEST_F(TestAnySubscriptionCallback, set_dispatch_shared_ptr) {
int callback_count = 0;
auto shared_ptr_callback = [&callback_count](
const std::shared_ptr<test_msgs::msg::Empty>) {
callback_count++;
};
any_subscription_callback_.set(shared_ptr_callback);
EXPECT_NO_THROW(any_subscription_callback_.dispatch(msg_shared_ptr_, message_info_));
EXPECT_EQ(callback_count, 1);
// Can't convert ConstSharedPtr to SharedPtr
EXPECT_THROW(
any_subscription_callback_.dispatch_intra_process(msg_const_shared_ptr_, message_info_),
std::runtime_error);
EXPECT_EQ(callback_count, 1);
// Promotes Unique into SharedPtr
EXPECT_NO_THROW(
any_subscription_callback_.dispatch_intra_process(std::move(msg_unique_ptr_), message_info_));
EXPECT_EQ(callback_count, 2);
}
TEST_F(TestAnySubscriptionCallback, set_dispatch_shared_ptr_w_info) {
int callback_count = 0;
auto shared_ptr_w_info_callback = [&callback_count](
const std::shared_ptr<test_msgs::msg::Empty>, const rclcpp::MessageInfo &) {
callback_count++;
};
any_subscription_callback_.set(shared_ptr_w_info_callback);
EXPECT_NO_THROW(any_subscription_callback_.dispatch(msg_shared_ptr_, message_info_));
EXPECT_EQ(callback_count, 1);
// Can't convert ConstSharedPtr to SharedPtr
EXPECT_THROW(
any_subscription_callback_.dispatch_intra_process(msg_const_shared_ptr_, message_info_),
std::runtime_error);
EXPECT_EQ(callback_count, 1);
// Promotes Unique into SharedPtr
EXPECT_NO_THROW(
any_subscription_callback_.dispatch_intra_process(std::move(msg_unique_ptr_), message_info_));
EXPECT_EQ(callback_count, 2);
}
TEST_F(TestAnySubscriptionCallback, set_dispatch_const_shared_ptr) {
int callback_count = 0;
auto const_shared_ptr_callback = [&callback_count](
std::shared_ptr<const test_msgs::msg::Empty>) {
callback_count++;
};
any_subscription_callback_.set(const_shared_ptr_callback);
// Ok to promote shared_ptr to ConstSharedPtr
EXPECT_NO_THROW(any_subscription_callback_.dispatch(msg_shared_ptr_, message_info_));
EXPECT_EQ(callback_count, 1);
EXPECT_NO_THROW(
any_subscription_callback_.dispatch_intra_process(msg_const_shared_ptr_, message_info_));
EXPECT_EQ(callback_count, 2);
// Not allowed to convert unique_ptr to const shared_ptr
EXPECT_THROW(
any_subscription_callback_.dispatch_intra_process(std::move(msg_unique_ptr_), message_info_),
std::runtime_error);
EXPECT_EQ(callback_count, 2);
}
TEST_F(TestAnySubscriptionCallback, set_dispatch_const_shared_ptr_w_info) {
int callback_count = 0;
auto const_shared_ptr_callback = [&callback_count](
std::shared_ptr<const test_msgs::msg::Empty>, const rclcpp::MessageInfo &) {
callback_count++;
};
any_subscription_callback_.set(
std::move(const_shared_ptr_callback));
// Ok to promote shared_ptr to ConstSharedPtr
EXPECT_NO_THROW(any_subscription_callback_.dispatch(msg_shared_ptr_, message_info_));
EXPECT_EQ(callback_count, 1);
EXPECT_NO_THROW(
any_subscription_callback_.dispatch_intra_process(msg_const_shared_ptr_, message_info_));
EXPECT_EQ(callback_count, 2);
// Not allowed to convert unique_ptr to const shared_ptr
EXPECT_THROW(
any_subscription_callback_.dispatch_intra_process(std::move(msg_unique_ptr_), message_info_),
std::runtime_error);
EXPECT_EQ(callback_count, 2);
}
TEST_F(TestAnySubscriptionCallback, set_dispatch_unique_ptr) {
int callback_count = 0;
auto unique_ptr_callback = [&callback_count](
std::unique_ptr<test_msgs::msg::Empty>) {
callback_count++;
};
any_subscription_callback_.set(unique_ptr_callback);
// Message is copied into unique_ptr
EXPECT_NO_THROW(any_subscription_callback_.dispatch(msg_shared_ptr_, message_info_));
EXPECT_EQ(callback_count, 1);
EXPECT_THROW(
any_subscription_callback_.dispatch_intra_process(msg_const_shared_ptr_, message_info_),
std::runtime_error);
EXPECT_EQ(callback_count, 1);
// Unique_ptr is_moved
EXPECT_NO_THROW(
any_subscription_callback_.dispatch_intra_process(std::move(msg_unique_ptr_), message_info_));
EXPECT_EQ(callback_count, 2);
}
TEST_F(TestAnySubscriptionCallback, set_dispatch_unique_ptr_w_info) {
int callback_count = 0;
auto unique_ptr_callback = [&callback_count](
std::unique_ptr<test_msgs::msg::Empty>, const rclcpp::MessageInfo &) {
callback_count++;
};
any_subscription_callback_.set(unique_ptr_callback);
// Message is copied into unique_ptr
EXPECT_NO_THROW(any_subscription_callback_.dispatch(msg_shared_ptr_, message_info_));
EXPECT_EQ(callback_count, 1);
EXPECT_THROW(
any_subscription_callback_.dispatch_intra_process(msg_const_shared_ptr_, message_info_),
std::runtime_error);
EXPECT_EQ(callback_count, 1);
// Unique_ptr is_moved
EXPECT_NO_THROW(
any_subscription_callback_.dispatch_intra_process(std::move(msg_unique_ptr_), message_info_));
EXPECT_EQ(callback_count, 2);
}

View File

@@ -0,0 +1,67 @@
// Copyright 2020 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 <gtest/gtest.h>
#include <chrono>
#include <memory>
#include "rclcpp/create_subscription.hpp"
#include "rclcpp/node.hpp"
#include "test_msgs/msg/empty.hpp"
#include "test_msgs/msg/empty.h"
using namespace std::chrono_literals;
class TestCreateSubscription : public ::testing::Test
{
public:
void SetUp() override
{
rclcpp::init(0, nullptr);
}
void TearDown() override
{
rclcpp::shutdown();
}
};
TEST_F(TestCreateSubscription, create) {
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
const rclcpp::QoS qos(10);
auto options = rclcpp::SubscriptionOptions();
auto callback = [](const test_msgs::msg::Empty::SharedPtr) {};
auto subscription =
rclcpp::create_subscription<test_msgs::msg::Empty>(node, "topic_name", qos, callback, options);
ASSERT_NE(nullptr, subscription);
EXPECT_STREQ("/ns/topic_name", subscription->get_topic_name());
}
TEST_F(TestCreateSubscription, create_with_statistics) {
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
const rclcpp::QoS qos(10);
auto options = rclcpp::SubscriptionOptions();
options.topic_stats_options.state = rclcpp::TopicStatisticsState::Enable;
options.topic_stats_options.publish_topic = "topic_statistics";
options.topic_stats_options.publish_period = 5min;
auto callback = [](const test_msgs::msg::Empty::SharedPtr) {};
auto subscription =
rclcpp::create_subscription<test_msgs::msg::Empty>(node, "topic_name", qos, callback, options);
ASSERT_NE(nullptr, subscription);
EXPECT_STREQ("/ns/topic_name", subscription->get_topic_name());
}

View File

@@ -0,0 +1,118 @@
// Copyright 2019 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 <gtest/gtest.h>
#include <atomic>
#include <chrono>
#include <memory>
#include "node_interfaces/node_wrapper.hpp"
#include "rclcpp/create_timer.hpp"
#include "rclcpp/executors.hpp"
#include "rclcpp/node.hpp"
using namespace std::chrono_literals;
TEST(TestCreateTimer, timer_executes)
{
rclcpp::init(0, nullptr);
auto node = std::make_shared<rclcpp::Node>("test_create_timer_node");
std::atomic<bool> got_callback{false};
rclcpp::TimerBase::SharedPtr timer;
timer = rclcpp::create_timer(
node,
node->get_clock(),
rclcpp::Duration(0ms),
[&got_callback, &timer]() {
got_callback = true;
timer->cancel();
});
rclcpp::spin_some(node);
ASSERT_TRUE(got_callback);
rclcpp::shutdown();
}
TEST(TestCreateTimer, call_with_node_wrapper_compiles)
{
rclcpp::init(0, nullptr);
NodeWrapper node("test_create_timer_call_with_node_wrapper_compiles");
rclcpp::TimerBase::SharedPtr timer;
timer = rclcpp::create_timer(
node,
node.get_node_clock_interface()->get_clock(),
rclcpp::Duration(0ms),
[]() {});
rclcpp::shutdown();
}
TEST(TestCreateTimer, call_wall_timer_with_bad_arguments)
{
rclcpp::init(0, nullptr);
NodeWrapper node("test_create_wall_timers_with_bad_arguments");
auto callback = []() {};
rclcpp::CallbackGroup::SharedPtr group = nullptr;
auto node_interface =
rclcpp::node_interfaces::get_node_base_interface(node).get();
auto timers_interface =
rclcpp::node_interfaces::get_node_timers_interface(node).get();
// Negative period
EXPECT_THROW(
rclcpp::create_wall_timer(-1ms, callback, group, node_interface, timers_interface),
std::invalid_argument);
// Very negative period
constexpr auto nanoseconds_min = std::chrono::nanoseconds::min();
EXPECT_THROW(
rclcpp::create_wall_timer(
nanoseconds_min, callback, group, node_interface, timers_interface),
std::invalid_argument);
// Period must be less than nanoseconds::max()
constexpr auto nanoseconds_max = std::chrono::nanoseconds::min();
EXPECT_THROW(
rclcpp::create_wall_timer(
nanoseconds_max, callback, group, node_interface, timers_interface),
std::invalid_argument);
EXPECT_NO_THROW(
rclcpp::create_wall_timer(
nanoseconds_max - 1us, callback, group, node_interface, timers_interface));
EXPECT_NO_THROW(
rclcpp::create_wall_timer(0ms, callback, group, node_interface, timers_interface));
// Period must be less than nanoseconds::max()
constexpr auto hours_max = std::chrono::hours::max();
EXPECT_THROW(
rclcpp::create_wall_timer(hours_max, callback, group, node_interface, timers_interface),
std::invalid_argument);
// node_interface is null
EXPECT_THROW(
rclcpp::create_wall_timer(1ms, callback, group, nullptr, timers_interface),
std::invalid_argument);
// timers_interface is null
EXPECT_THROW(
rclcpp::create_wall_timer(1ms, callback, group, node_interface, nullptr),
std::invalid_argument);
rclcpp::shutdown();
}

View File

@@ -32,11 +32,7 @@ class TestDuration : public ::testing::Test
{
};
// TEST(TestDuration, conversions) {
// TODO(tfoote) Implement conversion methods
// }
TEST(TestDuration, operators) {
TEST_F(TestDuration, operators) {
rclcpp::Duration old(1, 0);
rclcpp::Duration young(2, 0);
@@ -67,7 +63,7 @@ TEST(TestDuration, operators) {
EXPECT_TRUE(time == assignment_op_duration);
}
TEST(TestDuration, chrono_overloads) {
TEST_F(TestDuration, chrono_overloads) {
int64_t ns = 123456789l;
auto chrono_ns = std::chrono::nanoseconds(ns);
auto d1 = rclcpp::Duration(ns);
@@ -86,7 +82,7 @@ TEST(TestDuration, chrono_overloads) {
EXPECT_EQ(chrono_float_seconds, d5.to_chrono<decltype(chrono_float_seconds)>());
}
TEST(TestDuration, overflows) {
TEST_F(TestDuration, overflows) {
rclcpp::Duration max(std::numeric_limits<rcl_duration_value_t>::max());
rclcpp::Duration min(std::numeric_limits<rcl_duration_value_t>::min());
@@ -107,7 +103,7 @@ TEST(TestDuration, overflows) {
EXPECT_THROW(base_d_neg * 4, std::underflow_error);
}
TEST(TestDuration, negative_duration) {
TEST_F(TestDuration, negative_duration) {
rclcpp::Duration assignable_duration = rclcpp::Duration(0) - rclcpp::Duration(5, 0);
{
@@ -130,7 +126,7 @@ TEST(TestDuration, negative_duration) {
}
}
TEST(TestDuration, maximum_duration) {
TEST_F(TestDuration, maximum_duration) {
rclcpp::Duration max_duration = rclcpp::Duration::max();
rclcpp::Duration max(std::numeric_limits<int32_t>::max(), 999999999);
@@ -138,18 +134,105 @@ TEST(TestDuration, maximum_duration) {
}
static const int64_t HALF_SEC_IN_NS = 500 * 1000 * 1000;
static const int64_t ONE_SEC_IN_NS = 1000 * 1000 * 1000;
static const int64_t ONE_AND_HALF_SEC_IN_NS = 3 * HALF_SEC_IN_NS;
TEST(TestDuration, from_seconds) {
TEST_F(TestDuration, from_seconds) {
EXPECT_EQ(rclcpp::Duration(0), rclcpp::Duration::from_seconds(0.0));
EXPECT_EQ(rclcpp::Duration(0), rclcpp::Duration::from_seconds(0));
EXPECT_EQ(rclcpp::Duration(1, HALF_SEC_IN_NS), rclcpp::Duration::from_seconds(1.5));
EXPECT_EQ(rclcpp::Duration(-ONE_AND_HALF_SEC_IN_NS), rclcpp::Duration::from_seconds(-1.5));
}
TEST(TestDuration, std_chrono_constructors) {
TEST_F(TestDuration, std_chrono_constructors) {
EXPECT_EQ(rclcpp::Duration(0), rclcpp::Duration(0.0s));
EXPECT_EQ(rclcpp::Duration(0), rclcpp::Duration(0s));
EXPECT_EQ(rclcpp::Duration(1, HALF_SEC_IN_NS), rclcpp::Duration(1.5s));
EXPECT_EQ(rclcpp::Duration(-1, 0), rclcpp::Duration(-1s));
}
TEST_F(TestDuration, conversions) {
{
const rclcpp::Duration duration(HALF_SEC_IN_NS);
const auto duration_msg = static_cast<builtin_interfaces::msg::Duration>(duration);
EXPECT_EQ(duration_msg.sec, 0);
EXPECT_EQ(duration_msg.nanosec, HALF_SEC_IN_NS);
EXPECT_EQ(rclcpp::Duration(duration_msg).nanoseconds(), HALF_SEC_IN_NS);
const auto rmw_time = duration.to_rmw_time();
EXPECT_EQ(rmw_time.sec, 0u);
EXPECT_EQ(rmw_time.nsec, static_cast<uint64_t>(HALF_SEC_IN_NS));
const auto chrono_duration = duration.to_chrono<std::chrono::nanoseconds>();
EXPECT_EQ(chrono_duration.count(), HALF_SEC_IN_NS);
}
{
const rclcpp::Duration duration(ONE_SEC_IN_NS);
const auto duration_msg = static_cast<builtin_interfaces::msg::Duration>(duration);
EXPECT_EQ(duration_msg.sec, 1);
EXPECT_EQ(duration_msg.nanosec, 0u);
EXPECT_EQ(rclcpp::Duration(duration_msg).nanoseconds(), ONE_SEC_IN_NS);
const auto rmw_time = duration.to_rmw_time();
EXPECT_EQ(rmw_time.sec, 1u);
EXPECT_EQ(rmw_time.nsec, 0u);
const auto chrono_duration = duration.to_chrono<std::chrono::nanoseconds>();
EXPECT_EQ(chrono_duration.count(), ONE_SEC_IN_NS);
}
{
const rclcpp::Duration duration(ONE_AND_HALF_SEC_IN_NS);
auto duration_msg = static_cast<builtin_interfaces::msg::Duration>(duration);
EXPECT_EQ(duration_msg.sec, 1);
EXPECT_EQ(duration_msg.nanosec, HALF_SEC_IN_NS);
EXPECT_EQ(rclcpp::Duration(duration_msg).nanoseconds(), ONE_AND_HALF_SEC_IN_NS);
auto rmw_time = duration.to_rmw_time();
EXPECT_EQ(rmw_time.sec, 1u);
EXPECT_EQ(rmw_time.nsec, static_cast<uint64_t>(HALF_SEC_IN_NS));
auto chrono_duration = duration.to_chrono<std::chrono::nanoseconds>();
EXPECT_EQ(chrono_duration.count(), ONE_AND_HALF_SEC_IN_NS);
}
{
rclcpp::Duration duration(-HALF_SEC_IN_NS);
auto duration_msg = static_cast<builtin_interfaces::msg::Duration>(duration);
EXPECT_EQ(duration_msg.sec, -1);
EXPECT_EQ(duration_msg.nanosec, HALF_SEC_IN_NS);
EXPECT_EQ(rclcpp::Duration(duration_msg).nanoseconds(), -HALF_SEC_IN_NS);
EXPECT_THROW(duration.to_rmw_time(), std::runtime_error);
auto chrono_duration = duration.to_chrono<std::chrono::nanoseconds>();
EXPECT_EQ(chrono_duration.count(), -HALF_SEC_IN_NS);
}
{
rclcpp::Duration duration(-ONE_SEC_IN_NS);
auto duration_msg = static_cast<builtin_interfaces::msg::Duration>(duration);
EXPECT_EQ(duration_msg.sec, -1);
EXPECT_EQ(duration_msg.nanosec, 0u);
EXPECT_EQ(rclcpp::Duration(duration_msg).nanoseconds(), -ONE_SEC_IN_NS);
EXPECT_THROW(duration.to_rmw_time(), std::runtime_error);
auto chrono_duration = duration.to_chrono<std::chrono::nanoseconds>();
EXPECT_EQ(chrono_duration.count(), -ONE_SEC_IN_NS);
}
{
rclcpp::Duration duration(-ONE_AND_HALF_SEC_IN_NS);
auto duration_msg = static_cast<builtin_interfaces::msg::Duration>(duration);
EXPECT_EQ(duration_msg.sec, -2);
EXPECT_EQ(duration_msg.nanosec, HALF_SEC_IN_NS);
EXPECT_EQ(rclcpp::Duration(duration_msg).nanoseconds(), -ONE_AND_HALF_SEC_IN_NS);
EXPECT_THROW(duration.to_rmw_time(), std::runtime_error);
auto chrono_duration = duration.to_chrono<std::chrono::nanoseconds>();
EXPECT_EQ(chrono_duration.count(), -ONE_AND_HALF_SEC_IN_NS);
}
}

View File

@@ -0,0 +1,199 @@
// Copyright 2017 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 <gtest/gtest.h>
#include <algorithm>
#include <chrono>
#include <limits>
#include <memory>
#include <string>
#include "rcl/error_handling.h"
#include "rcl/time.h"
#include "rclcpp/clock.hpp"
#include "rclcpp/duration.hpp"
#include "rclcpp/rclcpp.hpp"
using namespace std::chrono_literals;
class TestExecutors : public ::testing::Test
{
protected:
static void SetUpTestCase()
{
rclcpp::init(0, nullptr);
}
void SetUp()
{
node = std::make_shared<rclcpp::Node>("my_node");
}
void TearDown()
{
node.reset();
}
rclcpp::Node::SharedPtr node;
};
// Make sure that executors detach from nodes when destructing
TEST_F(TestExecutors, detachOnDestruction) {
{
rclcpp::executors::SingleThreadedExecutor executor;
executor.add_node(node);
}
{
rclcpp::executors::SingleThreadedExecutor executor;
EXPECT_NO_THROW(executor.add_node(node));
}
}
// Make sure that the executor can automatically remove expired nodes correctly
TEST_F(TestExecutors, addTemporaryNode) {
rclcpp::executors::SingleThreadedExecutor executor;
executor.add_node(std::make_shared<rclcpp::Node>("temporary_node"));
EXPECT_NO_THROW(executor.spin_some());
}
// Make sure that the spin_until_future_complete works correctly with std::future
TEST_F(TestExecutors, testSpinUntilFutureComplete) {
rclcpp::executors::SingleThreadedExecutor executor;
std::future<void> future;
rclcpp::FutureReturnCode ret;
// test success
future = std::async(
[]() {
return;
});
ret = executor.spin_until_future_complete(future, 1s);
EXPECT_EQ(rclcpp::FutureReturnCode::SUCCESS, ret);
// test timeout
future = std::async(
[]() {
std::this_thread::sleep_for(1s);
return;
});
ret = executor.spin_until_future_complete(future, 100ms);
EXPECT_EQ(rclcpp::FutureReturnCode::TIMEOUT, ret);
}
// Make sure that the spin_until_future_complete works correctly with std::shared_future
TEST_F(TestExecutors, testSpinUntilFutureCompleteSharedFuture) {
rclcpp::executors::SingleThreadedExecutor executor;
std::future<void> future;
rclcpp::FutureReturnCode ret;
// test success
future = std::async(
[]() {
return;
});
ret = executor.spin_until_future_complete(future.share(), 1s);
EXPECT_EQ(rclcpp::FutureReturnCode::SUCCESS, ret);
// test timeout
future = std::async(
[]() {
std::this_thread::sleep_for(1s);
return;
});
ret = executor.spin_until_future_complete(future.share(), 100ms);
EXPECT_EQ(rclcpp::FutureReturnCode::TIMEOUT, ret);
}
class TestWaitable : public rclcpp::Waitable
{
public:
TestWaitable()
{
rcl_guard_condition_options_t guard_condition_options =
rcl_guard_condition_get_default_options();
gc_ = rcl_get_zero_initialized_guard_condition();
rcl_ret_t ret = rcl_guard_condition_init(
&gc_,
rclcpp::contexts::get_global_default_context()->get_rcl_context().get(),
guard_condition_options);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
}
}
bool
add_to_wait_set(rcl_wait_set_t * wait_set) override
{
rcl_ret_t ret = rcl_wait_set_add_guard_condition(wait_set, &gc_, NULL);
if (RCL_RET_OK != ret) {
return false;
}
ret = rcl_trigger_guard_condition(&gc_);
return RCL_RET_OK == ret;
}
bool
is_ready(rcl_wait_set_t * wait_set) override
{
(void)wait_set;
return true;
}
void
execute() override
{
count_++;
std::this_thread::sleep_for(100ms);
}
size_t
get_number_of_ready_guard_conditions() override {return 1;}
size_t
get_count()
{
return count_;
}
private:
size_t count_ = 0;
rcl_guard_condition_t gc_;
};
TEST_F(TestExecutors, testSpinAllvsSpinSome) {
{
rclcpp::executors::SingleThreadedExecutor executor;
auto waitable_interfaces = node->get_node_waitables_interface();
auto my_waitable = std::make_shared<TestWaitable>();
waitable_interfaces->add_waitable(my_waitable, nullptr);
executor.add_node(node);
executor.spin_all(1s);
executor.remove_node(node);
EXPECT_GT(my_waitable->get_count(), 1u);
waitable_interfaces->remove_waitable(my_waitable, nullptr);
}
{
rclcpp::executors::SingleThreadedExecutor executor;
auto waitable_interfaces = node->get_node_waitables_interface();
auto my_waitable = std::make_shared<TestWaitable>();
waitable_interfaces->add_waitable(my_waitable, nullptr);
executor.add_node(node);
executor.spin_some(1s);
executor.remove_node(node);
EXPECT_EQ(my_waitable->get_count(), 1u);
waitable_interfaces->remove_waitable(my_waitable, nullptr);
}
}

View File

@@ -14,10 +14,12 @@
#include <gtest/gtest.h>
#include <memory>
#include <string>
#include "rclcpp/logger.hpp"
#include "rclcpp/logging.hpp"
#include "rclcpp/node.hpp"
TEST(TestLogger, factory_functions) {
rclcpp::Logger logger = rclcpp::get_logger("test_logger");
@@ -33,3 +35,15 @@ TEST(TestLogger, hierarchy) {
rclcpp::Logger subsublogger = sublogger.get_child("grandchild");
EXPECT_STREQ("test_logger.child.grandchild", subsublogger.get_name());
}
TEST(TestLogger, get_node_logger) {
rclcpp::init(0, nullptr);
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
auto node_base = rclcpp::node_interfaces::get_node_base_interface(node);
auto logger = rclcpp::get_node_logger(node_base->get_rcl_node_handle());
EXPECT_STREQ(logger.get_name(), "ns.my_node");
logger = rclcpp::get_node_logger(nullptr);
EXPECT_STREQ(logger.get_name(), "rclcpp");
rclcpp::shutdown();
}

View File

@@ -2329,206 +2329,6 @@ TEST_F(TestNode, get_parameter_types_undeclared_parameters_allowed) {
}
}
// suppress deprecated function test warnings
#if !defined(_WIN32)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#else // !defined(_WIN32)
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
// test that it is possible to call get_parameter within the set_callback
TEST_F(TestNode, set_on_parameters_set_callback_get_parameter) {
auto node = std::make_shared<rclcpp::Node>("test_set_callback_get_parameter_node"_unq);
int64_t intval = node->declare_parameter("intparam", 42);
EXPECT_EQ(intval, 42);
double floatval = node->declare_parameter("floatparam", 5.4);
EXPECT_EQ(floatval, 5.4);
double floatout;
RCLCPP_SCOPE_EXIT({node->set_on_parameters_set_callback(nullptr);}); // always reset
auto on_set_parameters =
[&node, &floatout](const std::vector<rclcpp::Parameter> & parameters) {
rcl_interfaces::msg::SetParametersResult result;
result.successful = true;
if (parameters.size() != 1) {
result.successful = false;
}
if (parameters[0].get_value<int>() != 40) {
result.successful = false;
}
rclcpp::Parameter floatparam = node->get_parameter("floatparam");
if (floatparam.get_value<double>() != 5.4) {
result.successful = false;
}
floatout = floatparam.get_value<double>();
return result;
};
EXPECT_EQ(node->set_on_parameters_set_callback(on_set_parameters), nullptr);
ASSERT_NO_THROW(node->set_parameter({"intparam", 40}));
ASSERT_EQ(floatout, 5.4);
}
// test that calling set_parameter inside of a set_callback throws an exception
TEST_F(TestNode, set_on_parameters_set_callback_set_parameter) {
auto node = std::make_shared<rclcpp::Node>("test_set_callback_set_parameter_node"_unq);
int64_t intval = node->declare_parameter("intparam", 42);
EXPECT_EQ(intval, 42);
double floatval = node->declare_parameter("floatparam", 5.4);
EXPECT_EQ(floatval, 5.4);
RCLCPP_SCOPE_EXIT({node->set_on_parameters_set_callback(nullptr);}); // always reset
auto on_set_parameters =
[&node](const std::vector<rclcpp::Parameter> & parameters) {
rcl_interfaces::msg::SetParametersResult result;
result.successful = true;
if (parameters.size() != 1) {
result.successful = false;
}
if (parameters[0].get_value<int>() != 40) {
result.successful = false;
}
// This should throw an exception
node->set_parameter({"floatparam", 5.6});
return result;
};
EXPECT_EQ(node->set_on_parameters_set_callback(on_set_parameters), nullptr);
EXPECT_THROW(
{
node->set_parameter(rclcpp::Parameter("intparam", 40));
}, rclcpp::exceptions::ParameterModifiedInCallbackException);
}
// test that calling declare_parameter inside of a set_callback throws an exception
TEST_F(TestNode, set_on_parameters_set_callback_declare_parameter) {
auto node = std::make_shared<rclcpp::Node>("test_set_callback_declare_parameter_node"_unq);
int64_t intval = node->declare_parameter("intparam", 42);
EXPECT_EQ(intval, 42);
double floatval = node->declare_parameter("floatparam", 5.4);
EXPECT_EQ(floatval, 5.4);
RCLCPP_SCOPE_EXIT({node->set_on_parameters_set_callback(nullptr);}); // always reset
auto on_set_parameters =
[&node](const std::vector<rclcpp::Parameter> & parameters) {
rcl_interfaces::msg::SetParametersResult result;
result.successful = true;
if (parameters.size() != 1) {
result.successful = false;
}
if (parameters[0].get_value<int>() != 40) {
result.successful = false;
}
// This should throw an exception
node->declare_parameter("floatparam2", 5.6);
return result;
};
EXPECT_EQ(node->set_on_parameters_set_callback(on_set_parameters), nullptr);
EXPECT_THROW(
{
node->set_parameter(rclcpp::Parameter("intparam", 40));
}, rclcpp::exceptions::ParameterModifiedInCallbackException);
}
// test that calling undeclare_parameter inside a set_callback throws an exception
TEST_F(TestNode, set_on_parameters_set_callback_undeclare_parameter) {
auto node = std::make_shared<rclcpp::Node>("test_set_callback_undeclare_parameter_node"_unq);
int64_t intval = node->declare_parameter("intparam", 42);
EXPECT_EQ(intval, 42);
double floatval = node->declare_parameter("floatparam", 5.4);
EXPECT_EQ(floatval, 5.4);
RCLCPP_SCOPE_EXIT({node->set_on_parameters_set_callback(nullptr);}); // always reset
auto on_set_parameters =
[&node](const std::vector<rclcpp::Parameter> & parameters) {
rcl_interfaces::msg::SetParametersResult result;
result.successful = true;
if (parameters.size() != 1) {
result.successful = false;
}
if (parameters[0].get_value<int>() != 40) {
result.successful = false;
}
// This should throw an exception
node->undeclare_parameter("floatparam");
return result;
};
EXPECT_EQ(node->set_on_parameters_set_callback(on_set_parameters), nullptr);
EXPECT_THROW(
{
node->set_parameter(rclcpp::Parameter("intparam", 40));
}, rclcpp::exceptions::ParameterModifiedInCallbackException);
}
// test that calling set_on_parameters_set_callback from a set_callback throws an exception
TEST_F(TestNode, set_on_parameters_set_callback_set_on_parameters_set_callback) {
auto node = std::make_shared<rclcpp::Node>("test_set_callback_set_callback_node"_unq);
int64_t intval = node->declare_parameter("intparam", 42);
EXPECT_EQ(intval, 42);
double floatval = node->declare_parameter("floatparam", 5.4);
EXPECT_EQ(floatval, 5.4);
RCLCPP_SCOPE_EXIT({node->set_on_parameters_set_callback(nullptr);}); // always reset
auto on_set_parameters =
[&node](const std::vector<rclcpp::Parameter> & parameters) {
rcl_interfaces::msg::SetParametersResult result;
result.successful = true;
if (parameters.size() != 1) {
result.successful = false;
}
if (parameters[0].get_value<int>() != 40) {
result.successful = false;
}
auto bad_parameters =
[](const std::vector<rclcpp::Parameter> & parameters) {
(void)parameters;
rcl_interfaces::msg::SetParametersResult result;
return result;
};
// This should throw an exception
node->set_on_parameters_set_callback(bad_parameters);
return result;
};
EXPECT_EQ(node->set_on_parameters_set_callback(on_set_parameters), nullptr);
EXPECT_THROW(
{
node->set_parameter(rclcpp::Parameter("intparam", 40));
}, rclcpp::exceptions::ParameterModifiedInCallbackException);
}
// remove warning suppression
#if !defined(_WIN32)
# pragma GCC diagnostic pop
#else // !defined(_WIN32)
# pragma warning(pop)
#endif
void expect_qos_profile_eq(
const rmw_qos_profile_t & qos1, const rmw_qos_profile_t & qos2, bool is_publisher)
{

View File

@@ -105,6 +105,38 @@ TEST(TestNodeOptions, bad_ros_args) {
rclcpp::exceptions::UnknownROSArgsError);
}
TEST(TestNodeOptions, use_global_arguments) {
{
auto options = rclcpp::NodeOptions();
EXPECT_TRUE(options.use_global_arguments());
EXPECT_TRUE(options.get_rcl_node_options()->use_global_arguments);
}
{
auto options = rclcpp::NodeOptions().use_global_arguments(false);
EXPECT_FALSE(options.use_global_arguments());
EXPECT_FALSE(options.get_rcl_node_options()->use_global_arguments);
}
{
auto options = rclcpp::NodeOptions().use_global_arguments(true);
EXPECT_TRUE(options.use_global_arguments());
EXPECT_TRUE(options.get_rcl_node_options()->use_global_arguments);
}
{
auto options = rclcpp::NodeOptions();
EXPECT_TRUE(options.use_global_arguments());
EXPECT_TRUE(options.get_rcl_node_options()->use_global_arguments);
options.use_global_arguments(false);
EXPECT_FALSE(options.use_global_arguments());
EXPECT_FALSE(options.get_rcl_node_options()->use_global_arguments);
options.use_global_arguments(true);
EXPECT_TRUE(options.use_global_arguments());
EXPECT_TRUE(options.get_rcl_node_options()->use_global_arguments);
}
}
TEST(TestNodeOptions, enable_rosout) {
{
auto options = rclcpp::NodeOptions();
@@ -136,3 +168,33 @@ TEST(TestNodeOptions, enable_rosout) {
EXPECT_TRUE(options.get_rcl_node_options()->enable_rosout);
}
}
TEST(TestNodeOptions, copy) {
std::vector<std::string> expected_args{"--unknown-flag", "arg"};
auto options = rclcpp::NodeOptions().arguments(expected_args).use_global_arguments(false);
const rcl_node_options_t * rcl_options = options.get_rcl_node_options();
{
rclcpp::NodeOptions copied_options = options;
EXPECT_FALSE(copied_options.use_global_arguments());
EXPECT_EQ(expected_args, copied_options.arguments());
const rcl_node_options_t * copied_rcl_options = copied_options.get_rcl_node_options();
EXPECT_EQ(copied_rcl_options->use_global_arguments, rcl_options->use_global_arguments);
EXPECT_EQ(
rcl_arguments_get_count_unparsed(&copied_rcl_options->arguments),
rcl_arguments_get_count_unparsed(&rcl_options->arguments));
}
{
auto other_options = rclcpp::NodeOptions().use_global_arguments(true);
(void)other_options.get_rcl_node_options(); // force C structure initialization
other_options = options;
EXPECT_FALSE(other_options.use_global_arguments());
EXPECT_EQ(expected_args, other_options.arguments());
const rcl_node_options_t * other_rcl_options = other_options.get_rcl_node_options();
EXPECT_EQ(other_rcl_options->use_global_arguments, rcl_options->use_global_arguments);
EXPECT_EQ(
rcl_arguments_get_count_unparsed(&other_rcl_options->arguments),
rcl_arguments_get_count_unparsed(&rcl_options->arguments));
}
}

View File

@@ -32,7 +32,7 @@ protected:
}
};
TEST(TestParameter, not_set_variant) {
TEST_F(TestParameter, not_set_variant) {
// Direct instantiation
rclcpp::Parameter not_set_variant;
EXPECT_EQ(rclcpp::PARAMETER_NOT_SET, not_set_variant.get_type());
@@ -58,7 +58,7 @@ TEST(TestParameter, not_set_variant) {
rclcpp::Parameter::from_parameter_msg(not_set_param).get_type());
}
TEST(TestParameter, bool_variant) {
TEST_F(TestParameter, bool_variant) {
// Direct instantiation
rclcpp::Parameter bool_variant_true("bool_param", true);
EXPECT_EQ("bool_param", bool_variant_true.get_name());
@@ -116,7 +116,7 @@ TEST(TestParameter, bool_variant) {
bool_variant_false.get_value_message().type);
}
TEST(TestParameter, integer_variant) {
TEST_F(TestParameter, integer_variant) {
const int TEST_VALUE {42};
// Direct instantiation
@@ -164,7 +164,7 @@ TEST(TestParameter, integer_variant) {
from_msg.get_value_message().type);
}
TEST(TestParameter, long_integer_variant) {
TEST_F(TestParameter, long_integer_variant) {
const int64_t TEST_VALUE {std::numeric_limits<int64_t>::max()};
// Direct instantiation
@@ -212,7 +212,7 @@ TEST(TestParameter, long_integer_variant) {
from_msg.get_value_message().type);
}
TEST(TestParameter, float_variant) {
TEST_F(TestParameter, float_variant) {
const float TEST_VALUE {42.0f};
// Direct instantiation
@@ -260,7 +260,7 @@ TEST(TestParameter, float_variant) {
from_msg.get_value_message().type);
}
TEST(TestParameter, double_variant) {
TEST_F(TestParameter, double_variant) {
const double TEST_VALUE {-42.1};
// Direct instantiation
@@ -308,7 +308,7 @@ TEST(TestParameter, double_variant) {
from_msg.get_value_message().type);
}
TEST(TestParameter, string_variant) {
TEST_F(TestParameter, string_variant) {
const std::string TEST_VALUE {"ROS2"};
// Direct instantiation
@@ -354,7 +354,7 @@ TEST(TestParameter, string_variant) {
from_msg.get_value_message().type);
}
TEST(TestParameter, byte_array_variant) {
TEST_F(TestParameter, byte_array_variant) {
const std::vector<uint8_t> TEST_VALUE {0x52, 0x4f, 0x53, 0x32};
// Direct instantiation
@@ -402,7 +402,7 @@ TEST(TestParameter, byte_array_variant) {
from_msg.get_value_message().type);
}
TEST(TestParameter, bool_array_variant) {
TEST_F(TestParameter, bool_array_variant) {
const std::vector<bool> TEST_VALUE {false, true, true, false, false, true};
// Direct instantiation
@@ -450,7 +450,7 @@ TEST(TestParameter, bool_array_variant) {
from_msg.get_value_message().type);
}
TEST(TestParameter, integer_array_variant) {
TEST_F(TestParameter, integer_array_variant) {
const std::vector<int> TEST_VALUE
{42, -99, std::numeric_limits<int>::max(), std::numeric_limits<int>::lowest(), 0};
@@ -529,7 +529,7 @@ TEST(TestParameter, integer_array_variant) {
rcl_interfaces::msg::ParameterType::PARAMETER_INTEGER_ARRAY);
}
TEST(TestParameter, long_integer_array_variant) {
TEST_F(TestParameter, long_integer_array_variant) {
const std::vector<int64_t> TEST_VALUE
{42, -99, std::numeric_limits<int64_t>::max(), std::numeric_limits<int64_t>::lowest(), 0};
@@ -583,7 +583,7 @@ TEST(TestParameter, long_integer_array_variant) {
from_msg.get_value_message().type);
}
TEST(TestParameter, float_array_variant) {
TEST_F(TestParameter, float_array_variant) {
const std::vector<float> TEST_VALUE
{42.1f, -99.1f, std::numeric_limits<float>::max(), std::numeric_limits<float>::lowest(), 0.1f};
@@ -662,7 +662,7 @@ TEST(TestParameter, float_array_variant) {
from_msg.get_value_message().type);
}
TEST(TestParameter, double_array_variant) {
TEST_F(TestParameter, double_array_variant) {
const std::vector<double> TEST_VALUE
{42.1, -99.1, std::numeric_limits<double>::max(), std::numeric_limits<double>::lowest(), 0.1};
@@ -716,7 +716,7 @@ TEST(TestParameter, double_array_variant) {
from_msg.get_value_message().type);
}
TEST(TestParameter, string_array_variant) {
TEST_F(TestParameter, string_array_variant) {
const std::vector<std::string> TEST_VALUE {"R", "O", "S2"};
// Direct instantiation

View File

@@ -0,0 +1,249 @@
// Copyright 2019 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 <gtest/gtest.h>
#include <iostream>
#include <memory>
#include <string>
#include "rclcpp/exceptions.hpp"
#include "rclcpp/publisher.hpp"
#include "rclcpp/rclcpp.hpp"
#include "test_msgs/msg/empty.hpp"
namespace
{
template<typename ... Ts>
class NodeCreationPolicy
{
public:
rclcpp::NodeOptions & node_options()
{
return options_;
}
private:
rclcpp::NodeOptions options_;
};
template<typename T, typename ... Ts>
class NodeCreationPolicy<T, Ts...>
{
public:
NodeCreationPolicy()
{
gather<T, Ts...>(options_);
}
rclcpp::NodeOptions & node_options()
{
return options_;
}
private:
template<typename U>
static rclcpp::NodeOptions &
gather(rclcpp::NodeOptions & options)
{
return U::gather(options);
}
template<typename U, typename V, typename ... Ws>
static rclcpp::NodeOptions &
gather(rclcpp::NodeOptions & options)
{
return gather<V, Ws...>(U::gather(options));
}
rclcpp::NodeOptions options_;
};
template<bool value>
struct ShouldUseIntraprocess
{
static rclcpp::NodeOptions & gather(rclcpp::NodeOptions & options)
{
return options.use_intra_process_comms(value);
}
};
using UseIntraprocess = ShouldUseIntraprocess<true>;
using DoNotUseIntraprocess = ShouldUseIntraprocess<false>;
struct UseCustomContext
{
static rclcpp::NodeOptions & gather(rclcpp::NodeOptions & options)
{
auto context = rclcpp::Context::make_shared();
context->init(0, nullptr);
return options.context(context);
}
};
struct PrintTestDescription
{
template<typename T>
static std::string GetName(int i)
{
static_cast<void>(i);
return T::description;
}
};
} // namespace
template<typename TestDescription>
class TestPublisherSubscriptionCount : public ::testing::Test
{
public:
static void SetUpTestCase()
{
rclcpp::init(0, nullptr);
}
static void TearDownTestCase()
{
rclcpp::shutdown();
}
protected:
static void OnMessage(const test_msgs::msg::Empty::SharedPtr msg)
{
(void)msg;
}
std::chrono::milliseconds offset{2000};
};
/* Testing publisher subscription count api and internal process subscription count.
* Two subscriptions in the same topic, both using intraprocess comm.
*/
struct TwoSubscriptionsIntraprocessComm
{
static constexpr const char * description =
"two_subscriptions_intraprocess_comm";
using FirstNodeCreationPolicy = NodeCreationPolicy<UseIntraprocess>;
using SecondNodeCreationPolicy = NodeCreationPolicy<UseIntraprocess>;
static constexpr bool first_node_talks_intraprocess{true};
static constexpr bool both_nodes_talk_intraprocess{true};
};
/* Testing publisher subscription count api and internal process subscription count.
* Two subscriptions, one using intra-process comm and the other not using it.
*/
struct TwoSubscriptionsOneIntraprocessOneNot
{
static constexpr const char * description =
"two_subscriptions_one_intraprocess_one_not";
using FirstNodeCreationPolicy = NodeCreationPolicy<UseIntraprocess>;
using SecondNodeCreationPolicy = NodeCreationPolicy<>;
static constexpr bool first_node_talks_intraprocess{true};
static constexpr bool both_nodes_talk_intraprocess{false};
};
/* Testing publisher subscription count api and internal process subscription count.
* Two contexts, both using intra-process.
*/
struct TwoSubscriptionsInTwoContextsWithIntraprocessComm
{
static constexpr const char * description =
"two_subscriptions_in_two_contexts_with_intraprocess_comm";
using FirstNodeCreationPolicy = NodeCreationPolicy<UseIntraprocess>;
using SecondNodeCreationPolicy = NodeCreationPolicy<UseCustomContext, UseIntraprocess>;
static constexpr bool first_node_talks_intraprocess{true};
static constexpr bool both_nodes_talk_intraprocess{false};
};
/* Testing publisher subscription count api and internal process subscription count.
* Two contexts, both of them not using intra-process comm.
*/
struct TwoSubscriptionsInTwoContextsWithoutIntraprocessComm
{
static constexpr const char * description =
"two_subscriptions_in_two_contexts_without_intraprocess_comm";
using FirstNodeCreationPolicy = NodeCreationPolicy<>;
using SecondNodeCreationPolicy = NodeCreationPolicy<UseCustomContext>;
static constexpr bool first_node_talks_intraprocess{false};
static constexpr bool both_nodes_talk_intraprocess{false};
};
using AllTestDescriptions = ::testing::Types<
TwoSubscriptionsIntraprocessComm,
TwoSubscriptionsOneIntraprocessOneNot,
TwoSubscriptionsInTwoContextsWithIntraprocessComm,
TwoSubscriptionsInTwoContextsWithoutIntraprocessComm
>;
TYPED_TEST_CASE(TestPublisherSubscriptionCount, AllTestDescriptions, PrintTestDescription);
using test_msgs::msg::Empty;
TYPED_TEST(TestPublisherSubscriptionCount, increasing_and_decreasing_counts)
{
using TestDescription = TypeParam;
typename TestDescription::FirstNodeCreationPolicy my_node_creation_policy;
rclcpp::Node::SharedPtr node = std::make_shared<rclcpp::Node>(
"my_node",
"/ns",
my_node_creation_policy.node_options());
auto publisher = node->create_publisher<Empty>("/topic", 10);
EXPECT_EQ(publisher->get_subscription_count(), 0u);
EXPECT_EQ(publisher->get_intra_process_subscription_count(), 0u);
{
auto sub = node->create_subscription<Empty>(
"/topic", 10, &TestPublisherSubscriptionCount<TestDescription>::OnMessage);
rclcpp::sleep_for(this->offset);
EXPECT_EQ(publisher->get_subscription_count(), 1u);
EXPECT_EQ(
publisher->get_intra_process_subscription_count(),
(TestDescription::first_node_talks_intraprocess ? 1u : 0u));
{
typename TestDescription::SecondNodeCreationPolicy another_node_creation_policy;
rclcpp::Node::SharedPtr another_node = std::make_shared<rclcpp::Node>(
"another_node",
"/ns",
another_node_creation_policy.node_options());
auto another_sub = another_node->create_subscription<Empty>(
"/topic", 10, &TestPublisherSubscriptionCount<TestDescription>::OnMessage);
rclcpp::sleep_for(this->offset);
EXPECT_EQ(publisher->get_subscription_count(), 2u);
EXPECT_EQ(
publisher->get_intra_process_subscription_count(),
(TestDescription::first_node_talks_intraprocess ? 1u : 0u) +
(TestDescription::both_nodes_talk_intraprocess ? 1u : 0u));
}
rclcpp::sleep_for(this->offset);
EXPECT_EQ(publisher->get_subscription_count(), 1u);
EXPECT_EQ(
publisher->get_intra_process_subscription_count(),
(TestDescription::first_node_talks_intraprocess ? 1u : 0u));
}
/**
* Counts should be zero here, as all are subscriptions are out of scope.
* Subscriptions count checking is always preceeded with an sleep, as random failures had been
* detected without it. */
rclcpp::sleep_for(this->offset);
EXPECT_EQ(publisher->get_subscription_count(), 0u);
EXPECT_EQ(publisher->get_intra_process_subscription_count(), 0u);
}

View File

@@ -0,0 +1,166 @@
// Copyright 2019-2020 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 <gtest/gtest.h>
#include <iostream>
#include <string>
#include <memory>
#include "rclcpp/exceptions.hpp"
#include "rclcpp/rclcpp.hpp"
#include "test_msgs/msg/empty.hpp"
namespace
{
template<typename ... Ts>
class NodeCreationPolicy
{
public:
rclcpp::NodeOptions & node_options()
{
return options_;
}
private:
rclcpp::NodeOptions options_;
};
template<typename T, typename ... Ts>
class NodeCreationPolicy<T, Ts...>
{
public:
NodeCreationPolicy()
{
gather<T, Ts...>(options_);
}
rclcpp::NodeOptions & node_options()
{
return options_;
}
private:
template<typename U>
static rclcpp::NodeOptions &
gather(rclcpp::NodeOptions & options)
{
return U::gather(options);
}
template<typename U, typename V, typename ... Ws>
static rclcpp::NodeOptions &
gather(rclcpp::NodeOptions & options)
{
return gather<V, Ws...>(U::gather(options));
}
rclcpp::NodeOptions options_;
};
struct UseCustomContext
{
static rclcpp::NodeOptions & gather(rclcpp::NodeOptions & options)
{
auto context = rclcpp::Context::make_shared();
context->init(0, nullptr);
return options.context(context);
}
};
struct PrintTestDescription
{
template<typename T>
static std::string GetName(int i)
{
static_cast<void>(i);
return T::description;
}
};
} // namespace
template<typename TestDescription>
class TestSubscriptionPublisherCount : public ::testing::Test
{
public:
static void SetUpTestCase()
{
rclcpp::init(0, nullptr);
}
static void TearDownTestCase()
{
rclcpp::shutdown();
}
protected:
static void OnMessage(const test_msgs::msg::Empty::SharedPtr msg)
{
(void)msg;
}
std::chrono::milliseconds offset{2000};
};
struct OneContextPerTest
{
static constexpr const char * description = "one_context_test";
using NodeCreationPolicy = ::NodeCreationPolicy<>;
};
struct TwoContextsPerTest
{
static constexpr const char * description = "two_contexts_test";
using NodeCreationPolicy = ::NodeCreationPolicy<UseCustomContext>;
};
using AllTestDescriptions = ::testing::Types<OneContextPerTest, TwoContextsPerTest>;
TYPED_TEST_CASE(TestSubscriptionPublisherCount, AllTestDescriptions, PrintTestDescription);
using test_msgs::msg::Empty;
TYPED_TEST(TestSubscriptionPublisherCount, increasing_and_decreasing_counts)
{
using TestDescription = TypeParam;
rclcpp::Node::SharedPtr node = std::make_shared<rclcpp::Node>("my_node", "/ns");
auto subscription = node->create_subscription<Empty>(
"/topic", 10, &TestSubscriptionPublisherCount<TestDescription>::OnMessage);
EXPECT_EQ(subscription->get_publisher_count(), 0u);
{
auto pub = node->create_publisher<Empty>("/topic", 10);
rclcpp::sleep_for(this->offset);
EXPECT_EQ(subscription->get_publisher_count(), 1u);
{
typename TestDescription::NodeCreationPolicy node_creation_policy;
rclcpp::Node::SharedPtr another_node = std::make_shared<rclcpp::Node>(
"another_node",
"/ns",
node_creation_policy.node_options());
auto another_pub =
another_node->create_publisher<Empty>("/topic", 10);
rclcpp::sleep_for(this->offset);
EXPECT_EQ(subscription->get_publisher_count(), 2u);
}
rclcpp::sleep_for(this->offset);
EXPECT_EQ(subscription->get_publisher_count(), 1u);
}
rclcpp::sleep_for(this->offset);
EXPECT_EQ(subscription->get_publisher_count(), 0u);
}

View File

@@ -45,7 +45,7 @@ protected:
}
};
TEST(TestTime, clock_type_access) {
TEST_F(TestTime, clock_type_access) {
rclcpp::Clock ros_clock(RCL_ROS_TIME);
EXPECT_EQ(RCL_ROS_TIME, ros_clock.get_clock_type());
@@ -57,7 +57,7 @@ TEST(TestTime, clock_type_access) {
}
// Check that the clock may go out of the scope before the jump callback without leading in UB.
TEST(TestTime, clock_jump_callback_destruction_order) {
TEST_F(TestTime, clock_jump_callback_destruction_order) {
rclcpp::JumpHandler::SharedPtr handler;
{
rclcpp::Clock ros_clock(RCL_ROS_TIME);
@@ -68,7 +68,7 @@ TEST(TestTime, clock_jump_callback_destruction_order) {
}
}
TEST(TestTime, time_sources) {
TEST_F(TestTime, time_sources) {
using builtin_interfaces::msg::Time;
rclcpp::Clock ros_clock(RCL_ROS_TIME);
Time ros_now = ros_clock.now();
@@ -86,44 +86,124 @@ TEST(TestTime, time_sources) {
EXPECT_NE(0u, steady_now.nanosec);
}
TEST(TestTime, conversions) {
static const int64_t HALF_SEC_IN_NS = 500 * 1000 * 1000;
static const int64_t ONE_SEC_IN_NS = 1000 * 1000 * 1000;
static const int64_t ONE_AND_HALF_SEC_IN_NS = 3 * HALF_SEC_IN_NS;
TEST_F(TestTime, conversions) {
rclcpp::Clock system_clock(RCL_SYSTEM_TIME);
rclcpp::Time now = system_clock.now();
builtin_interfaces::msg::Time now_msg = now;
rclcpp::Time now_again = now_msg;
EXPECT_EQ(now.nanoseconds(), now_again.nanoseconds());
builtin_interfaces::msg::Time msg;
msg.sec = 12345;
msg.nanosec = 67890;
rclcpp::Time time = msg;
EXPECT_EQ(
RCL_S_TO_NS(static_cast<int64_t>(msg.sec)) + static_cast<int64_t>(msg.nanosec),
time.nanoseconds());
EXPECT_EQ(static_cast<int64_t>(msg.sec), RCL_NS_TO_S(time.nanoseconds()));
builtin_interfaces::msg::Time negative_time_msg;
negative_time_msg.sec = -1;
negative_time_msg.nanosec = 1;
EXPECT_ANY_THROW(
{
rclcpp::Time negative_time = negative_time_msg;
});
rclcpp::Time now = system_clock.now();
builtin_interfaces::msg::Time now_msg = now;
EXPECT_ANY_THROW(rclcpp::Time(-1, 1));
rclcpp::Time now_again = now_msg;
EXPECT_EQ(now.nanoseconds(), now_again.nanoseconds());
}
EXPECT_ANY_THROW(
{
rclcpp::Time assignment(1, 2);
assignment = negative_time_msg;
});
rclcpp::Time positive_time = rclcpp::Time(12345, 67890u);
builtin_interfaces::msg::Time msg = positive_time;
EXPECT_EQ(msg.sec, 12345);
EXPECT_EQ(msg.nanosec, 67890u);
rclcpp::Time time = msg;
EXPECT_EQ(time.nanoseconds(), positive_time.nanoseconds());
EXPECT_EQ(
RCL_S_TO_NS(static_cast<int64_t>(msg.sec)) + static_cast<int64_t>(msg.nanosec),
time.nanoseconds());
EXPECT_EQ(static_cast<int64_t>(msg.sec), RCL_NS_TO_S(time.nanoseconds()));
}
// throw on construction/assignment of negative times
{
builtin_interfaces::msg::Time negative_time_msg;
negative_time_msg.sec = -1;
negative_time_msg.nanosec = 1;
EXPECT_ANY_THROW(
{
rclcpp::Time negative_time = negative_time_msg;
});
EXPECT_ANY_THROW(rclcpp::Time(-1, 1));
EXPECT_ANY_THROW(
{
rclcpp::Time assignment(1, 2);
assignment = negative_time_msg;
});
}
{
const rclcpp::Time time(HALF_SEC_IN_NS);
const auto time_msg = static_cast<builtin_interfaces::msg::Time>(time);
EXPECT_EQ(time_msg.sec, 0);
EXPECT_EQ(time_msg.nanosec, HALF_SEC_IN_NS);
EXPECT_EQ(rclcpp::Time(time_msg).nanoseconds(), HALF_SEC_IN_NS);
}
{
const rclcpp::Time time(ONE_SEC_IN_NS);
const auto time_msg = static_cast<builtin_interfaces::msg::Time>(time);
EXPECT_EQ(time_msg.sec, 1);
EXPECT_EQ(time_msg.nanosec, 0u);
EXPECT_EQ(rclcpp::Time(time_msg).nanoseconds(), ONE_SEC_IN_NS);
}
{
const rclcpp::Time time(ONE_AND_HALF_SEC_IN_NS);
auto time_msg = static_cast<builtin_interfaces::msg::Time>(time);
EXPECT_EQ(time_msg.sec, 1);
EXPECT_EQ(time_msg.nanosec, HALF_SEC_IN_NS);
EXPECT_EQ(rclcpp::Time(time_msg).nanoseconds(), ONE_AND_HALF_SEC_IN_NS);
}
{
// Can rclcpp::Time be negative or not? The following constructor works:
rclcpp::Time time(-HALF_SEC_IN_NS);
auto time_msg = static_cast<builtin_interfaces::msg::Time>(time);
EXPECT_EQ(time_msg.sec, -1);
EXPECT_EQ(time_msg.nanosec, HALF_SEC_IN_NS);
// The opposite conversion throws...
EXPECT_ANY_THROW(
{
rclcpp::Time negative_time(time_msg);
});
}
{
// Can rclcpp::Time be negative or not? The following constructor works:
rclcpp::Time time(-ONE_SEC_IN_NS);
auto time_msg = static_cast<builtin_interfaces::msg::Time>(time);
EXPECT_EQ(time_msg.sec, -1);
EXPECT_EQ(time_msg.nanosec, 0u);
// The opposite conversion throws...
EXPECT_ANY_THROW(
{
rclcpp::Time negative_time(time_msg);
});
}
{
// Can rclcpp::Time be negative or not? The following constructor works:
rclcpp::Time time(-ONE_AND_HALF_SEC_IN_NS);
auto time_msg = static_cast<builtin_interfaces::msg::Time>(time);
EXPECT_EQ(time_msg.sec, -2);
EXPECT_EQ(time_msg.nanosec, HALF_SEC_IN_NS);
// The opposite conversion throws...
EXPECT_ANY_THROW(
{
rclcpp::Time negative_time(time_msg);
});
}
}
TEST(TestTime, operators) {
TEST_F(TestTime, operators) {
rclcpp::Time old(1, 0);
rclcpp::Time young(2, 0);
@@ -178,7 +258,7 @@ TEST(TestTime, operators) {
}
}
TEST(TestTime, overflow_detectors) {
TEST_F(TestTime, overflow_detectors) {
/////////////////////////////////////////////////////////////////////////////
// Test logical_eq call first:
EXPECT_TRUE(logical_eq(false, false));
@@ -198,8 +278,8 @@ TEST(TestTime, overflow_detectors) {
// 256 * 256 = 64K total loops, should be pretty fast on everything
for (big_type_t y = min_val; y <= max_val; ++y) {
for (big_type_t x = min_val; x <= max_val; ++x) {
const big_type_t sum = x + y;
const big_type_t diff = x - y;
const big_type_t sum = static_cast<big_type_t>(x + y);
const big_type_t diff = static_cast<big_type_t>(x - y);
const bool add_will_overflow =
rclcpp::add_will_overflow(test_type_t(x), test_type_t(y));
@@ -235,7 +315,7 @@ TEST(TestTime, overflow_detectors) {
EXPECT_TRUE(rclcpp::sub_will_underflow<int64_t>(INT64_MIN, 1));
}
TEST(TestTime, overflows) {
TEST_F(TestTime, overflows) {
rclcpp::Time max_time(std::numeric_limits<rcl_time_point_value_t>::max());
rclcpp::Time min_time(std::numeric_limits<rcl_time_point_value_t>::min());
rclcpp::Duration one(1);
@@ -267,7 +347,7 @@ TEST(TestTime, overflows) {
EXPECT_NO_THROW(one_time - two_time);
}
TEST(TestTime, seconds) {
TEST_F(TestTime, seconds) {
EXPECT_DOUBLE_EQ(0.0, rclcpp::Time(0, 0).seconds());
EXPECT_DOUBLE_EQ(4.5, rclcpp::Time(4, 500000000).seconds());
EXPECT_DOUBLE_EQ(2.5, rclcpp::Time(0, 2500000000).seconds());

View File

@@ -18,6 +18,7 @@
#include <chrono>
#include <exception>
#include <memory>
#include <utility>
#include "rcl/timer.h"
@@ -151,3 +152,42 @@ TEST_F(TestTimer, test_run_cancel_timer)
EXPECT_TRUE(has_timer_run.load());
EXPECT_TRUE(timer->is_canceled());
}
TEST_F(TestTimer, test_bad_arguments) {
auto node_base = rclcpp::node_interfaces::get_node_base_interface(test_node);
auto context = node_base->get_context();
auto steady_clock = std::make_shared<rclcpp::Clock>(RCL_STEADY_TIME);
// Negative period
EXPECT_THROW(
rclcpp::GenericTimer<void (*)()>(steady_clock, -1ms, []() {}, context),
rclcpp::exceptions::RCLInvalidArgument);
// Very negative period
constexpr auto nanoseconds_min = std::chrono::nanoseconds::min();
EXPECT_THROW(
rclcpp::GenericTimer<void (*)()>(
steady_clock, nanoseconds_min, []() {}, context),
rclcpp::exceptions::RCLInvalidArgument);
// nanoseconds max, should be ok
constexpr auto nanoseconds_max = std::chrono::nanoseconds::max();
EXPECT_NO_THROW(
rclcpp::GenericTimer<void (*)()>(
steady_clock, nanoseconds_max, []() {}, context));
// 0 duration period, should be ok
EXPECT_NO_THROW(
rclcpp::GenericTimer<void (*)()>(steady_clock, 0ms, []() {}, context));
// context is null, which resorts to default
EXPECT_NO_THROW(
rclcpp::GenericTimer<void (*)()>(steady_clock, 1ms, []() {}, nullptr));
// Clock is unitialized
auto unitialized_clock = std::make_shared<rclcpp::Clock>(RCL_CLOCK_UNINITIALIZED);
EXPECT_THROW(
rclcpp::GenericTimer<void (*)()>(unitialized_clock, 1us, []() {}, context),
rclcpp::exceptions::RCLError);
}

Some files were not shown because too many files have changed in this diff Show More