Add mock tests, publisher 95% coverage (#732)
* Add mimick test for rcl_publisher_get_subscription_count * Remove const qualifiers * Add missing mock suffix * Improve test description * Add mock test for rcl_publisher_assert_liveliness * Add class to init publisher tests * Add test for mocked rmw_publish * Add mock test for rcl_publish_serialized * Mock rcutils_string_map_init to make init fail * Add mock test making rmw_publisher_get_actual_qos fail * Add class to ease mimick usage * Reformat tests to use helper class * Add mocked rcutils_string_map_init to make init fail * Add tests mocking loaned functions * Add mock fail tests for publisher_init * Add publisher fini fail mock tests * Add nullptr tests * Update mocking utilities * Reformat with macro utility * Add comments for mocked tests * Check count_size value after test * Reformat to use constexpr where possible * Add variable making clear bad param test * Add link to original file to help tracking changes Signed-off-by: Jorge Perez <jjperez@ekumenlabs.com>
This commit is contained in:
parent
e4004955ad
commit
c1bf050bff
4 changed files with 724 additions and 17 deletions
|
@ -25,6 +25,7 @@
|
|||
<test_depend>ament_cmake_pytest</test_depend>
|
||||
<test_depend>ament_lint_auto</test_depend>
|
||||
<test_depend>ament_lint_common</test_depend>
|
||||
<test_depend>mimick_vendor</test_depend>
|
||||
<test_depend>rcpputils</test_depend>
|
||||
<test_depend>rmw</test_depend>
|
||||
<test_depend>rmw_implementation_cmake</test_depend>
|
||||
|
|
|
@ -3,6 +3,8 @@ find_package(launch_testing_ament_cmake REQUIRED)
|
|||
|
||||
find_package(test_msgs REQUIRED)
|
||||
|
||||
find_package(mimick_vendor REQUIRED)
|
||||
|
||||
find_package(rcpputils REQUIRED)
|
||||
find_package(rmw_implementation_cmake REQUIRED)
|
||||
|
||||
|
@ -206,7 +208,7 @@ function(test_target_function)
|
|||
ENV ${rmw_implementation_env_var}
|
||||
APPEND_LIBRARY_DIRS ${extra_lib_dirs}
|
||||
INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/../src/rcl/
|
||||
LIBRARIES ${PROJECT_NAME}
|
||||
LIBRARIES ${PROJECT_NAME} mimick
|
||||
AMENT_DEPENDENCIES ${rmw_implementation} "osrf_testing_tools_cpp" "test_msgs"
|
||||
)
|
||||
|
||||
|
|
355
rcl/test/mocking_utils/patch.hpp
Normal file
355
rcl/test/mocking_utils/patch.hpp
Normal file
|
@ -0,0 +1,355 @@
|
|||
// 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.
|
||||
|
||||
// Original file taken from:
|
||||
// https://github.com/ros2/rcutils/blob/master/test/mocking_utils/patch.hpp
|
||||
|
||||
#ifndef MOCKING_UTILS__PATCH_HPP_
|
||||
#define MOCKING_UTILS__PATCH_HPP_
|
||||
|
||||
#define MOCKING_UTILS_SUPPORT_VA_LIST
|
||||
#if (defined(__aarch64__) || defined(__arm__) || defined(_M_ARM) || defined(__thumb__))
|
||||
// In ARM machines, va_list does not define comparison operators
|
||||
// nor the compiler allows defining them via operator overloads.
|
||||
// Thus, Mimick argument matching code will not compile.
|
||||
#undef MOCKING_UTILS_SUPPORT_VA_LIST
|
||||
#endif
|
||||
|
||||
#ifdef MOCKING_UTILS_SUPPORT_VA_LIST
|
||||
#include <cstdarg>
|
||||
#endif
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "mimick/mimick.h"
|
||||
#include "rcutils/macros.h"
|
||||
|
||||
namespace mocking_utils
|
||||
{
|
||||
|
||||
/// Mimick specific traits for each mocking_utils::Patch instance.
|
||||
/**
|
||||
* \tparam ID Numerical identifier of the patch. Ought to be unique.
|
||||
* \tparam SignatureT Type of the symbol to be patched.
|
||||
*/
|
||||
template<size_t ID, typename SignatureT>
|
||||
struct PatchTraits;
|
||||
|
||||
/// Traits specialization for ReturnT(void) free functions.
|
||||
/**
|
||||
* \tparam ID Numerical identifier of the patch. Ought to be unique.
|
||||
* \tparam ReturnT Return value type.
|
||||
*/
|
||||
template<size_t ID, typename ReturnT>
|
||||
struct PatchTraits<ID, ReturnT(void)>
|
||||
{
|
||||
mmk_mock_define(mock_type, ReturnT);
|
||||
};
|
||||
|
||||
/// Traits specialization for ReturnT(ArgT0) free functions.
|
||||
/**
|
||||
* \tparam ID Numerical identifier of the patch. Ought to be unique.
|
||||
* \tparam ReturnT Return value type.
|
||||
* \tparam ArgT0 Argument type.
|
||||
*/
|
||||
template<size_t ID, typename ReturnT, typename ArgT0>
|
||||
struct PatchTraits<ID, ReturnT(ArgT0)>
|
||||
{
|
||||
mmk_mock_define(mock_type, ReturnT, ArgT0);
|
||||
};
|
||||
|
||||
/// Traits specialization for ReturnT(ArgT0, ArgT1) free functions.
|
||||
/**
|
||||
* \tparam ID Numerical identifier of the patch. Ought to be unique.
|
||||
* \tparam ReturnT Return value type.
|
||||
* \tparam ArgTx Argument types.
|
||||
*/
|
||||
template<size_t ID, typename ReturnT,
|
||||
typename ArgT0, typename ArgT1>
|
||||
struct PatchTraits<ID, ReturnT(ArgT0, ArgT1)>
|
||||
{
|
||||
mmk_mock_define(mock_type, ReturnT, ArgT0, ArgT1);
|
||||
};
|
||||
|
||||
/// Traits specialization for ReturnT(ArgT0, ArgT1, ArgT2) free functions.
|
||||
/**
|
||||
* \tparam ID Numerical identifier of the patch. Ought to be unique.
|
||||
* \tparam ReturnT Return value type.
|
||||
* \tparam ArgTx Argument types.
|
||||
*/
|
||||
template<size_t ID, typename ReturnT,
|
||||
typename ArgT0, typename ArgT1, typename ArgT2>
|
||||
struct PatchTraits<ID, ReturnT(ArgT0, ArgT1, ArgT2)>
|
||||
{
|
||||
mmk_mock_define(mock_type, ReturnT, ArgT0, ArgT1, ArgT2);
|
||||
};
|
||||
|
||||
/// Traits specialization for ReturnT(ArgT0, ArgT1, ArgT2, ArgT3) free functions.
|
||||
/**
|
||||
* \tparam ID Numerical identifier of the patch. Ought to be unique.
|
||||
* \tparam ReturnT Return value type.
|
||||
* \tparam ArgTx Argument types.
|
||||
*/
|
||||
template<size_t ID, typename ReturnT,
|
||||
typename ArgT0, typename ArgT1,
|
||||
typename ArgT2, typename ArgT3>
|
||||
struct PatchTraits<ID, ReturnT(ArgT0, ArgT1, ArgT2, ArgT3)>
|
||||
{
|
||||
mmk_mock_define(mock_type, ReturnT, ArgT0, ArgT1, ArgT2, ArgT3);
|
||||
};
|
||||
|
||||
/// Traits specialization for ReturnT(ArgT0, ArgT1, ArgT2, ArgT3, ArgT4)
|
||||
/// free functions.
|
||||
/**
|
||||
* \tparam ID Numerical identifier of the patch. Ought to be unique.
|
||||
* \tparam ReturnT Return value type.
|
||||
* \tparam ArgTx Argument types.
|
||||
*/
|
||||
template<size_t ID, typename ReturnT,
|
||||
typename ArgT0, typename ArgT1,
|
||||
typename ArgT2, typename ArgT3, typename ArgT4>
|
||||
struct PatchTraits<ID, ReturnT(ArgT0, ArgT1, ArgT2, ArgT3, ArgT4)>
|
||||
{
|
||||
mmk_mock_define(mock_type, ReturnT, ArgT0, ArgT1, ArgT2, ArgT3, ArgT4);
|
||||
};
|
||||
|
||||
/// Traits specialization for ReturnT(ArgT0, ArgT1, ArgT2, ArgT3, ArgT4, ArgT5)
|
||||
/// free functions.
|
||||
/**
|
||||
* \tparam ID Numerical identifier of the patch. Ought to be unique.
|
||||
* \tparam ReturnT Return value type.
|
||||
* \tparam ArgTx Argument types.
|
||||
*/
|
||||
template<size_t ID, typename ReturnT,
|
||||
typename ArgT0, typename ArgT1,
|
||||
typename ArgT2, typename ArgT3,
|
||||
typename ArgT4, typename ArgT5>
|
||||
struct PatchTraits<ID, ReturnT(ArgT0, ArgT1, ArgT2, ArgT3, ArgT4, ArgT5)>
|
||||
{
|
||||
mmk_mock_define(
|
||||
mock_type, ReturnT, ArgT0, ArgT1, ArgT2, ArgT3, ArgT4, ArgT5);
|
||||
};
|
||||
|
||||
/// Generic trampoline to wrap generalized callables in plain functions.
|
||||
/**
|
||||
* \tparam ID Numerical identifier of this trampoline. Ought to be unique.
|
||||
* \tparam SignatureT Type of the symbol this trampoline replaces.
|
||||
*/
|
||||
template<size_t ID, typename SignatureT>
|
||||
struct Trampoline;
|
||||
|
||||
/// Trampoline specialization for free functions.
|
||||
template<size_t ID, typename ReturnT, typename ... ArgTs>
|
||||
struct Trampoline<ID, ReturnT(ArgTs...)>
|
||||
{
|
||||
static ReturnT base(ArgTs... args)
|
||||
{
|
||||
return target(std::forward<ArgTs>(args)...);
|
||||
}
|
||||
|
||||
static std::function<ReturnT(ArgTs...)> target;
|
||||
};
|
||||
|
||||
template<size_t ID, typename ReturnT, typename ... ArgTs>
|
||||
std::function<ReturnT(ArgTs...)>
|
||||
Trampoline<ID, ReturnT(ArgTs...)>::target;
|
||||
|
||||
/// Setup trampoline with the given @p target.
|
||||
/**
|
||||
* \param[in] target Callable that this trampoline will target.
|
||||
* \return the plain base function of this trampoline.
|
||||
*
|
||||
* \tparam ID Numerical identifier of this trampoline. Ought to be unique.
|
||||
* \tparam SignatureT Type of the symbol this trampoline replaces.
|
||||
*/
|
||||
template<size_t ID, typename SignatureT>
|
||||
auto prepare_trampoline(std::function<SignatureT> target)
|
||||
{
|
||||
Trampoline<ID, SignatureT>::target = target;
|
||||
return Trampoline<ID, SignatureT>::base;
|
||||
}
|
||||
|
||||
/// Patch class for binary API mocking
|
||||
/**
|
||||
* Built on top of Mimick, to enable symbol mocking on a per dynamically
|
||||
* linked binary object basis.
|
||||
*
|
||||
* \tparam ID Numerical identifier for this patch. Ought to be unique.
|
||||
* \tparam SignatureT Type of the symbol to be patched.
|
||||
*/
|
||||
template<size_t ID, typename SignatureT>
|
||||
class Patch;
|
||||
|
||||
/// Patch specialization for ReturnT(ArgTs...) free functions.
|
||||
/**
|
||||
* \tparam ID Numerical identifier for this patch. Ought to be unique.
|
||||
* \tparam ReturnT Return value type.
|
||||
* \tparam ArgTs Argument types.
|
||||
*/
|
||||
template<size_t ID, typename ReturnT, typename ... ArgTs>
|
||||
class Patch<ID, ReturnT(ArgTs...)>
|
||||
{
|
||||
public:
|
||||
using mock_type = typename PatchTraits<ID, ReturnT(ArgTs...)>::mock_type;
|
||||
|
||||
/// Construct a patch.
|
||||
/**
|
||||
* \param[in] target Symbol target string, using Mimick syntax
|
||||
* i.e. "symbol(@scope)?", where scope may be "self" to target the current
|
||||
* binary, "lib:library_name" to target a given library, "file:path/to/library"
|
||||
* to target a given file, or "sym:other_symbol" to target the first library
|
||||
* that defines said symbol.
|
||||
* \param[in] proxy An indirection to call the target function.
|
||||
* This indirection must ensure this call goes through the function's
|
||||
* trampoline, as setup by the dynamic linker.
|
||||
* \return a mocking_utils::Patch instance.
|
||||
*/
|
||||
explicit Patch(const std::string & target, std::function<ReturnT(ArgTs...)> proxy)
|
||||
: proxy_(proxy)
|
||||
{
|
||||
auto MMK_MANGLE(mock_type, create) =
|
||||
PatchTraits<ID, ReturnT(ArgTs...)>::MMK_MANGLE(mock_type, create);
|
||||
mock_ = mmk_mock(target.c_str(), mock_type);
|
||||
}
|
||||
|
||||
// Copy construction and assignment are disabled.
|
||||
Patch(const Patch &) = delete;
|
||||
Patch & operator=(const Patch &) = delete;
|
||||
|
||||
Patch(Patch && other)
|
||||
{
|
||||
mock_ = other.mock_;
|
||||
other.mock_ = nullptr;
|
||||
}
|
||||
|
||||
Patch & operator=(Patch && other)
|
||||
{
|
||||
if (mock_) {
|
||||
mmk_reset(mock_);
|
||||
}
|
||||
mock_ = other.mock_;
|
||||
other.mock_ = nullptr;
|
||||
}
|
||||
|
||||
~Patch()
|
||||
{
|
||||
if (mock_) {
|
||||
mmk_reset(mock_);
|
||||
}
|
||||
}
|
||||
|
||||
/// Inject a @p replacement for the patched function.
|
||||
Patch & then_call(std::function<ReturnT(ArgTs...)> replacement) &
|
||||
{
|
||||
auto type_erased_trampoline =
|
||||
reinterpret_cast<mmk_fn>(prepare_trampoline<ID>(replacement));
|
||||
mmk_when(proxy_(any<ArgTs>()...), .then_call = type_erased_trampoline);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Inject a @p replacement for the patched function.
|
||||
Patch && then_call(std::function<ReturnT(ArgTs...)> replacement) &&
|
||||
{
|
||||
auto type_erased_trampoline =
|
||||
reinterpret_cast<mmk_fn>(prepare_trampoline<ID>(replacement));
|
||||
mmk_when(proxy_(any<ArgTs>()...), .then_call = type_erased_trampoline);
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
private:
|
||||
// Helper for template parameter pack expansion using `mmk_any`
|
||||
// macro as pattern.
|
||||
template<typename T>
|
||||
T any() {return mmk_any(T);}
|
||||
|
||||
mock_type mock_;
|
||||
std::function<ReturnT(ArgTs...)> proxy_;
|
||||
};
|
||||
|
||||
/// Make a patch for a `target` function.
|
||||
/**
|
||||
* Useful for type deduction during \ref mocking_utils::Patch construction.
|
||||
*
|
||||
* \param[in] target Symbol target string, using Mimick syntax.
|
||||
* \param[in] proxy An indirection to call the target function.
|
||||
* \return a mocking_utils::Patch instance.
|
||||
*
|
||||
* \tparam ID Numerical identifier for this patch. Ought to be unique.
|
||||
* \tparam SignatureT Type of the function to be patched.
|
||||
*
|
||||
* \sa mocking_utils::Patch for further reference.
|
||||
*/
|
||||
template<size_t ID, typename SignatureT>
|
||||
auto make_patch(const std::string & target, std::function<SignatureT> proxy)
|
||||
{
|
||||
return Patch<ID, SignatureT>(target, proxy);
|
||||
}
|
||||
|
||||
/// Define a dummy operator `op` for a given `type`.
|
||||
/**
|
||||
* Useful to enable patching functions that take arguments whose types
|
||||
* do not define basic comparison operators, as required by Mimick.
|
||||
*/
|
||||
#define MOCKING_UTILS_BOOL_OPERATOR_RETURNS_FALSE(type_, op) \
|
||||
template<typename T> \
|
||||
typename std::enable_if<std::is_same<T, type_>::value, bool>::type \
|
||||
operator op(const T &, const T &) { \
|
||||
return false; \
|
||||
}
|
||||
|
||||
/// Get the exact \ref mocking_utils::Patch type for a given `id` and `function`.
|
||||
/**
|
||||
* Useful to avoid ignored attribute warnings when using the \b decltype operator.
|
||||
*/
|
||||
#define MOCKING_UTILS_PATCH_TYPE(id, function) \
|
||||
decltype(mocking_utils::make_patch<id, decltype(function)>("", nullptr))
|
||||
|
||||
/// A transparent forwarding proxy to a given `function`.
|
||||
/**
|
||||
* Useful to ensure a call to `function` goes through its trampoline.
|
||||
*/
|
||||
#define MOCKING_UTILS_PATCH_PROXY(function) \
|
||||
[] (auto && ... args)->decltype(auto) { \
|
||||
return function(std::forward<decltype(args)>(args)...); \
|
||||
}
|
||||
|
||||
/// Compute a Mimick symbol target string based on which `function` is to be patched
|
||||
/// in which `scope`.
|
||||
#define MOCKING_UTILS_PATCH_TARGET(scope, function) \
|
||||
(std::string(RCUTILS_STRINGIFY(function)) + "@" + (scope))
|
||||
|
||||
/// Patch a `function` with a used-provided `replacement` in a given `scope`.
|
||||
#define patch(scope, function, replacement) \
|
||||
make_patch<__COUNTER__, decltype(function)>( \
|
||||
MOCKING_UTILS_PATCH_TARGET(scope, function), MOCKING_UTILS_PATCH_PROXY(function) \
|
||||
).then_call(replacement)
|
||||
|
||||
/// Patch a function with a function that only returns a value
|
||||
#define patch_and_return(scope, function, return_value) \
|
||||
patch(scope, function, [&](auto && ...) {return return_value;})
|
||||
|
||||
} // namespace mocking_utils
|
||||
|
||||
#ifdef MOCKING_UTILS_SUPPORT_VA_LIST
|
||||
// Define dummy comparison operators for C standard va_list type
|
||||
MOCKING_UTILS_BOOL_OPERATOR_RETURNS_FALSE(va_list, ==)
|
||||
MOCKING_UTILS_BOOL_OPERATOR_RETURNS_FALSE(va_list, !=)
|
||||
MOCKING_UTILS_BOOL_OPERATOR_RETURNS_FALSE(va_list, <)
|
||||
MOCKING_UTILS_BOOL_OPERATOR_RETURNS_FALSE(va_list, >)
|
||||
#endif
|
||||
|
||||
#endif // MOCKING_UTILS__PATCH_HPP_
|
|
@ -21,11 +21,15 @@
|
|||
#include "test_msgs/msg/strings.h"
|
||||
#include "rosidl_runtime_c/string_functions.h"
|
||||
|
||||
#include "./failing_allocator_functions.hpp"
|
||||
#include "mimick/mimick.h"
|
||||
#include "osrf_testing_tools_cpp/scope_exit.hpp"
|
||||
#include "rcl/error_handling.h"
|
||||
#include "rmw/validate_full_topic_name.h"
|
||||
#include "rmw/validate_node_name.h"
|
||||
|
||||
#include "./failing_allocator_functions.hpp"
|
||||
#include "./publisher_impl.h"
|
||||
#include "../mocking_utils/patch.hpp"
|
||||
|
||||
#ifdef RMW_IMPLEMENTATION
|
||||
# define CLASSNAME_(NAME, SUFFIX) NAME ## __ ## SUFFIX
|
||||
|
@ -57,7 +61,7 @@ public:
|
|||
}
|
||||
this->node_ptr = new rcl_node_t;
|
||||
*this->node_ptr = rcl_get_zero_initialized_node();
|
||||
const char * name = "test_publisher_node";
|
||||
constexpr char name[] = "test_publisher_node";
|
||||
rcl_node_options_t node_options = rcl_node_get_default_options();
|
||||
ret = rcl_node_init(this->node_ptr, name, "", this->context_ptr, &node_options);
|
||||
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
|
||||
|
@ -76,6 +80,34 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class CLASSNAME (TestPublisherFixtureInit, RMW_IMPLEMENTATION)
|
||||
: public CLASSNAME(TestPublisherFixture, RMW_IMPLEMENTATION)
|
||||
{
|
||||
public:
|
||||
const rosidl_message_type_support_t * ts =
|
||||
ROSIDL_GET_MSG_TYPE_SUPPORT(test_msgs, msg, BasicTypes);
|
||||
const char * topic_name = "chatter";
|
||||
rcl_publisher_t publisher;
|
||||
rcl_publisher_options_t publisher_options;
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
CLASSNAME(TestPublisherFixture, RMW_IMPLEMENTATION) ::SetUp();
|
||||
publisher = rcl_get_zero_initialized_publisher();
|
||||
publisher_options = rcl_publisher_get_default_options();
|
||||
rcl_ret_t ret = rcl_publisher_init(
|
||||
&publisher, this->node_ptr, ts, topic_name, &publisher_options);
|
||||
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
rcl_ret_t ret = rcl_publisher_fini(&publisher, this->node_ptr);
|
||||
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
|
||||
CLASSNAME(TestPublisherFixture, RMW_IMPLEMENTATION) ::TearDown();
|
||||
}
|
||||
};
|
||||
|
||||
/* Basic nominal test of a publisher.
|
||||
*/
|
||||
TEST_F(CLASSNAME(TestPublisherFixture, RMW_IMPLEMENTATION), test_publisher_nominal) {
|
||||
|
@ -83,8 +115,8 @@ TEST_F(CLASSNAME(TestPublisherFixture, RMW_IMPLEMENTATION), test_publisher_nomin
|
|||
rcl_publisher_t publisher = rcl_get_zero_initialized_publisher();
|
||||
const rosidl_message_type_support_t * ts =
|
||||
ROSIDL_GET_MSG_TYPE_SUPPORT(test_msgs, msg, BasicTypes);
|
||||
const char * topic_name = "chatter";
|
||||
const char * expected_topic_name = "/chatter";
|
||||
constexpr char topic_name[] = "chatter";
|
||||
constexpr char expected_topic_name[] = "/chatter";
|
||||
rcl_publisher_options_t publisher_options = rcl_publisher_get_default_options();
|
||||
ret = rcl_publisher_init(&publisher, this->node_ptr, ts, topic_name, &publisher_options);
|
||||
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
|
||||
|
@ -109,7 +141,7 @@ TEST_F(CLASSNAME(TestPublisherFixture, RMW_IMPLEMENTATION), test_publisher_nomin
|
|||
rcl_publisher_t publisher = rcl_get_zero_initialized_publisher();
|
||||
const rosidl_message_type_support_t * ts =
|
||||
ROSIDL_GET_MSG_TYPE_SUPPORT(test_msgs, msg, Strings);
|
||||
const char * topic_name = "chatter";
|
||||
constexpr char topic_name[] = "chatter";
|
||||
rcl_publisher_options_t publisher_options = rcl_publisher_get_default_options();
|
||||
ret = rcl_publisher_init(&publisher, this->node_ptr, ts, topic_name, &publisher_options);
|
||||
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
|
||||
|
@ -187,7 +219,7 @@ TEST_F(CLASSNAME(TestPublisherFixture, RMW_IMPLEMENTATION), test_publisher_init_
|
|||
rcl_publisher_t publisher;
|
||||
const rosidl_message_type_support_t * ts =
|
||||
ROSIDL_GET_MSG_TYPE_SUPPORT(test_msgs, msg, BasicTypes);
|
||||
const char * topic_name = "chatter";
|
||||
constexpr char topic_name[] = "chatter";
|
||||
rcl_publisher_options_t default_publisher_options = rcl_publisher_get_default_options();
|
||||
|
||||
// Check if null publisher is valid
|
||||
|
@ -216,6 +248,11 @@ TEST_F(CLASSNAME(TestPublisherFixture, RMW_IMPLEMENTATION), test_publisher_init_
|
|||
EXPECT_EQ(RCL_RET_NODE_INVALID, ret) << rcl_get_error_string().str;
|
||||
rcl_reset_error();
|
||||
|
||||
// Pass nullptr publisher to fini
|
||||
ret = rcl_publisher_fini(nullptr, this->node_ptr);
|
||||
EXPECT_EQ(RCL_RET_PUBLISHER_INVALID, ret) << rcl_get_error_string().str;
|
||||
rcl_reset_error();
|
||||
|
||||
// Try passing null for publisher in init.
|
||||
ret = rcl_publisher_init(nullptr, this->node_ptr, ts, topic_name, &default_publisher_options);
|
||||
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret) << rcl_get_error_string().str;
|
||||
|
@ -305,7 +342,7 @@ TEST_F(CLASSNAME(TestPublisherFixture, RMW_IMPLEMENTATION), test_publisher_loan)
|
|||
rcl_publisher_t publisher = rcl_get_zero_initialized_publisher();
|
||||
const rosidl_message_type_support_t * ts =
|
||||
ROSIDL_GET_MSG_TYPE_SUPPORT(test_msgs, msg, Strings);
|
||||
const char * topic_name = "chatter";
|
||||
constexpr char topic_name[] = "chatter";
|
||||
rcl_publisher_options_t publisher_options = rcl_publisher_get_default_options();
|
||||
rcl_ret_t ret =
|
||||
rcl_publisher_init(&publisher, this->node_ptr, ts, topic_name, &publisher_options);
|
||||
|
@ -337,7 +374,7 @@ TEST_F(CLASSNAME(TestPublisherFixture, RMW_IMPLEMENTATION), test_invalid_publish
|
|||
rcl_publisher_t publisher = rcl_get_zero_initialized_publisher();
|
||||
const rosidl_message_type_support_t * ts =
|
||||
ROSIDL_GET_MSG_TYPE_SUPPORT(test_msgs, msg, Strings);
|
||||
const char * topic_name = "chatter";
|
||||
constexpr char topic_name[] = "chatter";
|
||||
rcl_publisher_options_t publisher_options = rcl_publisher_get_default_options();
|
||||
rcl_ret_t ret =
|
||||
rcl_publisher_init(&publisher, this->node_ptr, ts, topic_name, &publisher_options);
|
||||
|
@ -371,6 +408,7 @@ TEST_F(CLASSNAME(TestPublisherFixture, RMW_IMPLEMENTATION), test_invalid_publish
|
|||
rcl_publisher_impl_t * saved_impl = publisher.impl;
|
||||
rcl_context_t * saved_context = publisher.impl->context;
|
||||
rmw_publisher_t * saved_rmw_handle = publisher.impl->rmw_handle;
|
||||
rmw_publisher_allocation_t * null_allocation_is_valid_arg = nullptr;
|
||||
|
||||
// Change internal context to nullptr
|
||||
publisher.impl->context = nullptr;
|
||||
|
@ -391,14 +429,25 @@ TEST_F(CLASSNAME(TestPublisherFixture, RMW_IMPLEMENTATION), test_invalid_publish
|
|||
rcl_reset_error();
|
||||
EXPECT_EQ(RCL_RET_PUBLISHER_INVALID, rcl_publisher_assert_liveliness(&publisher));
|
||||
rcl_reset_error();
|
||||
EXPECT_EQ(RCL_RET_PUBLISHER_INVALID, rcl_publish(&publisher, &msg, nullptr));
|
||||
EXPECT_EQ(RCL_RET_PUBLISHER_INVALID, rcl_publish(&publisher, &msg, null_allocation_is_valid_arg));
|
||||
rcl_reset_error();
|
||||
EXPECT_EQ(
|
||||
RCL_RET_PUBLISHER_INVALID,
|
||||
rcl_publish_serialized_message(&publisher, &serialized_msg, nullptr));
|
||||
rcl_publish_serialized_message(&publisher, &serialized_msg, null_allocation_is_valid_arg));
|
||||
rcl_reset_error();
|
||||
publisher.impl->context = saved_context;
|
||||
|
||||
// nullptr arguments
|
||||
EXPECT_EQ(
|
||||
RCL_RET_INVALID_ARGUMENT, rcl_publish(&publisher, nullptr, null_allocation_is_valid_arg));
|
||||
rcl_reset_error();
|
||||
EXPECT_EQ(
|
||||
RCL_RET_INVALID_ARGUMENT,
|
||||
rcl_publish_serialized_message(&publisher, nullptr, null_allocation_is_valid_arg));
|
||||
rcl_reset_error();
|
||||
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, rcl_publisher_get_subscription_count(&publisher, nullptr));
|
||||
rcl_reset_error();
|
||||
|
||||
// Change internal rmw_handle to nullptr
|
||||
publisher.impl->rmw_handle = nullptr;
|
||||
EXPECT_FALSE(rcl_publisher_is_valid_except_context(&publisher));
|
||||
|
@ -422,11 +471,11 @@ TEST_F(CLASSNAME(TestPublisherFixture, RMW_IMPLEMENTATION), test_invalid_publish
|
|||
rcl_reset_error();
|
||||
EXPECT_EQ(RCL_RET_PUBLISHER_INVALID, rcl_publisher_assert_liveliness(&publisher));
|
||||
rcl_reset_error();
|
||||
EXPECT_EQ(RCL_RET_PUBLISHER_INVALID, rcl_publish(&publisher, &msg, nullptr));
|
||||
EXPECT_EQ(RCL_RET_PUBLISHER_INVALID, rcl_publish(&publisher, &msg, null_allocation_is_valid_arg));
|
||||
rcl_reset_error();
|
||||
EXPECT_EQ(
|
||||
RCL_RET_PUBLISHER_INVALID,
|
||||
rcl_publish_serialized_message(&publisher, &serialized_msg, nullptr));
|
||||
rcl_publish_serialized_message(&publisher, &serialized_msg, null_allocation_is_valid_arg));
|
||||
rcl_reset_error();
|
||||
publisher.impl->rmw_handle = saved_rmw_handle;
|
||||
|
||||
|
@ -453,11 +502,11 @@ TEST_F(CLASSNAME(TestPublisherFixture, RMW_IMPLEMENTATION), test_invalid_publish
|
|||
rcl_reset_error();
|
||||
EXPECT_EQ(RCL_RET_PUBLISHER_INVALID, rcl_publisher_assert_liveliness(&publisher));
|
||||
rcl_reset_error();
|
||||
EXPECT_EQ(RCL_RET_PUBLISHER_INVALID, rcl_publish(&publisher, &msg, nullptr));
|
||||
EXPECT_EQ(RCL_RET_PUBLISHER_INVALID, rcl_publish(&publisher, &msg, null_allocation_is_valid_arg));
|
||||
rcl_reset_error();
|
||||
EXPECT_EQ(
|
||||
RCL_RET_PUBLISHER_INVALID,
|
||||
rcl_publish_serialized_message(&publisher, &serialized_msg, nullptr));
|
||||
rcl_publish_serialized_message(&publisher, &serialized_msg, null_allocation_is_valid_arg));
|
||||
rcl_reset_error();
|
||||
publisher.impl = saved_impl;
|
||||
|
||||
|
@ -483,10 +532,310 @@ TEST_F(CLASSNAME(TestPublisherFixture, RMW_IMPLEMENTATION), test_invalid_publish
|
|||
rcl_reset_error();
|
||||
EXPECT_EQ(RCL_RET_PUBLISHER_INVALID, rcl_publisher_assert_liveliness(nullptr));
|
||||
rcl_reset_error();
|
||||
EXPECT_EQ(RCL_RET_PUBLISHER_INVALID, rcl_publish(nullptr, &msg, nullptr));
|
||||
EXPECT_EQ(RCL_RET_PUBLISHER_INVALID, rcl_publish(nullptr, &msg, null_allocation_is_valid_arg));
|
||||
rcl_reset_error();
|
||||
EXPECT_EQ(
|
||||
RCL_RET_PUBLISHER_INVALID,
|
||||
rcl_publish_serialized_message(nullptr, &serialized_msg, nullptr));
|
||||
rcl_publish_serialized_message(nullptr, &serialized_msg, null_allocation_is_valid_arg));
|
||||
rcl_reset_error();
|
||||
}
|
||||
|
||||
// Mocking rmw_publisher_count_matched_subscriptions to make
|
||||
// rcl_publisher_get_subscription_count fail
|
||||
TEST_F(
|
||||
CLASSNAME(TestPublisherFixtureInit, RMW_IMPLEMENTATION),
|
||||
test_mock_publisher_get_subscription_count)
|
||||
{
|
||||
auto mock = mocking_utils::patch_and_return(
|
||||
"lib:rcl", rmw_publisher_count_matched_subscriptions, RMW_RET_BAD_ALLOC);
|
||||
|
||||
// Now normal usage of the function rcl_publisher_get_subscription_count returning
|
||||
// unexpected RMW_RET_BAD_ALLOC
|
||||
size_t count_size = 2u;
|
||||
EXPECT_EQ(
|
||||
RCL_RET_BAD_ALLOC, rcl_publisher_get_subscription_count(&publisher, &count_size));
|
||||
EXPECT_EQ(2u, count_size);
|
||||
rcl_reset_error();
|
||||
}
|
||||
|
||||
// Mocking rmw_publisher_assert_liveliness to make
|
||||
// rcl_publisher_assert_liveliness fail
|
||||
TEST_F(CLASSNAME(TestPublisherFixtureInit, RMW_IMPLEMENTATION), test_mock_assert_liveliness) {
|
||||
auto mock = mocking_utils::patch_and_return(
|
||||
"lib:rcl", rmw_publisher_assert_liveliness, RMW_RET_ERROR);
|
||||
|
||||
// Now normal usage of the function rcl_publisher_assert_liveliness returning
|
||||
// unexpected RMW_RET_ERROR
|
||||
EXPECT_EQ(
|
||||
RCL_RET_ERROR, rcl_publisher_assert_liveliness(&publisher));
|
||||
EXPECT_TRUE(rcl_error_is_set());
|
||||
rcl_reset_error();
|
||||
}
|
||||
|
||||
// Mocking rmw_publish to make rcl_publish fail
|
||||
TEST_F(CLASSNAME(TestPublisherFixtureInit, RMW_IMPLEMENTATION), test_mock_publish) {
|
||||
auto mock = mocking_utils::patch_and_return("lib:rcl", rmw_publish, RMW_RET_ERROR);
|
||||
|
||||
// Test normal usage of the function rcl_publish returning unexpected RMW_RET_ERROR
|
||||
test_msgs__msg__BasicTypes msg;
|
||||
test_msgs__msg__BasicTypes__init(&msg);
|
||||
msg.int64_value = 42;
|
||||
rcl_ret_t ret = rcl_publish(&publisher, &msg, nullptr);
|
||||
test_msgs__msg__BasicTypes__fini(&msg);
|
||||
EXPECT_EQ(RCL_RET_ERROR, ret) << rcl_get_error_string().str;
|
||||
EXPECT_TRUE(rcl_error_is_set());
|
||||
rcl_reset_error();
|
||||
}
|
||||
|
||||
// Mocking rmw_publish_serialized_message to make rcl_publish_serialized_message fail
|
||||
TEST_F(
|
||||
CLASSNAME(TestPublisherFixtureInit, RMW_IMPLEMENTATION), test_mock_publish_serialized_message)
|
||||
{
|
||||
rcl_serialized_message_t serialized_msg = rmw_get_zero_initialized_serialized_message();
|
||||
size_t initial_size_serialized = 0u;
|
||||
rcl_allocator_t allocator = rcl_get_default_allocator();
|
||||
ASSERT_EQ(
|
||||
RCL_RET_OK, rmw_serialized_message_init(
|
||||
&serialized_msg, initial_size_serialized, &allocator)) << rcl_get_error_string().str;
|
||||
constexpr char test_string[] = "testing";
|
||||
test_msgs__msg__Strings msg;
|
||||
test_msgs__msg__Strings__init(&msg);
|
||||
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT(
|
||||
{
|
||||
test_msgs__msg__Strings__fini(&msg);
|
||||
});
|
||||
|
||||
ASSERT_TRUE(rosidl_runtime_c__String__assign(&msg.string_value, test_string));
|
||||
ASSERT_STREQ(msg.string_value.data, test_string);
|
||||
rcl_ret_t ret = rmw_serialize(&msg, ts, &serialized_msg);
|
||||
ASSERT_EQ(RMW_RET_OK, ret);
|
||||
|
||||
rmw_ret_t rmw_publish_serialized_return = RMW_RET_ERROR;
|
||||
auto mock = mocking_utils::patch_and_return(
|
||||
"lib:rcl", rmw_publish_serialized_message, rmw_publish_serialized_return);
|
||||
{
|
||||
// Test normal usage of the function rcl_publish_serialized_message
|
||||
// returning unexpected RMW_RET_ERROR
|
||||
ret = rcl_publish_serialized_message(&publisher, &serialized_msg, nullptr);
|
||||
EXPECT_EQ(RCL_RET_ERROR, ret) << rcl_get_error_string().str;
|
||||
EXPECT_TRUE(rcl_error_is_set());
|
||||
rcl_reset_error();
|
||||
}
|
||||
{
|
||||
// Repeat, but now returning BAD_ALLOC
|
||||
rmw_publish_serialized_return = RMW_RET_BAD_ALLOC;
|
||||
ret = rcl_publish_serialized_message(&publisher, &serialized_msg, nullptr);
|
||||
EXPECT_EQ(RCL_RET_BAD_ALLOC, ret) << rcl_get_error_string().str;
|
||||
EXPECT_TRUE(rcl_error_is_set());
|
||||
rcl_reset_error();
|
||||
}
|
||||
}
|
||||
|
||||
// Define dummy comparison operators for rcutils_allocator_t type for use with the Mimick Library
|
||||
MOCKING_UTILS_BOOL_OPERATOR_RETURNS_FALSE(rcutils_allocator_t, ==)
|
||||
MOCKING_UTILS_BOOL_OPERATOR_RETURNS_FALSE(rcutils_allocator_t, <)
|
||||
MOCKING_UTILS_BOOL_OPERATOR_RETURNS_FALSE(rcutils_allocator_t, >)
|
||||
MOCKING_UTILS_BOOL_OPERATOR_RETURNS_FALSE(rcutils_allocator_t, !=)
|
||||
|
||||
TEST_F(CLASSNAME(TestPublisherFixture, RMW_IMPLEMENTATION), test_mock_publisher_init) {
|
||||
rcl_publisher_t publisher = rcl_get_zero_initialized_publisher();
|
||||
const rosidl_message_type_support_t * ts =
|
||||
ROSIDL_GET_MSG_TYPE_SUPPORT(test_msgs, msg, Strings);
|
||||
constexpr char topic_name[] = "chatter";
|
||||
rcl_publisher_options_t publisher_options = rcl_publisher_get_default_options();
|
||||
rcl_ret_t ret = RCL_RET_OK;
|
||||
|
||||
auto mock = mocking_utils::patch_and_return(
|
||||
"lib:rcl", rcutils_string_map_init, RCUTILS_RET_ERROR);
|
||||
ret = rcl_publisher_init(&publisher, this->node_ptr, ts, topic_name, &publisher_options);
|
||||
EXPECT_EQ(RCL_RET_ERROR, ret) << rcl_get_error_string().str;
|
||||
rcl_reset_error();
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
CLASSNAME(TestPublisherFixture, RMW_IMPLEMENTATION), test_mock_publisher_init_fail_qos)
|
||||
{
|
||||
auto mock = mocking_utils::patch_and_return(
|
||||
"lib:rcl", rmw_publisher_get_actual_qos, RMW_RET_ERROR);
|
||||
|
||||
rcl_publisher_t publisher = rcl_get_zero_initialized_publisher();
|
||||
const rosidl_message_type_support_t * ts =
|
||||
ROSIDL_GET_MSG_TYPE_SUPPORT(test_msgs, msg, Strings);
|
||||
constexpr char topic_name[] = "chatter";
|
||||
rcl_publisher_options_t publisher_options = rcl_publisher_get_default_options();
|
||||
|
||||
rcl_ret_t ret =
|
||||
rcl_publisher_init(&publisher, this->node_ptr, ts, topic_name, &publisher_options);
|
||||
EXPECT_EQ(RCL_RET_ERROR, ret) << rcl_get_error_string().str;
|
||||
rcl_reset_error();
|
||||
}
|
||||
|
||||
// Tests for loaned msgs functions. Mocked as the rmw tier1 vendors don't support it
|
||||
TEST_F(CLASSNAME(TestPublisherFixture, RMW_IMPLEMENTATION), test_mock_loaned_functions) {
|
||||
rcl_publisher_t publisher = rcl_get_zero_initialized_publisher();
|
||||
rcl_publisher_t not_init_publisher = rcl_get_zero_initialized_publisher();
|
||||
const rosidl_message_type_support_t * ts =
|
||||
ROSIDL_GET_MSG_TYPE_SUPPORT(test_msgs, msg, BasicTypes);
|
||||
constexpr char topic_name[] = "chatter";
|
||||
constexpr char expected_topic_name[] = "/chatter";
|
||||
rcl_publisher_options_t publisher_options = rcl_publisher_get_default_options();
|
||||
|
||||
rcl_ret_t ret = rcl_publisher_init(
|
||||
&publisher, this->node_ptr, ts, topic_name, &publisher_options);
|
||||
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
|
||||
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT(
|
||||
{
|
||||
ret = rcl_publisher_fini(&publisher, this->node_ptr);
|
||||
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
|
||||
});
|
||||
|
||||
EXPECT_EQ(strcmp(rcl_publisher_get_topic_name(&publisher), expected_topic_name), 0);
|
||||
test_msgs__msg__BasicTypes msg;
|
||||
test_msgs__msg__BasicTypes__init(&msg);
|
||||
msg.int64_value = 42;
|
||||
void * msg_pointer = &msg;
|
||||
rmw_publisher_allocation_t * null_allocation_is_valid_arg = nullptr;
|
||||
|
||||
{
|
||||
// mocked, publish nominal usage
|
||||
auto mock = mocking_utils::patch_and_return("lib:rcl", rmw_publish_loaned_message, RMW_RET_OK);
|
||||
EXPECT_EQ(RCL_RET_OK, rcl_publish_loaned_message(&publisher, &msg, nullptr));
|
||||
}
|
||||
{
|
||||
// bad params publish
|
||||
EXPECT_EQ(
|
||||
RCL_RET_PUBLISHER_INVALID,
|
||||
rcl_publish_loaned_message(nullptr, &msg, null_allocation_is_valid_arg));
|
||||
EXPECT_EQ(
|
||||
RCL_RET_PUBLISHER_INVALID,
|
||||
rcl_publish_loaned_message(¬_init_publisher, &msg, null_allocation_is_valid_arg));
|
||||
EXPECT_EQ(
|
||||
RCL_RET_INVALID_ARGUMENT,
|
||||
rcl_publish_loaned_message(&publisher, nullptr, null_allocation_is_valid_arg));
|
||||
}
|
||||
{
|
||||
// mocked, failure publish
|
||||
auto mock = mocking_utils::patch_and_return(
|
||||
"lib:rcl", rmw_publish_loaned_message, RMW_RET_ERROR);
|
||||
EXPECT_EQ(RCL_RET_ERROR, rcl_publish_loaned_message(&publisher, &msg, nullptr));
|
||||
}
|
||||
{
|
||||
// mocked, borrow loaned nominal usage
|
||||
auto mock = mocking_utils::patch_and_return("lib:rcl", rmw_borrow_loaned_message, RMW_RET_OK);
|
||||
EXPECT_EQ(RCL_RET_OK, rcl_borrow_loaned_message(&publisher, ts, &msg_pointer));
|
||||
}
|
||||
{
|
||||
// bad params borrow loaned
|
||||
EXPECT_EQ(RCL_RET_PUBLISHER_INVALID, rcl_borrow_loaned_message(nullptr, ts, &msg_pointer));
|
||||
EXPECT_EQ(
|
||||
RCL_RET_PUBLISHER_INVALID, rcl_borrow_loaned_message(¬_init_publisher, ts, &msg_pointer));
|
||||
}
|
||||
{
|
||||
// mocked, nominal return loaned message
|
||||
auto mock = mocking_utils::patch_and_return(
|
||||
"lib:rcl", rmw_return_loaned_message_from_publisher, RMW_RET_OK);
|
||||
EXPECT_EQ(RCL_RET_OK, rcl_return_loaned_message_from_publisher(&publisher, &msg));
|
||||
}
|
||||
{
|
||||
// bad params return loaned message
|
||||
EXPECT_EQ(
|
||||
RCL_RET_PUBLISHER_INVALID,
|
||||
rcl_return_loaned_message_from_publisher(nullptr, &msg));
|
||||
EXPECT_EQ(
|
||||
RCL_RET_PUBLISHER_INVALID,
|
||||
rcl_return_loaned_message_from_publisher(¬_init_publisher, &msg));
|
||||
EXPECT_EQ(
|
||||
RCL_RET_INVALID_ARGUMENT,
|
||||
rcl_return_loaned_message_from_publisher(&publisher, nullptr));
|
||||
}
|
||||
|
||||
test_msgs__msg__BasicTypes__fini(&msg);
|
||||
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
|
||||
}
|
||||
|
||||
// Tests mocking ini/fini functions for specific failures
|
||||
TEST_F(CLASSNAME(TestPublisherFixture, RMW_IMPLEMENTATION), test_mocks_fail_publisher_init) {
|
||||
rcl_publisher_t publisher = rcl_get_zero_initialized_publisher();
|
||||
const rosidl_message_type_support_t * ts =
|
||||
ROSIDL_GET_MSG_TYPE_SUPPORT(test_msgs, msg, Strings);
|
||||
constexpr char topic_name[] = "chatter";
|
||||
rcl_publisher_options_t publisher_options = rcl_publisher_get_default_options();
|
||||
rcl_ret_t ret = RCL_RET_OK;
|
||||
|
||||
{
|
||||
// Internal rmw failure validating node name
|
||||
auto mock = mocking_utils::patch_and_return("lib:rcl", rmw_validate_node_name, RMW_RET_ERROR);
|
||||
ret = rcl_publisher_init(&publisher, this->node_ptr, ts, topic_name, &publisher_options);
|
||||
EXPECT_EQ(RCL_RET_ERROR, ret) << rcl_get_error_string().str;
|
||||
rcl_reset_error();
|
||||
}
|
||||
{
|
||||
// Internal rmw failure validating node name
|
||||
auto mock = mocking_utils::patch_and_return(
|
||||
"lib:rcl", rmw_validate_node_name, RMW_RET_INVALID_ARGUMENT);
|
||||
ret = rcl_publisher_init(&publisher, this->node_ptr, ts, topic_name, &publisher_options);
|
||||
EXPECT_EQ(RCL_RET_ERROR, ret) << rcl_get_error_string().str;
|
||||
rcl_reset_error();
|
||||
}
|
||||
{
|
||||
// Internal failure when fini rcutils_string_map returns error, targets substitution_map fini
|
||||
auto mock = mocking_utils::patch_and_return(
|
||||
"lib:rcl", rcutils_string_map_fini, RCUTILS_RET_ERROR);
|
||||
ret = rcl_publisher_init(&publisher, this->node_ptr, ts, topic_name, &publisher_options);
|
||||
EXPECT_EQ(RCL_RET_ERROR, ret) << rcl_get_error_string().str;
|
||||
rcl_reset_error();
|
||||
}
|
||||
{
|
||||
// Internal failure when fini rcutils_string_map returns error, targets rcl_remap_topic_name
|
||||
auto mock = mocking_utils::patch(
|
||||
"lib:rcl", rcutils_string_map_init, [](auto...) {
|
||||
static int counter = 1;
|
||||
if (counter == 1) {
|
||||
counter++;
|
||||
return RCUTILS_RET_OK;
|
||||
} else {
|
||||
// This makes rcl_remap_topic_name fail
|
||||
return RCUTILS_RET_ERROR;
|
||||
}
|
||||
});
|
||||
ret = rcl_publisher_init(&publisher, this->node_ptr, ts, topic_name, &publisher_options);
|
||||
EXPECT_EQ(RCL_RET_ERROR, ret) << rcl_get_error_string().str;
|
||||
rcl_reset_error();
|
||||
}
|
||||
{
|
||||
// Internal rmw failure validating topic name
|
||||
auto mock = mocking_utils::patch_and_return(
|
||||
"lib:rcl", rmw_validate_full_topic_name, RMW_RET_ERROR);
|
||||
ret = rcl_publisher_init(&publisher, this->node_ptr, ts, topic_name, &publisher_options);
|
||||
EXPECT_EQ(RCL_RET_ERROR, ret) << rcl_get_error_string().str;
|
||||
rcl_reset_error();
|
||||
}
|
||||
{
|
||||
// Internal rmw failure validating node name, returns OK but the result is set to error
|
||||
auto mock = mocking_utils::patch(
|
||||
"lib:rcl", rmw_validate_full_topic_name, [](auto, int * result, auto) {
|
||||
*result = RMW_TOPIC_INVALID_NOT_ABSOLUTE;
|
||||
return RMW_RET_OK;
|
||||
});
|
||||
ret = rcl_publisher_init(&publisher, this->node_ptr, ts, topic_name, &publisher_options);
|
||||
EXPECT_EQ(RCL_RET_TOPIC_NAME_INVALID, ret) << rcl_get_error_string().str;
|
||||
rcl_reset_error();
|
||||
}
|
||||
}
|
||||
|
||||
// Test mocked fail fini publisher
|
||||
TEST_F(CLASSNAME(TestPublisherFixture, RMW_IMPLEMENTATION), test_mock_publisher_fini_fail) {
|
||||
rcl_publisher_t publisher = rcl_get_zero_initialized_publisher();
|
||||
const rosidl_message_type_support_t * ts =
|
||||
ROSIDL_GET_MSG_TYPE_SUPPORT(test_msgs, msg, BasicTypes);
|
||||
constexpr char topic_name[] = "chatter";
|
||||
rcl_publisher_options_t publisher_options = rcl_publisher_get_default_options();
|
||||
rcl_ret_t ret = rcl_publisher_init(
|
||||
&publisher, this->node_ptr, ts, topic_name, &publisher_options);
|
||||
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
|
||||
|
||||
// Internal rmw failure destroying publisher
|
||||
auto mock = mocking_utils::patch_and_return("lib:rcl", rmw_destroy_publisher, RMW_RET_ERROR);
|
||||
ret = rcl_publisher_fini(&publisher, this->node_ptr);
|
||||
EXPECT_EQ(RCL_RET_ERROR, ret) << rcl_get_error_string().str;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue