// // 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_