TianoCore EDK2 master
Loading...
Searching...
No Matches
FunctionMockLib.h
Go to the documentation of this file.
1
8#ifndef FUNCTION_MOCK_LIB_H_
9#define FUNCTION_MOCK_LIB_H_
10
12#include <Library/SubhookLib.h>
13#include <type_traits>
14
16// The below macros are the public function mock interface that are intended
17// to be used outside this file.
18
19#define MOCK_INTERFACE_DECLARATION(MOCK) \
20 static MOCK * Instance; \
21 MOCK (); \
22 ~MOCK ();
23
24#define MOCK_INTERFACE_DEFINITION(MOCK) \
25 MOCK_STATIC_INSTANCE_DEFINITION (MOCK) \
26 MOCK_INTERFACE_CONSTRUCTOR (MOCK) \
27 MOCK_INTERFACE_DECONSTRUCTOR (MOCK)
28
29// Mock function declaration for external functions (i.e. functions to
30// mock that do not exist in the compilation unit).
31#define MOCK_FUNCTION_DECLARATION(RET_TYPE, FUNC, ARGS) \
32 MOCK_FUNCTION_TYPE_DEFINITIONS(RET_TYPE, FUNC, ARGS) \
33 MOCK_METHOD (RET_TYPE, FUNC, ARGS);
34
35// Mock function definition for external functions (i.e. functions to
36// mock that do not exist in the compilation unit).
37#define MOCK_FUNCTION_DEFINITION(MOCK, FUNC, NUM_ARGS, CALL_TYPE) \
38 FUNCTION_DEFINITION_TO_CALL_MOCK(MOCK, FUNC, FUNC, NUM_ARGS, CALL_TYPE)
39
40// Mock function declaration for internal functions (i.e. functions to
41// mock that already exist in the compilation unit).
42#define MOCK_FUNCTION_INTERNAL_DECLARATION(RET_TYPE, FUNC, ARGS) \
43 MOCK_FUNCTION_DECLARATION(RET_TYPE, FUNC, ARGS) \
44 MOCK_FUNCTION_HOOK_DECLARATIONS(FUNC)
45
46// Mock function definition for internal functions (i.e. functions to
47// mock that already exist in the compilation unit). This definition also
48// implements MOCK_FUNC() which is later hooked as FUNC().
49#define MOCK_FUNCTION_INTERNAL_DEFINITION(MOCK, FUNC, NUM_ARGS, CALL_TYPE) \
50 FUNCTION_DEFINITION_TO_CALL_MOCK(MOCK, FUNC, MOCK##_##FUNC, NUM_ARGS, CALL_TYPE) \
51 MOCK_FUNCTION_HOOK_DEFINITIONS(MOCK, FUNC)
52
54// The below macros are private and should not be used outside this file.
55
56#define MOCK_FUNCTION_HOOK_DECLARATIONS(FUNC) \
57 static subhook::Hook Hook##FUNC; \
58 struct MockContainer_##FUNC { \
59 MockContainer_##FUNC (); \
60 ~MockContainer_##FUNC (); \
61 }; \
62 MockContainer_##FUNC MockContainerInst_##FUNC;
63
64// This definition implements a constructor and destructor inside a nested
65// class to enable automatic installation of the hooks to the associated
66// MOCK_FUNC() when the mock object is instantiated in scope and automatic
67// removal when the instantiated mock object goes out of scope.
68#define MOCK_FUNCTION_HOOK_DEFINITIONS(MOCK, FUNC) \
69 subhook :: Hook MOCK :: Hook##FUNC; \
70 MOCK :: MockContainer_##FUNC :: MockContainer_##FUNC () { \
71 if (MOCK :: Instance == NULL) \
72 MOCK :: Hook##FUNC .Install( \
73 (FUNC##_ret_type *) ::FUNC, \
74 (FUNC##_ret_type *) MOCK##_##FUNC); \
75 } \
76 MOCK :: MockContainer_##FUNC :: ~MockContainer_##FUNC () { \
77 MOCK :: Hook##FUNC .Remove(); \
78 } \
79 static_assert( \
80 std::is_same<decltype(&::FUNC), decltype(&MOCK##_##FUNC)>::value, \
81 "Function signature from 'MOCK_FUNCTION_INTERNAL_DEFINITION' macro " \
82 "invocation for '" #FUNC "' does not match the function signature " \
83 "of '" #FUNC "' function it is mocking. Mismatch could be due to " \
84 "different return type, arguments, or calling convention. See " \
85 "associated 'MOCK_FUNCTION_INTERNAL_DECLARATION' macro invocation " \
86 "for more details.");
87
88#define MOCK_FUNCTION_TYPE_DEFINITIONS(RET_TYPE, FUNC, ARGS) \
89 using FUNC##_ret_type = RET_TYPE; \
90 using FUNC##_type = FUNC##_ret_type ARGS;
91
92// This function definition simply calls MOCK::Instance->FUNC() which is the
93// mocked counterpart of the original function. This allows using gmock with
94// C free functions (since by default gmock only works with object methods).
95#define FUNCTION_DEFINITION_TO_CALL_MOCK(MOCK, FUNC, FUNC_DEF_NAME, NUM_ARGS, CALL_TYPE) \
96 extern "C" { \
97 typename MOCK :: FUNC##_ret_type CALL_TYPE FUNC_DEF_NAME( \
98 GMOCK_PP_REPEAT(GMOCK_INTERNAL_PARAMETER, \
99 (MOCK :: FUNC##_type), \
100 NUM_ARGS)) \
101 { \
102 EXPECT_TRUE(MOCK :: Instance != NULL) \
103 << "Called '" #FUNC "' in '" #MOCK "' function mock object before " \
104 << "an instance of '" #MOCK "' was created in test '" \
105 << ::testing::UnitTest::GetInstance()->current_test_info()->name() \
106 << "'."; \
107 return MOCK :: Instance->FUNC( \
108 GMOCK_PP_REPEAT(GMOCK_INTERNAL_FORWARD_ARG, \
109 (MOCK :: FUNC##_type), \
110 NUM_ARGS)); \
111 } \
112 }
113
114#define MOCK_STATIC_INSTANCE_DEFINITION(MOCK) MOCK * MOCK :: Instance = NULL;
115
116#define MOCK_INTERFACE_CONSTRUCTOR(MOCK) \
117 MOCK :: MOCK () { \
118 EXPECT_TRUE(MOCK :: Instance == NULL) \
119 << "Multiple instances of '" #MOCK "' function mock object were " \
120 << "created and only one instance is allowed in test '" \
121 << ::testing::UnitTest::GetInstance()->current_test_info()->name() \
122 << "'."; \
123 MOCK :: Instance = this; \
124 }
125
126#define MOCK_INTERFACE_DECONSTRUCTOR(MOCK) \
127 MOCK :: ~ MOCK () { \
128 MOCK :: Instance = NULL; \
129 }
130
131#endif // FUNCTION_MOCK_LIB_H_