1 // 2 // Copyright 2019 The Abseil Authors. 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // https://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 16 #ifndef ABSL_RANDOM_INTERNAL_MOCK_HELPERS_H_ 17 #define ABSL_RANDOM_INTERNAL_MOCK_HELPERS_H_ 18 19 #include <tuple> 20 #include <type_traits> 21 22 #include "absl/base/internal/fast_type_id.h" 23 #include "absl/types/optional.h" 24 25 namespace absl { 26 ABSL_NAMESPACE_BEGIN 27 namespace random_internal { 28 29 // MockHelpers works in conjunction with MockOverloadSet, MockingBitGen, and 30 // BitGenRef to enable the mocking capability for absl distribution functions. 31 // 32 // MockingBitGen registers mocks based on the typeid of a mock signature, KeyT, 33 // which is used to generate a unique id. 34 // 35 // KeyT is a signature of the form: 36 // result_type(discriminator_type, std::tuple<args...>) 37 // The mocked function signature will be composed from KeyT as: 38 // result_type(args...) 39 // 40 class MockHelpers { 41 using IdType = ::absl::base_internal::FastTypeIdType; 42 43 // Given a key signature type used to index the mock, extract the components. 44 // KeyT is expected to have the form: 45 // result_type(discriminator_type, arg_tuple_type) 46 template <typename KeyT> 47 struct KeySignature; 48 49 template <typename ResultT, typename DiscriminatorT, typename ArgTupleT> 50 struct KeySignature<ResultT(DiscriminatorT, ArgTupleT)> { 51 using result_type = ResultT; 52 using discriminator_type = DiscriminatorT; 53 using arg_tuple_type = ArgTupleT; 54 }; 55 56 // Detector for InvokeMock. 57 template <class T> 58 using invoke_mock_t = decltype(std::declval<T*>()->InvokeMock( 59 std::declval<IdType>(), std::declval<void*>(), std::declval<void*>())); 60 61 // Empty implementation of InvokeMock. 62 template <typename KeyT, typename ReturnT, typename ArgTupleT, typename URBG, 63 typename... Args> 64 static absl::optional<ReturnT> InvokeMockImpl(char, URBG*, Args&&...) { 65 return absl::nullopt; 66 } 67 68 // Non-empty implementation of InvokeMock. 69 template <typename KeyT, typename ReturnT, typename ArgTupleT, typename URBG, 70 typename = invoke_mock_t<URBG>, typename... Args> 71 static absl::optional<ReturnT> InvokeMockImpl(int, URBG* urbg, 72 Args&&... args) { 73 ArgTupleT arg_tuple(std::forward<Args>(args)...); 74 ReturnT result; 75 if (urbg->InvokeMock(::absl::base_internal::FastTypeId<KeyT>(), &arg_tuple, 76 &result)) { 77 return result; 78 } 79 return absl::nullopt; 80 } 81 82 public: 83 // Invoke a mock for the KeyT (may or may not be a signature). 84 // 85 // KeyT is used to generate a typeid-based lookup key for the mock. 86 // KeyT is a signature of the form: 87 // result_type(discriminator_type, std::tuple<args...>) 88 // The mocked function signature will be composed from KeyT as: 89 // result_type(args...) 90 // 91 // An instance of arg_tuple_type must be constructable from Args..., since 92 // the underlying mechanism requires a pointer to an argument tuple. 93 template <typename KeyT, typename URBG, typename... Args> 94 static auto MaybeInvokeMock(URBG* urbg, Args&&... args) 95 -> absl::optional<typename KeySignature<KeyT>::result_type> { 96 // Use function overloading to dispatch to the implemenation since 97 // more modern patterns (e.g. require + constexpr) are not supported in all 98 // compiler configurations. 99 return InvokeMockImpl<KeyT, typename KeySignature<KeyT>::result_type, 100 typename KeySignature<KeyT>::arg_tuple_type, URBG>( 101 0, urbg, std::forward<Args>(args)...); 102 } 103 104 // Acquire a mock for the KeyT (may or may not be a signature). 105 // 106 // KeyT is used to generate a typeid-based lookup for the mock. 107 // KeyT is a signature of the form: 108 // result_type(discriminator_type, std::tuple<args...>) 109 // The mocked function signature will be composed from KeyT as: 110 // result_type(args...) 111 template <typename KeyT, typename MockURBG> 112 static auto MockFor(MockURBG& m) -> decltype( 113 std::declval<MockURBG>() 114 .template RegisterMock<typename KeySignature<KeyT>::result_type, 115 typename KeySignature<KeyT>::arg_tuple_type>( 116 std::declval<IdType>())) { 117 return m.template RegisterMock<typename KeySignature<KeyT>::result_type, 118 typename KeySignature<KeyT>::arg_tuple_type>( 119 ::absl::base_internal::FastTypeId<KeyT>()); 120 } 121 }; 122 123 } // namespace random_internal 124 ABSL_NAMESPACE_END 125 } // namespace absl 126 127 #endif // ABSL_RANDOM_INTERNAL_MOCK_HELPERS_H_ 128