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 #include <utility> 22 23 #include "absl/base/internal/fast_type_id.h" 24 #include "absl/types/optional.h" 25 26 namespace absl { 27 ABSL_NAMESPACE_BEGIN 28 namespace random_internal { 29 30 // MockHelpers works in conjunction with MockOverloadSet, MockingBitGen, and 31 // BitGenRef to enable the mocking capability for absl distribution functions. 32 // 33 // MockingBitGen registers mocks based on the typeid of a mock signature, KeyT, 34 // which is used to generate a unique id. 35 // 36 // KeyT is a signature of the form: 37 // result_type(discriminator_type, std::tuple<args...>) 38 // The mocked function signature will be composed from KeyT as: 39 // result_type(args...) 40 // 41 class MockHelpers { 42 using IdType = ::absl::base_internal::FastTypeIdType; 43 44 // Given a key signature type used to index the mock, extract the components. 45 // KeyT is expected to have the form: 46 // result_type(discriminator_type, arg_tuple_type) 47 template <typename KeyT> 48 struct KeySignature; 49 50 template <typename ResultT, typename DiscriminatorT, typename ArgTupleT> 51 struct KeySignature<ResultT(DiscriminatorT, ArgTupleT)> { 52 using result_type = ResultT; 53 using discriminator_type = DiscriminatorT; 54 using arg_tuple_type = ArgTupleT; 55 }; 56 57 // Detector for InvokeMock. 58 template <class T> 59 using invoke_mock_t = decltype(std::declval<T*>()->InvokeMock( 60 std::declval<IdType>(), std::declval<void*>(), std::declval<void*>())); 61 62 // Empty implementation of InvokeMock. 63 template <typename KeyT, typename ReturnT, typename ArgTupleT, typename URBG, 64 typename... Args> 65 static absl::optional<ReturnT> InvokeMockImpl(char, URBG*, Args&&...) { 66 return absl::nullopt; 67 } 68 69 // Non-empty implementation of InvokeMock. 70 template <typename KeyT, typename ReturnT, typename ArgTupleT, typename URBG, 71 typename = invoke_mock_t<URBG>, typename... Args> 72 static absl::optional<ReturnT> InvokeMockImpl(int, URBG* urbg, 73 Args&&... args) { 74 ArgTupleT arg_tuple(std::forward<Args>(args)...); 75 ReturnT result; 76 if (urbg->InvokeMock(::absl::base_internal::FastTypeId<KeyT>(), &arg_tuple, 77 &result)) { 78 return result; 79 } 80 return absl::nullopt; 81 } 82 83 public: 84 // InvokeMock is private; this provides access for some specialized use cases. 85 template <typename URBG> 86 static inline bool PrivateInvokeMock(URBG* urbg, IdType type, 87 void* args_tuple, void* result) { 88 return urbg->InvokeMock(type, args_tuple, result); 89 } 90 91 // Invoke a mock for the KeyT (may or may not be a signature). 92 // 93 // KeyT is used to generate a typeid-based lookup key for the mock. 94 // KeyT is a signature of the form: 95 // result_type(discriminator_type, std::tuple<args...>) 96 // The mocked function signature will be composed from KeyT as: 97 // result_type(args...) 98 // 99 // An instance of arg_tuple_type must be constructable from Args..., since 100 // the underlying mechanism requires a pointer to an argument tuple. 101 template <typename KeyT, typename URBG, typename... Args> 102 static auto MaybeInvokeMock(URBG* urbg, Args&&... args) 103 -> absl::optional<typename KeySignature<KeyT>::result_type> { 104 // Use function overloading to dispatch to the implemenation since 105 // more modern patterns (e.g. require + constexpr) are not supported in all 106 // compiler configurations. 107 return InvokeMockImpl<KeyT, typename KeySignature<KeyT>::result_type, 108 typename KeySignature<KeyT>::arg_tuple_type, URBG>( 109 0, urbg, std::forward<Args>(args)...); 110 } 111 112 // Acquire a mock for the KeyT (may or may not be a signature). 113 // 114 // KeyT is used to generate a typeid-based lookup for the mock. 115 // KeyT is a signature of the form: 116 // result_type(discriminator_type, std::tuple<args...>) 117 // The mocked function signature will be composed from KeyT as: 118 // result_type(args...) 119 template <typename KeyT, typename MockURBG> 120 static auto MockFor(MockURBG& m) 121 -> decltype(m.template RegisterMock< 122 typename KeySignature<KeyT>::result_type, 123 typename KeySignature<KeyT>::arg_tuple_type>( 124 m, std::declval<IdType>())) { 125 return m.template RegisterMock<typename KeySignature<KeyT>::result_type, 126 typename KeySignature<KeyT>::arg_tuple_type>( 127 m, ::absl::base_internal::FastTypeId<KeyT>()); 128 } 129 }; 130 131 } // namespace random_internal 132 ABSL_NAMESPACE_END 133 } // namespace absl 134 135 #endif // ABSL_RANDOM_INTERNAL_MOCK_HELPERS_H_ 136