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