mocking_bit_gen.h 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. // Copyright 2018 The Abseil Authors.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // https://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. //
  15. // -----------------------------------------------------------------------------
  16. // mocking_bit_gen.h
  17. // -----------------------------------------------------------------------------
  18. //
  19. // This file includes an `absl::MockingBitGen` class to use as a mock within the
  20. // GoogleTest testing framework. Such a mock is useful to provide deterministic
  21. // values as return values within (otherwise random) Abseil distribution
  22. // functions. Such determinism within a mock is useful within testing frameworks
  23. // to test otherwise indeterminate APIs.
  24. //
  25. // More information about the GoogleTest testing framework is available at
  26. // https://github.com/google/googletest
  27. #ifndef ABSL_RANDOM_MOCKING_BIT_GEN_H_
  28. #define ABSL_RANDOM_MOCKING_BIT_GEN_H_
  29. #include <memory>
  30. #include <tuple>
  31. #include <type_traits>
  32. #include <utility>
  33. #include "gmock/gmock.h"
  34. #include "absl/base/config.h"
  35. #include "absl/base/internal/fast_type_id.h"
  36. #include "absl/container/flat_hash_map.h"
  37. #include "absl/meta/type_traits.h"
  38. #include "absl/random/internal/mock_helpers.h"
  39. #include "absl/random/random.h"
  40. #include "absl/utility/utility.h"
  41. namespace absl {
  42. ABSL_NAMESPACE_BEGIN
  43. class BitGenRef;
  44. namespace random_internal {
  45. template <typename>
  46. struct DistributionCaller;
  47. class MockHelpers;
  48. } // namespace random_internal
  49. // MockingBitGen
  50. //
  51. // `absl::MockingBitGen` is a mock Uniform Random Bit Generator (URBG) class
  52. // which can act in place of an `absl::BitGen` URBG within tests using the
  53. // GoogleTest testing framework.
  54. //
  55. // Usage:
  56. //
  57. // Use an `absl::MockingBitGen` along with a mock distribution object (within
  58. // mock_distributions.h) inside Googletest constructs such as ON_CALL(),
  59. // EXPECT_TRUE(), etc. to produce deterministic results conforming to the
  60. // distribution's API contract.
  61. //
  62. // Example:
  63. //
  64. // // Mock a call to an `absl::Bernoulli` distribution using Googletest
  65. // absl::MockingBitGen bitgen;
  66. //
  67. // ON_CALL(absl::MockBernoulli(), Call(bitgen, 0.5))
  68. // .WillByDefault(testing::Return(true));
  69. // EXPECT_TRUE(absl::Bernoulli(bitgen, 0.5));
  70. //
  71. // // Mock a call to an `absl::Uniform` distribution within Googletest
  72. // absl::MockingBitGen bitgen;
  73. //
  74. // ON_CALL(absl::MockUniform<int>(), Call(bitgen, testing::_, testing::_))
  75. // .WillByDefault([] (int low, int high) {
  76. // return low + (high - low) / 2;
  77. // });
  78. //
  79. // EXPECT_EQ(absl::Uniform<int>(gen, 0, 10), 5);
  80. // EXPECT_EQ(absl::Uniform<int>(gen, 30, 40), 35);
  81. //
  82. // At this time, only mock distributions supplied within the Abseil random
  83. // library are officially supported.
  84. //
  85. // EXPECT_CALL and ON_CALL need to be made within the same DLL component as
  86. // the call to absl::Uniform and related methods, otherwise mocking will fail
  87. // since the underlying implementation creates a type-specific pointer which
  88. // will be distinct across different DLL boundaries.
  89. //
  90. class MockingBitGen {
  91. public:
  92. MockingBitGen() = default;
  93. ~MockingBitGen() = default;
  94. // URBG interface
  95. using result_type = absl::BitGen::result_type;
  96. static constexpr result_type(min)() { return (absl::BitGen::min)(); }
  97. static constexpr result_type(max)() { return (absl::BitGen::max)(); }
  98. result_type operator()() { return gen_(); }
  99. private:
  100. // GetMockFnType returns the testing::MockFunction for a result and tuple.
  101. // This method only exists for type deduction and is otherwise unimplemented.
  102. template <typename ResultT, typename... Args>
  103. static auto GetMockFnType(ResultT, std::tuple<Args...>)
  104. -> ::testing::MockFunction<ResultT(Args...)>;
  105. // MockFnCaller is a helper method for use with absl::apply to
  106. // apply an ArgTupleT to a compatible MockFunction.
  107. // NOTE: MockFnCaller is essentially equivalent to the lambda:
  108. // [fn](auto... args) { return fn->Call(std::move(args)...)}
  109. // however that fails to build on some supported platforms.
  110. template <typename MockFnType, typename ValidatorT, typename ResultT,
  111. typename Tuple>
  112. struct MockFnCaller;
  113. // specialization for std::tuple.
  114. template <typename MockFnType, typename ValidatorT, typename ResultT,
  115. typename... Args>
  116. struct MockFnCaller<MockFnType, ValidatorT, ResultT, std::tuple<Args...>> {
  117. MockFnType* fn;
  118. inline ResultT operator()(Args... args) {
  119. ResultT result = fn->Call(args...);
  120. ValidatorT::Validate(result, args...);
  121. return result;
  122. }
  123. };
  124. // FunctionHolder owns a particular ::testing::MockFunction associated with
  125. // a mocked type signature, and implement the type-erased Apply call, which
  126. // applies type-erased arguments to the mock.
  127. class FunctionHolder {
  128. public:
  129. virtual ~FunctionHolder() = default;
  130. // Call is a dispatch function which converts the
  131. // generic type-erased parameters into a specific mock invocation call.
  132. virtual void Apply(/*ArgTupleT*/ void* args_tuple,
  133. /*ResultT*/ void* result) = 0;
  134. };
  135. template <typename MockFnType, typename ValidatorT, typename ResultT,
  136. typename ArgTupleT>
  137. class FunctionHolderImpl final : public FunctionHolder {
  138. public:
  139. void Apply(void* args_tuple, void* result) final {
  140. // Requires tuple_args to point to a ArgTupleT, which is a
  141. // std::tuple<Args...> used to invoke the mock function. Requires result
  142. // to point to a ResultT, which is the result of the call.
  143. *static_cast<ResultT*>(result) = absl::apply(
  144. MockFnCaller<MockFnType, ValidatorT, ResultT, ArgTupleT>{&mock_fn_},
  145. *static_cast<ArgTupleT*>(args_tuple));
  146. }
  147. MockFnType mock_fn_;
  148. };
  149. // MockingBitGen::RegisterMock
  150. //
  151. // RegisterMock<ResultT, ArgTupleT>(FastTypeIdType) is the main extension
  152. // point for extending the MockingBitGen framework. It provides a mechanism to
  153. // install a mock expectation for a function like ResultT(Args...) keyed by
  154. // type_idex onto the MockingBitGen context. The key is that the type_index
  155. // used to register must match the type index used to call the mock.
  156. //
  157. // The returned MockFunction<...> type can be used to setup additional
  158. // distribution parameters of the expectation.
  159. template <typename ResultT, typename ArgTupleT, typename SelfT,
  160. typename ValidatorT>
  161. auto RegisterMock(SelfT&, base_internal::FastTypeIdType type, ValidatorT)
  162. -> decltype(GetMockFnType(std::declval<ResultT>(),
  163. std::declval<ArgTupleT>())) & {
  164. using MockFnType = decltype(GetMockFnType(std::declval<ResultT>(),
  165. std::declval<ArgTupleT>()));
  166. using WrappedFnType = absl::conditional_t<
  167. std::is_same<SelfT, ::testing::NiceMock<MockingBitGen>>::value,
  168. ::testing::NiceMock<MockFnType>,
  169. absl::conditional_t<
  170. std::is_same<SelfT, ::testing::NaggyMock<MockingBitGen>>::value,
  171. ::testing::NaggyMock<MockFnType>,
  172. absl::conditional_t<
  173. std::is_same<SelfT,
  174. ::testing::StrictMock<MockingBitGen>>::value,
  175. ::testing::StrictMock<MockFnType>, MockFnType>>>;
  176. using ImplT =
  177. FunctionHolderImpl<WrappedFnType, ValidatorT, ResultT, ArgTupleT>;
  178. auto& mock = mocks_[type];
  179. if (!mock) {
  180. mock = absl::make_unique<ImplT>();
  181. }
  182. return static_cast<ImplT*>(mock.get())->mock_fn_;
  183. }
  184. // MockingBitGen::InvokeMock
  185. //
  186. // InvokeMock(FastTypeIdType, args, result) is the entrypoint for invoking
  187. // mocks registered on MockingBitGen.
  188. //
  189. // When no mocks are registered on the provided FastTypeIdType, returns false.
  190. // Otherwise attempts to invoke the mock function ResultT(Args...) that
  191. // was previously registered via the type_index.
  192. // Requires tuple_args to point to a ArgTupleT, which is a std::tuple<Args...>
  193. // used to invoke the mock function.
  194. // Requires result to point to a ResultT, which is the result of the call.
  195. inline bool InvokeMock(base_internal::FastTypeIdType type, void* args_tuple,
  196. void* result) {
  197. // Trigger a mock, if there exists one that matches `param`.
  198. auto it = mocks_.find(type);
  199. if (it == mocks_.end()) return false;
  200. it->second->Apply(args_tuple, result);
  201. return true;
  202. }
  203. absl::flat_hash_map<base_internal::FastTypeIdType,
  204. std::unique_ptr<FunctionHolder>>
  205. mocks_;
  206. absl::BitGen gen_;
  207. template <typename>
  208. friend struct ::absl::random_internal::DistributionCaller; // for InvokeMock
  209. friend class ::absl::BitGenRef; // for InvokeMock
  210. friend class ::absl::random_internal::MockHelpers; // for RegisterMock,
  211. // InvokeMock
  212. };
  213. ABSL_NAMESPACE_END
  214. } // namespace absl
  215. #endif // ABSL_RANDOM_MOCKING_BIT_GEN_H_