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