mocking_bit_gen.h 9.1 KB

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