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