diff --git a/rclcpp/CMakeLists.txt b/rclcpp/CMakeLists.txt index 3918120e5a..1e0581451b 100644 --- a/rclcpp/CMakeLists.txt +++ b/rclcpp/CMakeLists.txt @@ -101,19 +101,65 @@ configure_file( COPYONLY ) # generate header with logging macros -set(python_code +set(python_code_logging "import em" "em.invoke(['-o', 'include/rclcpp/logging.hpp', '${CMAKE_CURRENT_SOURCE_DIR}/resource/logging.hpp.em'])") -string(REPLACE ";" "$" python_code "${python_code}") +string(REPLACE ";" "$" python_code_logging "${python_code_logging}") add_custom_command(OUTPUT include/rclcpp/logging.hpp COMMAND ${CMAKE_COMMAND} -E make_directory "include/rclcpp" - COMMAND ${PYTHON_EXECUTABLE} ARGS -c "${python_code}" + COMMAND ${PYTHON_EXECUTABLE} ARGS -c "${python_code_logging}" DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/logging.hpp.em.watch" COMMENT "Expanding logging.hpp.em" VERBATIM ) list(APPEND ${PROJECT_NAME}_SRCS include/rclcpp/logging.hpp) + +file(GLOB interface_files "include/rclcpp/node_interfaces/node_*_interface.hpp") +foreach(interface_file ${interface_files}) + get_filename_component(interface_name ${interface_file} NAME_WE) + + # "watch" template for changes + configure_file( + "resource/interface_traits.hpp.em" + "${CMAKE_CURRENT_BINARY_DIR}/${interface_name}_traits.hpp.em.watch" + COPYONLY + ) + set(python_${interface_name}_traits + "import em" + "em.invoke(['-D', 'interface_name = \\'${interface_name}\\'', '-o', 'include/rclcpp/node_interfaces/${interface_name}_traits.hpp', '${CMAKE_CURRENT_SOURCE_DIR}/resource/interface_traits.hpp.em'])") + string(REPLACE ";" "$" python_${interface_name}_traits "${python_${interface_name}_traits}") + add_custom_command(OUTPUT include/rclcpp/node_interfaces/${interface_name}_traits.hpp + COMMAND ${CMAKE_COMMAND} -E make_directory "include/rclcpp/node_interfaces" + COMMAND ${PYTHON_EXECUTABLE} ARGS -c "${python_${interface_name}_traits}" + DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${interface_name}_traits.hpp.em.watch" + COMMENT "Expanding interface_traits.hpp.em into ${interface_name}_traits.hpp" + VERBATIM + ) + list(APPEND ${PROJECT_NAME}_SRCS + include/rclcpp/node_interfaces/${interface_name}_traits.hpp) + + # "watch" template for changes + configure_file( + "resource/get_interface.hpp.em" + "get_${interface_name}.hpp.em.watch" + COPYONLY + ) + set(python_get_${interface_name} + "import em" + "em.invoke(['-D', 'interface_name = \\'${interface_name}\\'', '-o', 'include/rclcpp/node_interfaces/get_${interface_name}.hpp', '${CMAKE_CURRENT_SOURCE_DIR}/resource/get_interface.hpp.em'])") + string(REPLACE ";" "$" python_get_${interface_name} "${python_get_${interface_name}}") + add_custom_command(OUTPUT include/rclcpp/node_interfaces/get_${interface_name}.hpp + COMMAND ${CMAKE_COMMAND} -E make_directory "include/rclcpp/node_interfaces" + COMMAND ${PYTHON_EXECUTABLE} ARGS -c "${python_get_${interface_name}}" + DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/get_${interface_name}.hpp.em.watch" + COMMENT "Expanding get_interface.hpp.em into get_${interface_file}.hpp" + VERBATIM + ) + list(APPEND ${PROJECT_NAME}_SRCS + include/rclcpp/node_interfaces/get_${interface_name}.hpp) +endforeach() + include_directories("${CMAKE_CURRENT_BINARY_DIR}/include") add_library(${PROJECT_NAME} @@ -532,6 +578,14 @@ if(BUILD_TESTING) 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) diff --git a/rclcpp/include/rclcpp/create_timer.hpp b/rclcpp/include/rclcpp/create_timer.hpp index 208474f345..c541ba4616 100644 --- a/rclcpp/include/rclcpp/create_timer.hpp +++ b/rclcpp/include/rclcpp/create_timer.hpp @@ -32,8 +32,8 @@ namespace rclcpp template typename rclcpp::TimerBase::SharedPtr create_timer( - node_interfaces::NodeBaseInterface * node_base, - node_interfaces::NodeTimersInterface * node_timers, + std::shared_ptr node_base, + std::shared_ptr node_timers, rclcpp::Clock::SharedPtr clock, rclcpp::Duration period, CallbackT && callback, diff --git a/rclcpp/include/rclcpp/node_interfaces/get_node_base_interface.hpp b/rclcpp/include/rclcpp/node_interfaces/get_node_base_interface.hpp deleted file mode 100644 index cfc5917689..0000000000 --- a/rclcpp/include/rclcpp/node_interfaces/get_node_base_interface.hpp +++ /dev/null @@ -1,149 +0,0 @@ -// 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. - -#ifndef RCLCPP__NODE_INTERFACES__GET_NODE_BASE_INTERFACE_HPP_ -#define RCLCPP__NODE_INTERFACES__GET_NODE_BASE_INTERFACE_HPP_ - -#include -#include -#include - -#include "rclcpp/node_interfaces/node_base_interface.hpp" - -/// This header provides the get_node_base_interface() template function. -/** - * This function is useful for getting the NodeBaseInterface pointer from - * various kinds of Node-like classes. - * - * It's able to get the NodeBaseInterface pointer so long as the class - * has a method called ``get_node_base_interface()`` which returns - * either a pointer (const or not) to a NodeBaseInterface or a - * std::shared_ptr to a NodeBaseInterface. - */ - -namespace rclcpp -{ -namespace node_interfaces -{ - -namespace detail -{ - -// This is a meta-programming checker for if a given Node-like object has a -// getter called get_node_base_interface() which returns various types, -// e.g. const pointer or a shared pointer. -template -struct has_get_node_base_interface -{ -private: - template - static constexpr - auto - check(T *)->typename std::is_same< - decltype(std::declval().get_node_base_interface()), - ReturnType - >::type; - - template - static constexpr - std::false_type - check(...); - -public: - using type = decltype(check(nullptr)); - static constexpr bool value = type::value; -}; - -// If NodeType is a pointer to NodeBaseInterface already (just normal function overload). -inline -rclcpp::node_interfaces::NodeBaseInterface * -get_node_base_interface_from_pointer(rclcpp::node_interfaces::NodeBaseInterface * pointer) -{ - return pointer; -} - -// If NodeType has a method called get_node_base_interface() which returns a shared pointer. -template< - typename NodeType, - typename std::enable_if::type, - std::shared_ptr - >::value, int>::type = 0 -> -rclcpp::node_interfaces::NodeBaseInterface * -get_node_base_interface_from_pointer(NodeType node_pointer) -{ - return node_pointer->get_node_base_interface().get(); -} - -// If NodeType has a method called get_node_base_interface() which returns a pointer. -template< - typename NodeType, - typename std::enable_if::type, - rclcpp::node_interfaces::NodeBaseInterface * - >::value, int>::type = 0 -> -rclcpp::node_interfaces::NodeBaseInterface * -get_node_base_interface_from_pointer(NodeType node_pointer) -{ - return node_pointer->get_node_base_interface(); -} - -// Forward shared_ptr's to const node pointer signatures. -template< - typename NodeType, - typename std::enable_if::type::element_type> * - >::value, int>::type = 0 -> -rclcpp::node_interfaces::NodeBaseInterface * -get_node_base_interface_from_pointer(NodeType node_shared_pointer) -{ - return get_node_base_interface_from_pointer(node_shared_pointer->get()); -} - -} // namespace detail - -/// Get the NodeBaseInterface as a pointer from a pointer to a "Node like" object. -template< - typename NodeType, - typename std::enable_if::value, int>::type = 0 -> -rclcpp::node_interfaces::NodeBaseInterface * -get_node_base_interface(NodeType node_pointer) -{ - // Forward pointers to detail implmentation directly. - return detail::get_node_base_interface_from_pointer(node_pointer); -} - -/// Get the NodeBaseInterface as a pointer from a "Node like" object. -template< - typename NodeType, - typename std::enable_if< - !std::is_pointer::type>::value, int - >::type = 0 -> -rclcpp::node_interfaces::NodeBaseInterface * -get_node_base_interface(NodeType && node_reference) -{ - // Forward references to detail implmentation as a pointer. - return detail::get_node_base_interface_from_pointer(&node_reference); -} - -} // namespace node_interfaces -} // namespace rclcpp - -#endif // RCLCPP__NODE_INTERFACES__GET_NODE_BASE_INTERFACE_HPP_ diff --git a/rclcpp/include/rclcpp/node_interfaces/get_node_timers_interface.hpp b/rclcpp/include/rclcpp/node_interfaces/get_node_timers_interface.hpp deleted file mode 100644 index 9c54f06e9c..0000000000 --- a/rclcpp/include/rclcpp/node_interfaces/get_node_timers_interface.hpp +++ /dev/null @@ -1,149 +0,0 @@ -// 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. - -#ifndef RCLCPP__NODE_INTERFACES__GET_NODE_TIMERS_INTERFACE_HPP_ -#define RCLCPP__NODE_INTERFACES__GET_NODE_TIMERS_INTERFACE_HPP_ - -#include -#include -#include - -#include "rclcpp/node_interfaces/node_timers_interface.hpp" - -/// This header provides the get_node_timers_interface() template function. -/** - * This function is useful for getting the NodeTimersInterface pointer from - * various kinds of Node-like classes. - * - * It's able to get the NodeTimersInterface pointer so long as the class - * has a method called ``get_node_timers_interface()`` which returns - * either a pointer (const or not) to a NodeTimersInterface or a - * std::shared_ptr to a NodeTimersInterface. - */ - -namespace rclcpp -{ -namespace node_interfaces -{ - -namespace detail -{ - -// This is a meta-programming checker for if a given Node-like object has a -// getter called get_node_timers_interface() which returns various types, -// e.g. const pointer or a shared pointer. -template -struct has_get_node_timers_interface -{ -private: - template - static constexpr - auto - check(T *)->typename std::is_same< - decltype(std::declval().get_node_timers_interface()), - ReturnType - >::type; - - template - static constexpr - std::false_type - check(...); - -public: - using type = decltype(check(nullptr)); - static constexpr bool value = type::value; -}; - -// If NodeType is a pointer to NodeTimersInterface already (just normal function overload). -inline -rclcpp::node_interfaces::NodeTimersInterface * -get_node_timers_interface_from_pointer(rclcpp::node_interfaces::NodeTimersInterface * pointer) -{ - return pointer; -} - -// If NodeType has a method called get_node_timers_interface() which returns a shared pointer. -template< - typename NodeType, - typename std::enable_if::type, - std::shared_ptr - >::value, int>::type = 0 -> -rclcpp::node_interfaces::NodeTimersInterface * -get_node_timers_interface_from_pointer(NodeType node_pointer) -{ - return node_pointer->get_node_timers_interface().get(); -} - -// If NodeType has a method called get_node_timers_interface() which returns a pointer. -template< - typename NodeType, - typename std::enable_if::type, - rclcpp::node_interfaces::NodeTimersInterface * - >::value, int>::type = 0 -> -rclcpp::node_interfaces::NodeTimersInterface * -get_node_timers_interface_from_pointer(NodeType node_pointer) -{ - return node_pointer->get_node_timers_interface(); -} - -// Forward shared_ptr's to const node pointer signatures. -template< - typename NodeType, - typename std::enable_if::type::element_type> * - >::value, int>::type = 0 -> -rclcpp::node_interfaces::NodeTimersInterface * -get_node_timers_interface_from_pointer(NodeType node_shared_pointer) -{ - return get_node_timers_interface_from_pointer(node_shared_pointer->get()); -} - -} // namespace detail - -/// Get the NodeTimersInterface as a pointer from a pointer to a "Node like" object. -template< - typename NodeType, - typename std::enable_if::value, int>::type = 0 -> -rclcpp::node_interfaces::NodeTimersInterface * -get_node_timers_interface(NodeType node_pointer) -{ - // Forward pointers to detail implmentation directly. - return detail::get_node_timers_interface_from_pointer(node_pointer); -} - -/// Get the NodeTimersInterface as a pointer from a "Node like" object. -template< - typename NodeType, - typename std::enable_if< - !std::is_pointer::type>::value, int - >::type = 0 -> -rclcpp::node_interfaces::NodeTimersInterface * -get_node_timers_interface(NodeType && node_reference) -{ - // Forward references to detail implmentation as a pointer. - return detail::get_node_timers_interface_from_pointer(&node_reference); -} - -} // namespace node_interfaces -} // namespace rclcpp - -#endif // RCLCPP__NODE_INTERFACES__GET_NODE_TIMERS_INTERFACE_HPP_ diff --git a/rclcpp/include/rclcpp/node_interfaces/get_node_topics_interface.hpp b/rclcpp/include/rclcpp/node_interfaces/get_node_topics_interface.hpp deleted file mode 100644 index c84234282f..0000000000 --- a/rclcpp/include/rclcpp/node_interfaces/get_node_topics_interface.hpp +++ /dev/null @@ -1,149 +0,0 @@ -// 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. - -#ifndef RCLCPP__NODE_INTERFACES__GET_NODE_TOPICS_INTERFACE_HPP_ -#define RCLCPP__NODE_INTERFACES__GET_NODE_TOPICS_INTERFACE_HPP_ - -#include -#include -#include - -#include "rclcpp/node_interfaces/node_topics_interface.hpp" - -/// This header provides the get_node_topics_interface() template function. -/** - * This function is useful for getting the NodeTopicsInterface pointer from - * various kinds of Node-like classes. - * - * It's able to get the NodeTopicsInterface pointer so long as the class - * has a method called ``get_node_topics_interface()`` which returns - * either a pointer (const or not) to a NodeTopicsInterface or a - * std::shared_ptr to a NodeTopicsInterface. - */ - -namespace rclcpp -{ -namespace node_interfaces -{ - -namespace detail -{ - -// This is a meta-programming checker for if a given Node-like object has a -// getter called get_node_topics_interface() which returns various types, -// e.g. const pointer or a shared pointer. -template -struct has_get_node_topics_interface -{ -private: - template - static constexpr - auto - check(T *)->typename std::is_same< - decltype(std::declval().get_node_topics_interface()), - ReturnType - >::type; - - template - static constexpr - std::false_type - check(...); - -public: - using type = decltype(check(nullptr)); - static constexpr bool value = type::value; -}; - -// If NodeType is a pointer to NodeTopicsInterface already (just normal function overload). -inline -rclcpp::node_interfaces::NodeTopicsInterface * -get_node_topics_interface_from_pointer(rclcpp::node_interfaces::NodeTopicsInterface * pointer) -{ - return pointer; -} - -// If NodeType has a method called get_node_topics_interface() which returns a shared pointer. -template< - typename NodeType, - typename std::enable_if::type, - std::shared_ptr - >::value, int>::type = 0 -> -rclcpp::node_interfaces::NodeTopicsInterface * -get_node_topics_interface_from_pointer(NodeType node_pointer) -{ - return node_pointer->get_node_topics_interface().get(); -} - -// If NodeType has a method called get_node_topics_interface() which returns a pointer. -template< - typename NodeType, - typename std::enable_if::type, - rclcpp::node_interfaces::NodeTopicsInterface * - >::value, int>::type = 0 -> -rclcpp::node_interfaces::NodeTopicsInterface * -get_node_topics_interface_from_pointer(NodeType node_pointer) -{ - return node_pointer->get_node_topics_interface(); -} - -// Forward shared_ptr's to const node pointer signatures. -template< - typename NodeType, - typename std::enable_if::type::element_type> * - >::value, int>::type = 0 -> -rclcpp::node_interfaces::NodeTopicsInterface * -get_node_topics_interface_from_pointer(NodeType node_shared_pointer) -{ - return get_node_topics_interface_from_pointer(node_shared_pointer->get()); -} - -} // namespace detail - -/// Get the NodeTopicsInterface as a pointer from a pointer to a "Node like" object. -template< - typename NodeType, - typename std::enable_if::value, int>::type = 0 -> -rclcpp::node_interfaces::NodeTopicsInterface * -get_node_topics_interface(NodeType node_pointer) -{ - // Forward pointers to detail implmentation directly. - return detail::get_node_topics_interface_from_pointer(node_pointer); -} - -/// Get the NodeTopicsInterface as a pointer from a "Node like" object. -template< - typename NodeType, - typename std::enable_if< - !std::is_pointer::type>::value, int - >::type = 0 -> -rclcpp::node_interfaces::NodeTopicsInterface * -get_node_topics_interface(NodeType && node_reference) -{ - // Forward references to detail implmentation as a pointer. - return detail::get_node_topics_interface_from_pointer(&node_reference); -} - -} // namespace node_interfaces -} // namespace rclcpp - -#endif // RCLCPP__NODE_INTERFACES__GET_NODE_TOPICS_INTERFACE_HPP_ diff --git a/rclcpp/resource/get_interface.hpp.em b/rclcpp/resource/get_interface.hpp.em new file mode 100644 index 0000000000..879b405f7f --- /dev/null +++ b/rclcpp/resource/get_interface.hpp.em @@ -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. + +@{ +uppercase_interface_name = interface_name.upper() +}@ + +#ifndef RCLCPP__NODE_INTERFACES__GET_@(uppercase_interface_name)_HPP_ +#define RCLCPP__NODE_INTERFACES__GET_@(uppercase_interface_name)_HPP_ + +#include +#include +#include + +#include "rcpputils/pointer_traits.hpp" + +#include "rclcpp/node_interfaces/@(interface_name).hpp" +#include "rclcpp/node_interfaces/@(interface_name)_traits.hpp" + +@{ +interface_typename = ''.join([part.capitalize() for part in interface_name.split('_')]) +}@ + +/// This header provides the get_@(interface_name)() template function. +/** + * This function is useful for getting the @(interface_typename) pointer from + * various kinds of Node-like classes. + * + * It's able to get a std::shared_ptr to a @(interface_typename) so long as the class + * has a method called ``get_@(interface_name)()`` which returns one. + */ + +namespace rclcpp +{ +namespace node_interfaces +{ +namespace detail +{ + +// If NodeType has a method called get_@(interface_name)() which returns a shared pointer. +template< + typename NodeType, + typename std::enable_if::type + >::value, int>::type = 0 +> +std::shared_ptr +get_@(interface_name)_from_pointer(NodeType node_pointer) +{ + if (!node_pointer) { + throw std::invalid_argument("node cannot be nullptr"); + } + return node_pointer->get_@(interface_name)(); +} + +} // namespace detail + +/// Get the @(interface_typename) as a shared pointer from a pointer to a "Node like" object. +template< + typename NodeType, + typename std::enable_if< + rcpputils::is_pointer::value, int + >::type = 0 +> +inline +std::shared_ptr +get_@(interface_name)(NodeType && node) +{ + // Forward pointers to detail implementation directly. + return detail::get_@(interface_name)_from_pointer(node); +} + +/// Get the @(interface_typename) as a shared pointer from a "Node like" object. +template< + typename NodeType, + typename std::enable_if< + !rcpputils::is_pointer::value, int + >::type = 0 +> +inline +std::shared_ptr +get_@(interface_name)(NodeType && node) +{ + // Forward references to detail implementation as a pointer. + return detail::get_@(interface_name)_from_pointer(&node); +} + +/// Keep the @(interface_typename) a shared pointer. +inline +std::shared_ptr +get_@(interface_name)( + std::shared_ptr & node_interface) +{ + return node_interface; +} + +} // namespace node_interfaces +} // namespace rclcpp + +#endif // RCLCPP__NODE_INTERFACES__GET_@(uppercase_interface_name)_HPP_ diff --git a/rclcpp/resource/interface_traits.hpp.em b/rclcpp/resource/interface_traits.hpp.em new file mode 100644 index 0000000000..506d67fefd --- /dev/null +++ b/rclcpp/resource/interface_traits.hpp.em @@ -0,0 +1,47 @@ +// 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. +@{ +uppercase_interface_name = interface_name.upper() +interface_typename = ''.join([part.capitalize() for part in interface_name.split('_')]) +}@ + +#ifndef RCLCPP__NODE_INTERFACES__@(uppercase_interface_name)_TRAITS_HPP_ +#define RCLCPP__NODE_INTERFACES__@(uppercase_interface_name)_TRAITS_HPP_ + +#include +#include + +#include "rclcpp/node_interfaces/@(interface_name).hpp" + +namespace rclcpp +{ +namespace node_interfaces +{ + +template +struct has_@(interface_name) : std::false_type +{}; + +template +struct has_@(interface_name)< + T, typename std::enable_if< + std::is_same< + std::shared_ptr, + decltype(std::declval().get_@(interface_name)())>::value>::type> : std::true_type +{}; + +} // namespace node_interfaces +} // namespace rclcpp + +#endif // RCLCPP__NODE_INTERFACES__@(uppercase_interface_name)_TRAITS_HPP_ diff --git a/rclcpp/test/node_interfaces/test_get_node_interfaces.cpp b/rclcpp/test/node_interfaces/test_get_node_interfaces.cpp index 015cade1e4..d91570e3be 100644 --- a/rclcpp/test/node_interfaces/test_get_node_interfaces.cpp +++ b/rclcpp/test/node_interfaces/test_get_node_interfaces.cpp @@ -47,22 +47,38 @@ class TestGetNodeInterfaces : public ::testing::Test rclcpp::Node::SharedPtr TestGetNodeInterfaces::node = nullptr; std::shared_ptr TestGetNodeInterfaces::wrapped_node = nullptr; +TEST_F(TestGetNodeInterfaces, null_rclcpp_node_shared_ptr) { + rclcpp::Node::SharedPtr null_node; + EXPECT_THROW( + { + rclcpp::node_interfaces::get_node_topics_interface(null_node); + }, std::invalid_argument); +} + TEST_F(TestGetNodeInterfaces, rclcpp_node_shared_ptr) { auto result = rclcpp::node_interfaces::get_node_topics_interface(this->node); static_assert( std::is_same< - rclcpp::node_interfaces::NodeTopicsInterface *, + std::shared_ptr, decltype(result) - >::value, "expected rclcpp::node_interfaces::NodeTopicsInterface *"); + >::value, "expected std::shared_ptr"); +} + +TEST_F(TestGetNodeInterfaces, null_node_shared_ptr) { + std::shared_ptr null_node; + EXPECT_THROW( + { + rclcpp::node_interfaces::get_node_topics_interface(null_node); + }, std::invalid_argument); } TEST_F(TestGetNodeInterfaces, node_shared_ptr) { auto result = rclcpp::node_interfaces::get_node_topics_interface(this->wrapped_node); static_assert( std::is_same< - rclcpp::node_interfaces::NodeTopicsInterface *, + std::shared_ptr, decltype(result) - >::value, "expected rclcpp::node_interfaces::NodeTopicsInterface *"); + >::value, "expected std::shared_ptr"); } TEST_F(TestGetNodeInterfaces, rclcpp_node_reference) { @@ -70,9 +86,9 @@ TEST_F(TestGetNodeInterfaces, rclcpp_node_reference) { auto result = rclcpp::node_interfaces::get_node_topics_interface(node_reference); static_assert( std::is_same< - rclcpp::node_interfaces::NodeTopicsInterface *, + std::shared_ptr, decltype(result) - >::value, "expected rclcpp::node_interfaces::NodeTopicsInterface *"); + >::value, "expected std::shared_ptr"); } TEST_F(TestGetNodeInterfaces, node_reference) { @@ -80,9 +96,9 @@ TEST_F(TestGetNodeInterfaces, node_reference) { auto result = rclcpp::node_interfaces::get_node_topics_interface(wrapped_node_reference); static_assert( std::is_same< - rclcpp::node_interfaces::NodeTopicsInterface *, + std::shared_ptr, decltype(result) - >::value, "expected rclcpp::node_interfaces::NodeTopicsInterface *"); + >::value, "expected std::shared_ptr"); } TEST_F(TestGetNodeInterfaces, rclcpp_node_pointer) { @@ -90,9 +106,17 @@ TEST_F(TestGetNodeInterfaces, rclcpp_node_pointer) { auto result = rclcpp::node_interfaces::get_node_topics_interface(node_pointer); static_assert( std::is_same< - rclcpp::node_interfaces::NodeTopicsInterface *, + std::shared_ptr, decltype(result) - >::value, "expected rclcpp::node_interfaces::NodeTopicsInterface *"); + >::value, "expected std::shared_ptr"); +} + +TEST_F(TestGetNodeInterfaces, null_rclcpp_node_pointer) { + rclcpp::Node * null_node{nullptr}; + EXPECT_THROW( + { + rclcpp::node_interfaces::get_node_topics_interface(null_node); + }, std::invalid_argument); } TEST_F(TestGetNodeInterfaces, node_pointer) { @@ -100,9 +124,17 @@ TEST_F(TestGetNodeInterfaces, node_pointer) { auto result = rclcpp::node_interfaces::get_node_topics_interface(wrapped_node_pointer); static_assert( std::is_same< - rclcpp::node_interfaces::NodeTopicsInterface *, + std::shared_ptr, decltype(result) - >::value, "expected rclcpp::node_interfaces::NodeTopicsInterface *"); + >::value, "expected std::shared_ptr"); +} + +TEST_F(TestGetNodeInterfaces, null_node_pointer) { + NodeWrapper * null_node{nullptr}; + EXPECT_THROW( + { + rclcpp::node_interfaces::get_node_topics_interface(null_node); + }, std::invalid_argument); } TEST_F(TestGetNodeInterfaces, interface_shared_pointer) { @@ -111,7 +143,7 @@ TEST_F(TestGetNodeInterfaces, interface_shared_pointer) { auto result = rclcpp::node_interfaces::get_node_topics_interface(interface_shared_ptr); static_assert( std::is_same< - rclcpp::node_interfaces::NodeTopicsInterface *, + std::shared_ptr, decltype(result) - >::value, "expected rclcpp::node_interfaces::NodeTopicsInterface *"); + >::value, "expected std::shared_ptr"); } diff --git a/rclcpp/test/test_interface_traits.cpp b/rclcpp/test/test_interface_traits.cpp new file mode 100644 index 0000000000..56754b6c98 --- /dev/null +++ b/rclcpp/test/test_interface_traits.cpp @@ -0,0 +1,77 @@ +// 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 + +#include +#include + +#include "rclcpp/contexts/default_context.hpp" +#include "rclcpp/node_interfaces/node_base_interface_traits.hpp" +#include "rclcpp/node_interfaces/node_base.hpp" +#include "rclcpp/node.hpp" + +class MyNode +{ +public: + std::shared_ptr get_node_base_interface() const + { + rclcpp::NodeOptions options; + return std::make_shared( + "my_node_name", + "my_node_namespace", + rclcpp::contexts::default_context::get_global_default_context(), + *options.get_rcl_node_options(), + false); + } +}; + +class WrongNode +{ +public: + std::shared_ptr not_get_node_base_interface() + { + return nullptr; + } +}; + +template::value + >::type * = nullptr> +void get_node_name(const T & nodelike) +{ + ASSERT_STREQ("my_node_name", nodelike.get_node_base_interface()->get_name()); +} + +class TestInterfaceTraits : public ::testing::Test +{ +protected: + static void SetUpTestCase() + { + rclcpp::init(0, nullptr); + } + + static void TearDownTestCase() + { + rclcpp::shutdown(); + } +}; + +TEST_F(TestInterfaceTraits, has_node_base_interface) { + ASSERT_TRUE(rclcpp::node_interfaces::has_node_base_interface::value); + ASSERT_FALSE(rclcpp::node_interfaces::has_node_base_interface::value); + ASSERT_TRUE(rclcpp::node_interfaces::has_node_base_interface::value); + + get_node_name(MyNode()); +}