Skip to content

Commit

Permalink
Collapse mocking_utils into one.
Browse files Browse the repository at this point in the history
Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
  • Loading branch information
hidmic committed Aug 11, 2020
1 parent 5d86e4d commit 6158ea2
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 391 deletions.
55 changes: 38 additions & 17 deletions rcl/test/mocking_utils/patch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,11 +219,8 @@ class Patch<ID, ReturnT(ArgTs...)>
* \return a mocking_utils::Patch instance.
*/
explicit Patch(const std::string & target, std::function<ReturnT(ArgTs...)> proxy)
: proxy_(proxy)
: target_(target), 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.
Expand Down Expand Up @@ -255,18 +252,14 @@ class Patch<ID, ReturnT(ArgTs...)>
/// 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);
replace_with(replacement);
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);
replace_with(replacement);
return std::move(*this);
}

Expand All @@ -276,7 +269,21 @@ class Patch<ID, ReturnT(ArgTs...)>
template<typename T>
T any() {return mmk_any(T);}

mock_type mock_;
void replace_with(std::function<ReturnT(ArgTs...)> replacement)
{
if (mock_) {
throw std::logic_error("Cannot configure patch more than once");
}
auto type_erased_trampoline =
reinterpret_cast<mmk_fn>(prepare_trampoline<ID>(replacement));
auto MMK_MANGLE(mock_type, create) =
PatchTraits<ID, ReturnT(ArgTs...)>::MMK_MANGLE(mock_type, create);
mock_ = mmk_mock(target_.c_str(), mock_type);
mmk_when(proxy_(any<ArgTs>()...), .then_call = type_erased_trampoline);
}

mock_type mock_{nullptr};
std::string target_;
std::function<ReturnT(ArgTs...)> proxy_;
};

Expand Down Expand Up @@ -332,15 +339,29 @@ auto make_patch(const std::string & target, std::function<SignatureT> proxy)
#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) \
/// Prepare a mocking_utils::Patch for patching a `function` in a given `scope`
/// but defer applying any changes.
#define prepare_patch(scope, function) \
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;})
/// Patch a `function` with a used-provided `replacement` in a given `scope`.
#define patch(scope, function, replacement) \
prepare_patch(scope, function).then_call(replacement)

/// Patch a `function` to always yield a given `return_code` in a given `scope`.
#define patch_and_return(scope, function, return_code) \
patch(scope, function, [&](auto && ...) {return return_code;})

/// Patch a `function` to execute normally but always yield a given `return_code`
/// in a given `scope`.
#define inject_on_return(scope, function, return_code) \
patch( \
scope, function, ([&, base = function](auto && ... __args) { \
static_cast<void>(base(std::forward<decltype(__args)>(__args)...)); \
return return_code; \
}))

} // namespace mocking_utils

Expand Down
Loading

0 comments on commit 6158ea2

Please sign in to comment.