You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

mocking_bit_gen.h 10 kB

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