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__