| // | |
| // 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 <optional> | |
| #include <utility> | |
| #include "absl/base/config.h" | |
| #include "absl/base/fast_type_id.h" | |
| #include "absl/random/mocking_access.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::FastTypeIdType; | |
| using RandomMockingAccess = ::absl::RandomMockingAccess; | |
| // 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; | |
| }; | |
| public: | |
| // 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) | |
| -> std::optional<typename KeySignature<KeyT>::result_type> { | |
| if constexpr (RandomMockingAccess::HasInvokeMock<URBG>::value) { | |
| typename KeySignature<KeyT>::arg_tuple_type arg_tuple( | |
| std::forward<Args>(args)...); | |
| typename KeySignature<KeyT>::result_type result; | |
| if (RandomMockingAccess::InvokeMock(urbg, FastTypeId<KeyT>(), &arg_tuple, | |
| &result)) { | |
| return result; | |
| } | |
| } | |
| return std::nullopt; | |
| } | |
| // 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::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_ |