-
Notifications
You must be signed in to change notification settings - Fork 181
Add mimick tests, publisher 95% coverage #732
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
38 commits
Select commit
Hold shift + click to select a range
8311924
Add mimick test for rcl_publisher_get_subscription_count
Blast545 3450eb1
Remove const qualifiers
Blast545 64e1f49
Add missing mock suffix
Blast545 2d9d15c
Remove unused variable
Blast545 298a0c2
Fix linter issue
Blast545 e3b5e89
Target lib at rcl instead of rmw
Blast545 1633b60
Add proper library file
Blast545 807a935
Improve test description
Blast545 108b102
Add mock test for rcl_publisher_assert_liveliness
Blast545 25e7082
Add class to init publisher tests
Blast545 5e4cab5
Add test for mocked rmw_publish
Blast545 449e8f8
Add mock test for rcl_publish_serialized
Blast545 6920f50
Mock rcutils_string_map_init to make init fail
Blast545 436d5fc
Add mock test making rmw_publisher_get_actual_qos fail
Blast545 1c3ed36
Add class to ease mimick usage
Blast545 5562953
Reformat tests to use helper class
Blast545 e8094bd
Add mocked rcutils_string_map_init to make init fail
Blast545 4591a9e
Add tests mocking loaned functions
Blast545 bbd023d
Add mock fail tests for publisher_init
Blast545 145e050
Remove not working test
Blast545 5889cd4
Add publisher fini fail mock tests
Blast545 48e64eb
Add fini mocked tests, commented, failing
Blast545 5f5c305
Add nullptr tests
Blast545 80b8621
Re enable failing test
Blast545 e0fb32d
Update mocking utilities
Blast545 c7de0f1
Rename variable
Blast545 d4228e4
Reformat with macro utility
Blast545 24a0941
Reformat test names
Blast545 dafbc0f
Add comments for mocked tests
Blast545 98defc1
Add newlines to help code reading
Blast545 06caaca
Remove extra ret variable
Blast545 5ed77be
Check count_size value after test
Blast545 5df381f
Reformat to use constexpr where possible
Blast545 641da42
Add comment explain dummy operators
Blast545 ac2f6a1
Add variable making clear bad param test
Blast545 0f3c6a4
Remove NOTE, tracked by #735
Blast545 8f4c91a
Reword comment
Blast545 0e986e3
Add link to original file to help tracking changes
Blast545 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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_ | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.