File indexing completed on 2024-11-24 03:41:03
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2021 Slava Aseev <nullptrnine@basealt.ru> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #ifndef __STATIC_MOCK__H__ 0009 #define __STATIC_MOCK__H__ 0010 0011 #include <cstddef> 0012 #include <cstdint> 0013 #include <functional> 0014 #include <tuple> 0015 0016 /* 0017 * Details 0018 */ 0019 0020 #define COMPTIME_HASH(x) details::fnv1a64_hash<sizeof(x) - 2>(x) 0021 0022 namespace details 0023 { 0024 template<size_t I> 0025 constexpr uint64_t fnv1a64_hash(const char *str) 0026 { 0027 return (fnv1a64_hash<I - 1>(str) ^ static_cast<uint64_t>(str[I])) * 0x100000001b3; 0028 } 0029 0030 template<> 0031 constexpr uint64_t fnv1a64_hash<size_t(-1)>(const char *) 0032 { 0033 return 0xcbf29ce484222325; 0034 } 0035 0036 template<bool Enable, size_t N, typename... ArgsT> 0037 struct ElementType_ { 0038 using type = typename std::tuple_element<N, std::tuple<ArgsT...>>::type; 0039 }; 0040 0041 template<size_t N, typename... ArgsT> 0042 struct ElementType_<false, N, ArgsT...> { 0043 using type = std::nullptr_t; 0044 }; 0045 0046 template<size_t N, typename... ArgsT> 0047 struct ElementType : details::ElementType_<(N < sizeof...(ArgsT)), N, ArgsT...> { 0048 }; 0049 0050 template<typename ReturnT, typename T, typename... ArgsT> 0051 struct FunctionTraitsImpl { 0052 using ReturnType = ReturnT; 0053 0054 template<size_t ArgNum> 0055 using ArgT = typename ElementType<ArgNum, ArgsT...>::type; 0056 0057 static constexpr size_t arity = sizeof...(ArgsT); 0058 }; 0059 0060 template<typename T> 0061 struct FunctionTraits { 0062 }; 0063 0064 template<typename ReturnT, typename T, typename... ArgsT> 0065 struct FunctionTraits<ReturnT (T::*)(ArgsT...)> : FunctionTraitsImpl<ReturnT, T, ArgsT...> { 0066 }; 0067 0068 template<typename ReturnT, typename T, typename... ArgsT> 0069 struct FunctionTraits<ReturnT (T::*)(ArgsT...) const> : FunctionTraitsImpl<ReturnT, T, ArgsT...> { 0070 }; 0071 0072 template<typename ReturnT, typename... ArgsT> 0073 struct FunctionTraits<ReturnT (*)(ArgsT...)> : FunctionTraitsImpl<ReturnT, void, ArgsT...> { 0074 }; 0075 0076 template<typename, uint64_t, typename T> 0077 static T &returnStaticStorage() 0078 { 0079 static T value; 0080 return value; 0081 } 0082 0083 template<typename MemberF, uint64_t NameHash, typename T> 0084 struct ReturnStaticStorageHelper { 0085 using TT = typename std::decay<T>::type; 0086 0087 static T get() 0088 { 0089 return returnStaticStorage<MemberF, NameHash, TT>(); 0090 } 0091 template<typename V> 0092 static void setValue(V &&v) 0093 { 0094 returnStaticStorage<MemberF, NameHash, TT>() = std::forward<V>(v); 0095 } 0096 }; 0097 0098 template<typename MemberF, uint64_t NameHash> 0099 struct ReturnStaticStorageHelper<MemberF, NameHash, void> { 0100 static void get() 0101 { 0102 } 0103 template<typename V> 0104 static void setValue(V) 0105 { 0106 } 0107 }; 0108 0109 template<typename T> 0110 struct DefaultCtorOrNullForVoid { 0111 using TT = typename std::decay<T>::type; 0112 static TT get() 0113 { 0114 return TT(); 0115 } 0116 }; 0117 0118 template<> 0119 struct DefaultCtorOrNullForVoid<void> { 0120 static std::nullptr_t get() 0121 { 0122 return nullptr; 0123 } 0124 }; 0125 0126 template<typename MemberF, uint64_t NameHash, typename... ArgsT> 0127 struct FuncImplHelper { 0128 using RetT = typename FunctionTraits<MemberF>::ReturnType; 0129 0130 static typename FunctionTraits<MemberF>::ReturnType call(ArgsT... args) 0131 { 0132 if (func()) 0133 return func()(args...); 0134 else 0135 return ReturnStaticStorageHelper<MemberF, NameHash, typename FunctionTraits<MemberF>::ReturnType>::get(); 0136 } 0137 0138 static std::function<RetT(ArgsT...)> &func() 0139 { 0140 static std::function<RetT(ArgsT...)> holder; 0141 return holder; 0142 } 0143 }; 0144 0145 template<typename MemberF, uint64_t NameHash, size_t I = 0, typename... ArgsT> 0146 struct FuncImpl : std::conditional<(I < FunctionTraits<MemberF>::arity), 0147 FuncImpl<MemberF, NameHash, I + 1, ArgsT..., typename FunctionTraits<MemberF>::template ArgT<I>>, 0148 FuncImplHelper<MemberF, NameHash, ArgsT...>>::type { 0149 }; 0150 0151 } // namespace details 0152 0153 #define MM_MEMBER_TRAITS(NAME) details::FunctionTraits<decltype(&NAME)> 0154 0155 #define MM_MEMBER_ARG_0(NAME) 0156 #define MM_MEMBER_ARG_1(NAME) typename details::FunctionTraits<NAME>::ArgT<0> _0 0157 #define MM_MEMBER_ARG_2(NAME) MM_MEMBER_ARG_1(NAME), typename details::FunctionTraits<NAME>::ArgT<1> _1 0158 #define MM_MEMBER_ARG_3(NAME) MM_MEMBER_ARG_2(NAME), typename details::FunctionTraits<NAME>::ArgT<2> _2 0159 #define MM_MEMBER_ARG_4(NAME) MM_MEMBER_ARG_3(NAME), typename details::FunctionTraits<NAME>::ArgT<3> _3 0160 #define MM_MEMBER_ARG_5(NAME) MM_MEMBER_ARG_4(NAME), typename details::FunctionTraits<NAME>::ArgT<4> _4 0161 #define MM_MEMBER_ARG_6(NAME) MM_MEMBER_ARG_5(NAME), typename details::FunctionTraits<NAME>::ArgT<5> _5 0162 #define MM_MEMBER_ARG_7(NAME) MM_MEMBER_ARG_6(NAME), typename details::FunctionTraits<NAME>::ArgT<6> _6 0163 0164 #define MM_MEMBER_ARGNAME_0(NAME) 0165 #define MM_MEMBER_ARGNAME_1(NAME) _0 0166 #define MM_MEMBER_ARGNAME_2(NAME) MM_MEMBER_ARGNAME_1(NAME), _1 0167 #define MM_MEMBER_ARGNAME_3(NAME) MM_MEMBER_ARGNAME_2(NAME), _2 0168 #define MM_MEMBER_ARGNAME_4(NAME) MM_MEMBER_ARGNAME_3(NAME), _3 0169 #define MM_MEMBER_ARGNAME_5(NAME) MM_MEMBER_ARGNAME_4(NAME), _4 0170 #define MM_MEMBER_ARGNAME_6(NAME) MM_MEMBER_ARGNAME_5(NAME), _5 0171 #define MM_MEMBER_ARGNAME_7(NAME) MM_MEMBER_ARGNAME_6(NAME), _6 0172 0173 #define MM_LINE_NAME(prefix) MM_JOIN_NAME(prefix, __LINE__) 0174 #define MM_JOIN_NAME(NAME, LINE) MM_JOIN_NAME_1(NAME, LINE) 0175 #define MM_JOIN_NAME_1(NAME, LINE) NAME##LINE 0176 0177 #define MOCK_FUNCTION_RES_RAW_TYPE(CLASS, NAME, TYPE, ARGS_COUNT, INIT_VALUE, ...) \ 0178 details::FunctionTraits<TYPE>::ReturnType CLASS::NAME(MM_MEMBER_ARG_##ARGS_COUNT(TYPE)) __VA_ARGS__ \ 0179 { \ 0180 return details::FuncImpl<TYPE, COMPTIME_HASH(#CLASS "::" #NAME)>::call(MM_MEMBER_ARGNAME_##ARGS_COUNT(TYPE)); \ 0181 } \ 0182 static int MM_LINE_NAME(_init_res_##CLASS##NAME##ARGS_COUNT) = []() { \ 0183 details::ReturnStaticStorageHelper<TYPE, COMPTIME_HASH(#CLASS "::" #NAME), details::FunctionTraits<TYPE>::ReturnType>::setValue(INIT_VALUE); \ 0184 return 0; \ 0185 }() 0186 0187 /* 0188 * Interface 0189 */ 0190 0191 /* 0192 * Defines implementation for the function with specified return value 0193 * 0194 * CLASS - the class name 0195 * NAME - the function name 0196 * ARGS_COUNT - the count of function arguments 0197 * INIT_VALUE - the new result of the function 0198 * ... - the optional const qualifier (must be empty if member function is non-const) 0199 */ 0200 #define MOCK_FUNCTION_RES(CLASS, NAME, ARGS_COUNT, INIT_VALUE, ...) \ 0201 MOCK_FUNCTION_RES_RAW_TYPE(CLASS, NAME, decltype(&CLASS::NAME), ARGS_COUNT, INIT_VALUE, __VA_ARGS__) 0202 0203 /* 0204 * Defines implementation for the function with default-constructed return value 0205 * 0206 * CLASS - the class name 0207 * NAME - the function name 0208 * ARGS_COUNT - the count of function arguments 0209 * ... - the optional const qualifier (must be empty if member function is non-const) 0210 */ 0211 #define MOCK_FUNCTION(CLASS, NAME, ARGS_COUNT, ...) \ 0212 MOCK_FUNCTION_RES(CLASS, \ 0213 NAME, \ 0214 ARGS_COUNT, \ 0215 details::DefaultCtorOrNullForVoid<details::FunctionTraits<decltype(&CLASS::NAME)>::ReturnType>::get(), \ 0216 __VA_ARGS__) 0217 0218 /* 0219 * Defines implementation for the overloaded function with specified return value 0220 * 0221 * CLASS - the class name 0222 * NAME - the function name 0223 * ARGS_COUNT - the count of function arguments 0224 * INIT_VALUE - the new result of the function 0225 * ... - the signature of the overloaded function 0226 */ 0227 #define MOCK_FUNCTION_OVERLOADED_RES(CLASS, NAME, ARGS_COUNT, INIT_VALUE, ...) \ 0228 MOCK_FUNCTION_RES_RAW_TYPE(CLASS, NAME, decltype((__VA_ARGS__) & CLASS::NAME), ARGS_COUNT, INIT_VALUE, ) 0229 0230 /* 0231 * Defines implementation for the overloaded const member function with specified return value 0232 * 0233 * CLASS - the class name 0234 * NAME - the function name 0235 * ARGS_COUNT - the count of function arguments 0236 * INIT_VALUE - the new result of the function 0237 * ... - the signature of the overloaded function 0238 */ 0239 #define MOCK_FUNCTION_OVERLOADED_RES_CONST(CLASS, NAME, ARGS_COUNT, INIT_VALUE, ...) \ 0240 MOCK_FUNCTION_RES_RAW_TYPE(CLASS, NAME, decltype((__VA_ARGS__) & CLASS::NAME), ARGS_COUNT, INIT_VALUE, const) 0241 0242 /* 0243 * Defines implementation for the overloaded function with default-constructed return value 0244 * 0245 * CLASS - the class name 0246 * NAME - the function name 0247 * ARGS_COUNT - the count of function arguments 0248 * ... - the signature of the overloaded function 0249 */ 0250 #define MOCK_FUNCTION_OVERLOADED(CLASS, NAME, ARGS_COUNT, ...) \ 0251 MOCK_FUNCTION_OVERLOADED_RES(CLASS, \ 0252 NAME, \ 0253 ARGS_COUNT, \ 0254 details::DefaultCtorOrNullForVoid<details::FunctionTraits<decltype((__VA_ARGS__) & CLASS::NAME)>::ReturnType>::get(), \ 0255 __VA_ARGS__) 0256 0257 /* 0258 * Defines implementation for the overloaded const member function with default-constructed return value 0259 * 0260 * CLASS - the class name 0261 * NAME - the function name 0262 * ARGS_COUNT - the count of function arguments 0263 * ... - the signature of the overloaded function 0264 */ 0265 #define MOCK_FUNCTION_OVERLOADED_CONST(CLASS, NAME, ARGS_COUNT, ...) \ 0266 MOCK_FUNCTION_OVERLOADED_RES_CONST(CLASS, \ 0267 NAME, \ 0268 ARGS_COUNT, \ 0269 details::DefaultCtorOrNullForVoid<details::FunctionTraits<decltype((__VA_ARGS__) & CLASS::NAME)>::ReturnType>::get(), \ 0270 __VA_ARGS__) 0271 0272 /* 0273 * Sets return value for the specified function 0274 * 0275 * FULL_NAME - the full name of the function (e.g. SomeClass::functionName) 0276 * ... - the value to be returned (or arguments to constructor) 0277 */ 0278 #define SET_FUNCTION_RESULT(FULL_NAME, ...) \ 0279 details::ReturnStaticStorageHelper<decltype(&FULL_NAME), COMPTIME_HASH(#FULL_NAME), details::FunctionTraits<decltype(&FULL_NAME)>::ReturnType>::setValue( \ 0280 __VA_ARGS__) 0281 0282 /* 0283 * Sets return value for the specified overloaded function 0284 * 0285 * FULL_NAME - the full name of the function (e.g. SomeClass::functionName) 0286 * VALUE - the value to be returned 0287 * ... - the signature of the overloaded function 0288 */ 0289 #define SET_FUNCTION_RESULT_OVERLOADED(FULL_NAME, VALUE, ...) \ 0290 details::ReturnStaticStorageHelper<decltype((__VA_ARGS__) & FULL_NAME), \ 0291 COMPTIME_HASH(#FULL_NAME), \ 0292 details::FunctionTraits<decltype((__VA_ARGS__) & FULL_NAME)>::ReturnType>::setValue(VALUE) 0293 0294 /* 0295 * Sets implementation for the specified function 0296 * 0297 * FULL_NAME - the full name of the function (e.g. SomeClass::functionName) 0298 * ... - the lambda or function for implementation 0299 */ 0300 #define SET_FUNCTION_IMPL(FULL_NAME, ...) details::FuncImpl<decltype(&FULL_NAME), COMPTIME_HASH(#FULL_NAME)>::func() = __VA_ARGS__ 0301 0302 /* 0303 * Sets implementation for the specified overloaded function 0304 * 0305 * FULL_NAME - the full name of the function (e.g. SomeClass::functionName) 0306 * FUNC_TYPE - the signature of the overloaded function (must be alias if it contains commas) 0307 * ... - the lambda or function for implementation 0308 */ 0309 #define SET_FUNCTION_IMPL_OVERLOADED(FULL_NAME, FUNC_TYPE, ...) \ 0310 details::FuncImpl<decltype((FUNC_TYPE) & FULL_NAME), COMPTIME_HASH(#FULL_NAME)>::func() = __VA_ARGS__ 0311 0312 #endif // __STATIC_MOCK__H__