xref: /spdk/include/spdk_internal/mock.h (revision bf30e09abe1667ae2769aa367cde39c550bcac00)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2017 Intel Corporation.
3  *   All rights reserved.
4  */
5 
6 #ifndef SPDK_INTERNAL_MOCK_H
7 #define SPDK_INTERNAL_MOCK_H
8 
9 #include "spdk/queue.h"
10 #include "spdk/stdinc.h"
11 
12 #define MOCK_STRUCT_INIT(...) \
13 	{ __VA_ARGS__ }
14 
15 #define DEFINE_RETURN_MOCK(fn, ret) \
16 	DECLARE_MOCK_QUEUE(fn, ret);		\
17 	DEFINE_MOCK_QUEUE(fn, ret);		\
18 	bool ut_ ## fn ## _mocked = false;	\
19 	ret ut_ ## fn
20 
21 #define DECLARE_MOCK_QUEUE(fn, ret) \
22 	struct ut_mqe_ ## fn {						\
23 		ret				val;			\
24 		TAILQ_ENTRY(ut_mqe_ ## fn)	link;			\
25 	};								\
26 	extern TAILQ_HEAD(ut_mqh_ ## fn, ut_mqe_ ## fn) ut_mqh_ ## fn;	\
27 	ret ut_mq_dequeue_ ## fn (void);					\
28 
29 #define DEFINE_MOCK_QUEUE(fn, ret) \
30 	struct ut_mqh_ ## fn ut_mqh_ ## fn =				\
31 		TAILQ_HEAD_INITIALIZER(ut_mqh_ ## fn);			\
32 									\
33 	ret ut_mq_dequeue_ ## fn (void)					\
34 	{								\
35 		struct ut_mqe_ ## fn *mqe;				\
36 		ret val;						\
37 		mqe = TAILQ_FIRST(&ut_mqh_ ## fn);			\
38 		TAILQ_REMOVE(&ut_mqh_ ## fn, mqe, link);		\
39 		val = mqe->val;						\
40 		free(mqe);						\
41 		return val;						\
42 	}
43 /*
44  * For controlling mocked function behavior, setting
45  * and getting values from the stub, the _P macros are
46  * for mocking functions that return pointer values.
47  */
48 #define MOCK_SET(fn, val) \
49 	ut_ ## fn ## _mocked = true; \
50 	ut_ ## fn = val
51 
52 /*
53  * MOCK_ENQUEUE() can be used to specify multiple different return values for the same function.
54  * Each consecutive call to a function will return a value specified by this macro (in a FIFO
55  * fashion).  Once all such values are exhausted (or none has been specified), the value assigned by
56  * MOCK_SET() will be returned.
57  */
58 #define MOCK_ENQUEUE(fn, _val) do { \
59 		struct ut_mqe_ ## fn *mqe = calloc(1, sizeof(*mqe));	\
60 		mqe->val = _val;					\
61 		TAILQ_INSERT_TAIL(&ut_mqh_ ## fn, mqe, link);		\
62 	} while (0)
63 
64 #define MOCK_GET(fn) \
65 	!TAILQ_EMPTY(&ut_mqh_ ## fn) ? ut_mq_dequeue_ ## fn () : ut_ ## fn
66 
67 #define MOCK_CLEAR_QUEUE(fn) do { \
68 		struct ut_mqe_ ## fn *mqe;				\
69 		while ((mqe = TAILQ_FIRST(&ut_mqh_ ## fn))) {		\
70 			TAILQ_REMOVE(&ut_mqh_ ## fn, mqe, link);	\
71 			free(mqe);					\
72 		}							\
73 	} while (0)
74 
75 #define MOCK_CLEAR(fn) do { \
76 		ut_ ## fn ## _mocked = false;	\
77 		MOCK_CLEAR_QUEUE(fn);		\
78 	} while (0)
79 
80 #define MOCK_CLEAR_P(fn) do { \
81 		ut_ ## fn ## _mocked = false;	\
82 		ut_ ## fn = NULL;		\
83 		MOCK_CLEAR_QUEUE(fn);		\
84 	} while (0)
85 
86 /* for proving to *certain* static analysis tools that we didn't reset the mock function. */
87 #define MOCK_CLEARED_ASSERT(fn) \
88 	SPDK_CU_ASSERT_FATAL(ut_ ## fn ## _mocked == false)
89 
90 /* for declaring function prototypes for wrappers */
91 #define DECLARE_WRAPPER(fn, ret, args) \
92 	DECLARE_MOCK_QUEUE(fn, ret); \
93 	extern bool ut_ ## fn ## _mocked; \
94 	extern ret ut_ ## fn; \
95 	__attribute__((used)) ret __wrap_ ## fn args; ret __real_ ## fn args
96 
97 /*
98  * For defining the implementation of wrappers for syscalls.
99  * Avoid nested macro calls to prevent macro expansion of fn.
100  */
101 #define DEFINE_WRAPPER(fn, ret, dargs, pargs) \
102 	DEFINE_WRAPPER_MOCK(fn, ret); \
103 	ret __wrap_ ## fn dargs \
104 	{ \
105 		if (!ut_ ## fn ## _mocked) { \
106 			return __real_ ## fn pargs; \
107 		} else { \
108 			return ut_ ## fn; \
109 		} \
110 	}
111 
112 #define DEFINE_WRAPPER_MOCK(fn, ret) \
113 	DEFINE_MOCK_QUEUE(fn, ret);		\
114 	bool ut_ ## fn ## _mocked = false;	\
115 	ret ut_ ## fn
116 
117 /* DEFINE_STUB is for defining the implementation of stubs for SPDK funcs. */
118 #define DEFINE_STUB(fn, ret, dargs, val) \
119 	DECLARE_MOCK_QUEUE(fn, ret); \
120 	DEFINE_MOCK_QUEUE(fn, ret); \
121 	bool ut_ ## fn ## _mocked = true; \
122 	ret ut_ ## fn = val; \
123 	ret fn dargs; \
124 	ret fn dargs \
125 	{ \
126 		return MOCK_GET(fn); \
127 	}
128 
129 /* DEFINE_STUB_V macro is for stubs that don't have a return value */
130 #define DEFINE_STUB_V(fn, dargs) \
131 	void fn dargs; \
132 	void fn dargs \
133 	{ \
134 	}
135 
136 #define HANDLE_RETURN_MOCK(fn)  \
137 	if (!TAILQ_EMPTY(&ut_mqh_ ## fn)) {	\
138 		return ut_mq_dequeue_ ## fn ();	\
139 	}					\
140 	if (ut_ ## fn ## _mocked) {		\
141 		return ut_ ## fn;		\
142 	}					\
143 
144 
145 /* declare wrapper protos (alphabetically please) here */
146 DECLARE_WRAPPER(calloc, void *, (size_t nmemb, size_t size));
147 
148 DECLARE_WRAPPER(pthread_mutex_init, int,
149 		(pthread_mutex_t *mtx, const pthread_mutexattr_t *attr));
150 
151 DECLARE_WRAPPER(pthread_mutexattr_init, int,
152 		(pthread_mutexattr_t *attr));
153 
154 DECLARE_WRAPPER(recvmsg, ssize_t, (int sockfd, struct msghdr *msg, int flags));
155 
156 DECLARE_WRAPPER(sendmsg, ssize_t, (int sockfd, const struct msghdr *msg, int flags));
157 
158 DECLARE_WRAPPER(writev, ssize_t, (int fd, const struct iovec *iov, int iovcnt));
159 
160 /* unlink is done a bit differently. */
161 extern char *g_unlink_path;
162 extern void (*g_unlink_callback)(void);
163 /* If g_unlink_path is NULL, __wrap_unlink will return ENOENT.
164  * If the __wrap_unlink() parameter does not match g_unlink_path, it will return ENOENT.
165  * If g_unlink_path does match, and g_unlink_callback has been set, g_unlink_callback will
166  * be called before returning 0.
167  */
168 int __wrap_unlink(const char *path);
169 
170 #endif /* SPDK_INTERNAL_MOCK_H */
171