This repository has been archived by the owner on Jan 18, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Resolves #502
- Loading branch information
Showing
3 changed files
with
246 additions
and
1 deletion.
There are no files selected for viewing
This file contains 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,150 @@ | ||
#pragma once | ||
|
||
#include <cstdint> | ||
#include <functional> | ||
|
||
namespace hal::mock { | ||
/** | ||
* @addtogroup mock | ||
* @{ | ||
*/ | ||
|
||
/** | ||
* @brief General class which will be used to allow for signature to be used and | ||
* then split by the below class. | ||
* | ||
* @tparam signature function signature to be split up in the callback_recorder | ||
* specialization | ||
*/ | ||
template<typename signature> | ||
class callback_recorder; | ||
|
||
/** | ||
* @brief Specialization of callback_recorder with the return type and arguments | ||
* split up. | ||
* | ||
* @tparam return_t function's return type | ||
* @tparam args_t function's set of arguments | ||
*/ | ||
template<typename return_t, typename... args_t> | ||
class callback_recorder<return_t(args_t... p_args)> | ||
{ | ||
public: | ||
using callback_function = std::function<return_t(args_t... p_args)>; | ||
|
||
/** | ||
* @brief Construct a new callback_recorder without providing a callback | ||
* | ||
* @tparam U - return type of the callback function | ||
* @tparam V - type of the callback function | ||
*/ | ||
template<typename U = return_t, | ||
typename V = std::enable_if_t<std::is_void_v<U>>*> | ||
callback_recorder() noexcept | ||
{ | ||
m_callback = [this]([[maybe_unused]] args_t... p_args) { m_call_count++; }; | ||
} | ||
|
||
/** | ||
* @brief Construct a new callback_recorder that returns a default value | ||
* | ||
* @tparam U - return type of the callback function | ||
* @tparam V - type of the callback function | ||
* @param p_default - default value to return from callback function | ||
* @param p_callback - when the static callback function is called, it will | ||
* call this callback | ||
*/ | ||
template<typename U = return_t, | ||
typename V = std::enable_if_t<!std::is_void_v<U>>*> | ||
callback_recorder(U p_default = U{}, V p_callback = 0) noexcept | ||
{ | ||
m_callback = | ||
[this, p_default, p_callback]([[maybe_unused]] args_t... p_args) -> U { | ||
m_call_count++; | ||
return p_default; | ||
}; | ||
} | ||
|
||
/** | ||
* @brief Construct a new static callable object | ||
* | ||
* @param p_callback - when the static callback function is called, it will | ||
* call this callback | ||
*/ | ||
explicit callback_recorder(callback_function p_callback) noexcept | ||
{ | ||
m_callback = [this, | ||
p_callback]([[maybe_unused]] args_t... p_args) -> return_t { | ||
m_call_count++; | ||
return p_callback(p_args...); | ||
}; | ||
} | ||
|
||
/** | ||
* @brief Get the static function's address | ||
* | ||
* @return auto* - static function's address | ||
*/ | ||
[[nodiscard]] auto& callback() noexcept | ||
{ | ||
return m_callback; | ||
} | ||
|
||
/** | ||
* @brief Returns true if the callback was ever called | ||
* | ||
* @return true - was called | ||
* @return false - has not been called | ||
*/ | ||
[[nodiscard]] bool was_called() noexcept | ||
{ | ||
return m_call_count > 0; | ||
} | ||
|
||
/** | ||
* @brief Returns true if the callback was called exactly once | ||
* | ||
* @return true - called exactly once | ||
* @return false - called more or less than once | ||
*/ | ||
[[nodiscard]] bool was_called_once() noexcept | ||
{ | ||
return m_call_count == 1; | ||
} | ||
|
||
/** | ||
* @brief Returns true if the callback was called exactly n times | ||
* | ||
* @return true - called exactly n times | ||
* @return false - called more or less than n times | ||
*/ | ||
[[nodiscard]] bool was_called_n_times(std::uint32_t p_times_called) noexcept | ||
{ | ||
return m_call_count == p_times_called; | ||
} | ||
|
||
/** | ||
* @brief Get the number of calls to the handler | ||
* | ||
* @return auto - number of calls to the callback | ||
*/ | ||
[[nodiscard]] auto call_count() noexcept | ||
{ | ||
return m_call_count; | ||
} | ||
|
||
/** | ||
* @brief Clear call count | ||
* | ||
*/ | ||
void clear_call_count() noexcept | ||
{ | ||
m_call_count = 0; | ||
} | ||
|
||
private: | ||
std::function<return_t(args_t... p_args)> m_callback; | ||
std::uint32_t m_call_count = 0; | ||
}; | ||
/** @} */ | ||
} // namespace hal::mock |
This file contains 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 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,94 @@ | ||
#include <libhal/callback_recorder.hpp> | ||
|
||
#include <boost/ut.hpp> | ||
|
||
namespace hal { | ||
boost::ut::suite callback_recorder_test = []() { | ||
using namespace boost::ut; | ||
|
||
"callback_recorder::ctor(callback_function)"_test = []() { | ||
// Setup | ||
int counter = 0; | ||
const std::function<void(void)> expected_callback = [&counter](void) { | ||
counter++; | ||
}; | ||
hal::mock::callback_recorder<void(void)> recorder(expected_callback); | ||
|
||
// Exercise + Verify | ||
auto recorded_callback = recorder.callback(); | ||
expect(that % 0 == counter); | ||
expect(that % 0 == recorder.call_count()); | ||
expect(that % false == recorder.was_called()); | ||
expect(that % false == recorder.was_called_once()); | ||
|
||
recorded_callback(); | ||
expect(that % 1 == counter); | ||
expect(that % 1 == recorder.call_count()); | ||
expect(that % true == recorder.was_called()); | ||
expect(that % true == recorder.was_called_once()); | ||
expect(that % true == recorder.was_called_n_times(1)); | ||
recorded_callback(); | ||
expect(that % false == recorder.was_called_once()); | ||
expect(that % true == recorder.was_called_n_times(2)); | ||
|
||
recorder.clear_call_count(); | ||
expect(that % 0 == recorder.call_count()); | ||
expect(that % false == recorder.was_called()); | ||
expect(that % false == recorder.was_called_once()); | ||
|
||
recorded_callback(); | ||
expect(that % 3 == counter); | ||
expect(that % 1 == recorder.call_count()); | ||
expect(that % true == recorder.was_called()); | ||
expect(that % true == recorder.was_called_once()); | ||
}; | ||
|
||
"callback_recorder::ctor(void)"_test = []() { | ||
// Setup | ||
hal::mock::callback_recorder<void(void)> recorder; | ||
|
||
// Exercise + Verify | ||
auto recorded_callback = recorder.callback(); | ||
expect(that % 0 == recorder.call_count()); | ||
expect(that % false == recorder.was_called()); | ||
expect(that % false == recorder.was_called_once()); | ||
|
||
recorded_callback(); | ||
expect(that % 1 == recorder.call_count()); | ||
expect(that % true == recorder.was_called()); | ||
expect(that % true == recorder.was_called_once()); | ||
expect(that % true == recorder.was_called_n_times(1)); | ||
recorded_callback(); | ||
expect(that % false == recorder.was_called_once()); | ||
expect(that % true == recorder.was_called_n_times(2)); | ||
|
||
recorder.clear_call_count(); | ||
expect(that % 0 == recorder.call_count()); | ||
expect(that % false == recorder.was_called()); | ||
expect(that % false == recorder.was_called_once()); | ||
}; | ||
|
||
"callback_recorder::ctor(default)"_test = []() { | ||
// Setup | ||
hal::mock::callback_recorder<int(void)> recorder(5); | ||
|
||
// Exercise + Verify | ||
auto recorded_callback = recorder.callback(); | ||
expect(that % 0 == recorder.call_count()); | ||
expect(that % false == recorder.was_called()); | ||
expect(that % false == recorder.was_called_once()); | ||
|
||
auto result = recorded_callback(); | ||
expect(that % 5 == result); | ||
expect(that % 1 == recorder.call_count()); | ||
expect(that % true == recorder.was_called()); | ||
expect(that % true == recorder.was_called_once()); | ||
expect(that % true == recorder.was_called_n_times(1)); | ||
|
||
recorder.clear_call_count(); | ||
expect(that % 0 == recorder.call_count()); | ||
expect(that % false == recorder.was_called()); | ||
expect(that % false == recorder.was_called_once()); | ||
}; | ||
}; | ||
} // namespace hal |