| // |
| // Copyright 2019 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef ABSL_RANDOM_INTERNAL_MOCK_HELPERS_H_ |
| #define ABSL_RANDOM_INTERNAL_MOCK_HELPERS_H_ |
| |
| #include <utility> |
| |
| #include "absl/base/config.h" |
| #include "absl/base/internal/fast_type_id.h" |
| #include "absl/types/optional.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace random_internal { |
| |
| // A no-op validator meeting the ValidatorT requirements for MockHelpers. |
| // |
| // Custom validators should follow a similar structure, passing the type to |
| // MockHelpers::MockFor<KeyT>(m, CustomValidatorT()). |
| struct NoOpValidator { |
| // Default validation: do nothing. |
| template <typename ResultT, typename... Args> |
| static void Validate(ResultT, Args&&...) {} |
| }; |
| |
| // MockHelpers works in conjunction with MockOverloadSet, MockingBitGen, and |
| // BitGenRef to enable the mocking capability for absl distribution functions. |
| // |
| // MockingBitGen registers mocks based on the typeid of a mock signature, KeyT, |
| // which is used to generate a unique id. |
| // |
| // KeyT is a signature of the form: |
| // result_type(discriminator_type, std::tuple<args...>) |
| // The mocked function signature will be composed from KeyT as: |
| // result_type(args...) |
| // |
| class MockHelpers { |
| using IdType = ::absl::base_internal::FastTypeIdType; |
| |
| // Given a key signature type used to index the mock, extract the components. |
| // KeyT is expected to have the form: |
| // result_type(discriminator_type, arg_tuple_type) |
| template <typename KeyT> |
| struct KeySignature; |
| |
| template <typename ResultT, typename DiscriminatorT, typename ArgTupleT> |
| struct KeySignature<ResultT(DiscriminatorT, ArgTupleT)> { |
| using result_type = ResultT; |
| using discriminator_type = DiscriminatorT; |
| using arg_tuple_type = ArgTupleT; |
| }; |
| |
| // Detector for InvokeMock. |
| template <class T> |
| using invoke_mock_t = decltype(std::declval<T*>()->InvokeMock( |
| std::declval<IdType>(), std::declval<void*>(), std::declval<void*>())); |
| |
| // Empty implementation of InvokeMock. |
| template <typename KeyT, typename ReturnT, typename ArgTupleT, typename URBG, |
| typename... Args> |
| static absl::optional<ReturnT> InvokeMockImpl(char, URBG*, Args&&...) { |
| return absl::nullopt; |
| } |
| |
| // Non-empty implementation of InvokeMock. |
| template <typename KeyT, typename ReturnT, typename ArgTupleT, typename URBG, |
| typename = invoke_mock_t<URBG>, typename... Args> |
| static absl::optional<ReturnT> InvokeMockImpl(int, URBG* urbg, |
| Args&&... args) { |
| ArgTupleT arg_tuple(std::forward<Args>(args)...); |
| ReturnT result; |
| if (urbg->InvokeMock(::absl::base_internal::FastTypeId<KeyT>(), &arg_tuple, |
| &result)) { |
| return result; |
| } |
| return absl::nullopt; |
| } |
| |
| public: |
| // InvokeMock is private; this provides access for some specialized use cases. |
| template <typename URBG> |
| static inline bool PrivateInvokeMock(URBG* urbg, IdType type, |
| void* args_tuple, void* result) { |
| return urbg->InvokeMock(type, args_tuple, result); |
| } |
| |
| // Invoke a mock for the KeyT (may or may not be a signature). |
| // |
| // KeyT is used to generate a typeid-based lookup key for the mock. |
| // KeyT is a signature of the form: |
| // result_type(discriminator_type, std::tuple<args...>) |
| // The mocked function signature will be composed from KeyT as: |
| // result_type(args...) |
| // |
| // An instance of arg_tuple_type must be constructable from Args..., since |
| // the underlying mechanism requires a pointer to an argument tuple. |
| template <typename KeyT, typename URBG, typename... Args> |
| static auto MaybeInvokeMock(URBG* urbg, Args&&... args) |
| -> absl::optional<typename KeySignature<KeyT>::result_type> { |
| // Use function overloading to dispatch to the implementation since |
| // more modern patterns (e.g. require + constexpr) are not supported in all |
| // compiler configurations. |
| return InvokeMockImpl<KeyT, typename KeySignature<KeyT>::result_type, |
| typename KeySignature<KeyT>::arg_tuple_type, URBG>( |
| 0, urbg, std::forward<Args>(args)...); |
| } |
| |
| // Acquire a mock for the KeyT (may or may not be a signature), set up to use |
| // the ValidatorT to verify that the result is in the range of the RNG |
| // function. |
| // |
| // KeyT is used to generate a typeid-based lookup for the mock. |
| // KeyT is a signature of the form: |
| // result_type(discriminator_type, std::tuple<args...>) |
| // The mocked function signature will be composed from KeyT as: |
| // result_type(args...) |
| // ValidatorT::Validate will be called after the result of the RNG. The |
| // signature is expected to be of the form: |
| // ValidatorT::Validate(result, args...) |
| template <typename KeyT, typename ValidatorT, typename MockURBG> |
| static auto MockFor(MockURBG& m, ValidatorT) |
| -> decltype(m.template RegisterMock< |
| typename KeySignature<KeyT>::result_type, |
| typename KeySignature<KeyT>::arg_tuple_type>( |
| m, std::declval<IdType>(), ValidatorT())) { |
| return m.template RegisterMock<typename KeySignature<KeyT>::result_type, |
| typename KeySignature<KeyT>::arg_tuple_type>( |
| m, ::absl::base_internal::FastTypeId<KeyT>(), ValidatorT()); |
| } |
| |
| // Acquire a mock for the KeyT (may or may not be a signature). |
| // |
| // KeyT is used to generate a typeid-based lookup for the mock. |
| // KeyT is a signature of the form: |
| // result_type(discriminator_type, std::tuple<args...>) |
| // The mocked function signature will be composed from KeyT as: |
| // result_type(args...) |
| template <typename KeyT, typename MockURBG> |
| static decltype(auto) MockFor(MockURBG& m) { |
| return MockFor<KeyT>(m, NoOpValidator()); |
| } |
| }; |
| |
| } // namespace random_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_RANDOM_INTERNAL_MOCK_HELPERS_H_ |