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 <utility> 20 21 #include "absl/base/config.h" 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 // A no-op validator meeting the ValidatorT requirements for MockHelpers. 30 // 31 // Custom validators should follow a similar structure, passing the type to 32 // MockHelpers::MockFor<KeyT>(m, CustomValidatorT()). 33 struct NoOpValidator { 34 // Default validation: do nothing. 35 template <typename ResultT, typename... Args> ValidateNoOpValidator36 static void Validate(ResultT, Args&&...) {} 37 }; 38 39 // MockHelpers works in conjunction with MockOverloadSet, MockingBitGen, and 40 // BitGenRef to enable the mocking capability for absl distribution functions. 41 // 42 // MockingBitGen registers mocks based on the typeid of a mock signature, KeyT, 43 // which is used to generate a unique id. 44 // 45 // KeyT is a signature of the form: 46 // result_type(discriminator_type, std::tuple<args...>) 47 // The mocked function signature will be composed from KeyT as: 48 // result_type(args...) 49 // 50 class MockHelpers { 51 using IdType = ::absl::base_internal::FastTypeIdType; 52 53 // Given a key signature type used to index the mock, extract the components. 54 // KeyT is expected to have the form: 55 // result_type(discriminator_type, arg_tuple_type) 56 template <typename KeyT> 57 struct KeySignature; 58 59 template <typename ResultT, typename DiscriminatorT, typename ArgTupleT> 60 struct KeySignature<ResultT(DiscriminatorT, ArgTupleT)> { 61 using result_type = ResultT; 62 using discriminator_type = DiscriminatorT; 63 using arg_tuple_type = ArgTupleT; 64 }; 65 66 // Detector for InvokeMock. 67 template <class T> 68 using invoke_mock_t = decltype(std::declval<T*>()->InvokeMock( 69 std::declval<IdType>(), std::declval<void*>(), std::declval<void*>())); 70 71 // Empty implementation of InvokeMock. 72 template <typename KeyT, typename ReturnT, typename ArgTupleT, typename URBG, 73 typename... Args> 74 static absl::optional<ReturnT> InvokeMockImpl(char, URBG*, Args&&...) { 75 return absl::nullopt; 76 } 77 78 // Non-empty implementation of InvokeMock. 79 template <typename KeyT, typename ReturnT, typename ArgTupleT, typename URBG, 80 typename = invoke_mock_t<URBG>, typename... Args> 81 static absl::optional<ReturnT> InvokeMockImpl(int, URBG* urbg, 82 Args&&... args) { 83 ArgTupleT arg_tuple(std::forward<Args>(args)...); 84 ReturnT result; 85 if (urbg->InvokeMock(::absl::base_internal::FastTypeId<KeyT>(), &arg_tuple, 86 &result)) { 87 return result; 88 } 89 return absl::nullopt; 90 } 91 92 public: 93 // InvokeMock is private; this provides access for some specialized use cases. 94 template <typename URBG> 95 static inline bool PrivateInvokeMock(URBG* urbg, IdType type, 96 void* args_tuple, void* result) { 97 return urbg->InvokeMock(type, args_tuple, result); 98 } 99 100 // Invoke a mock for the KeyT (may or may not be a signature). 101 // 102 // KeyT is used to generate a typeid-based lookup key for the mock. 103 // KeyT is a signature of the form: 104 // result_type(discriminator_type, std::tuple<args...>) 105 // The mocked function signature will be composed from KeyT as: 106 // result_type(args...) 107 // 108 // An instance of arg_tuple_type must be constructable from Args..., since 109 // the underlying mechanism requires a pointer to an argument tuple. 110 template <typename KeyT, typename URBG, typename... Args> 111 static auto MaybeInvokeMock(URBG* urbg, Args&&... args) 112 -> absl::optional<typename KeySignature<KeyT>::result_type> { 113 // Use function overloading to dispatch to the implementation since 114 // more modern patterns (e.g. require + constexpr) are not supported in all 115 // compiler configurations. 116 return InvokeMockImpl<KeyT, typename KeySignature<KeyT>::result_type, 117 typename KeySignature<KeyT>::arg_tuple_type, URBG>( 118 0, urbg, std::forward<Args>(args)...); 119 } 120 121 // Acquire a mock for the KeyT (may or may not be a signature), set up to use 122 // the ValidatorT to verify that the result is in the range of the RNG 123 // function. 124 // 125 // KeyT is used to generate a typeid-based lookup for the mock. 126 // KeyT is a signature of the form: 127 // result_type(discriminator_type, std::tuple<args...>) 128 // The mocked function signature will be composed from KeyT as: 129 // result_type(args...) 130 // ValidatorT::Validate will be called after the result of the RNG. The 131 // signature is expected to be of the form: 132 // ValidatorT::Validate(result, args...) 133 template <typename KeyT, typename ValidatorT, typename MockURBG> 134 static auto MockFor(MockURBG& m, ValidatorT) 135 -> decltype(m.template RegisterMock< 136 typename KeySignature<KeyT>::result_type, 137 typename KeySignature<KeyT>::arg_tuple_type>( 138 m, std::declval<IdType>(), ValidatorT())) { 139 return m.template RegisterMock<typename KeySignature<KeyT>::result_type, 140 typename KeySignature<KeyT>::arg_tuple_type>( 141 m, ::absl::base_internal::FastTypeId<KeyT>(), ValidatorT()); 142 } 143 144 // Acquire a mock for the KeyT (may or may not be a signature). 145 // 146 // KeyT is used to generate a typeid-based lookup for the mock. 147 // KeyT is a signature of the form: 148 // result_type(discriminator_type, std::tuple<args...>) 149 // The mocked function signature will be composed from KeyT as: 150 // result_type(args...) 151 template <typename KeyT, typename MockURBG> 152 static decltype(auto) MockFor(MockURBG& m) { 153 return MockFor<KeyT>(m, NoOpValidator()); 154 } 155 }; 156 157 } // namespace random_internal 158 ABSL_NAMESPACE_END 159 } // namespace absl 160 161 #endif // ABSL_RANDOM_INTERNAL_MOCK_HELPERS_H_ 162