1 /* 2 * virmock.h: helper for mocking C functions 3 * 4 * Copyright (C) 2014 Red Hat, Inc. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library. If not, see 18 * <http://www.gnu.org/licenses/>. 19 * 20 */ 21 22 #pragma once 23 24 #if WITH_DLFCN_H 25 # include <dlfcn.h> 26 #endif 27 28 #include "internal.h" 29 30 #define VIR_MOCK_COUNT_ARGS(...) VIR_MOCK_ARG27(__VA_ARGS__, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1) 31 #define VIR_MOCK_ARG27(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, ...) _27 32 #define VIR_MOCK_ARG_PASTE(a, b, ...) a##b(__VA_ARGS__) 33 34 #define VIR_MOCK_ARGNAME(a, b) b 35 #define VIR_MOCK_ARGTYPE(a, b) a 36 #define VIR_MOCK_ARGTYPENAME(a, b) a b 37 #define VIR_MOCK_ARGTYPENAME_UNUSED(a, b) a b G_GNUC_UNUSED 38 39 #define VIR_MOCK_GET_ARG2(z, a, b) z(a, b) 40 #define VIR_MOCK_GET_ARG3(z, a, b, c) z(a, b) 41 #define VIR_MOCK_GET_ARG4(z, a, b, c, d) z(a, b), z(c, d) 42 #define VIR_MOCK_GET_ARG5(z, a, b, c, d, e) z(a, b), z(c, d) 43 #define VIR_MOCK_GET_ARG6(z, a, b, c, d, e, f) z(a, b), z(c, d), z(e, f) 44 #define VIR_MOCK_GET_ARG7(z, a, b, c, d, e, f, g) z(a, b), z(c, d), z(e, f) 45 #define VIR_MOCK_GET_ARG8(z, a, b, c, d, e, f, g, h) z(a, b), z(c, d), z(e, f), z(g, h) 46 #define VIR_MOCK_GET_ARG9(z, a, b, c, d, e, f, g, h, i) z(a, b), z(c, d), z(e, f), z(g, h) 47 #define VIR_MOCK_GET_ARG10(z, a, b, c, d, e, f, g, h, i, j) z(a, b), z(c, d), z(e, f), z(g, h), z(i, j) 48 #define VIR_MOCK_GET_ARG11(z, a, b, c, d, e, f, g, h, i, j, k) z(a, b), z(c, d), z(e, f), z(g, h), z(i, j) 49 #define VIR_MOCK_GET_ARG12(z, a, b, c, d, e, f, g, h, i, j, k, l) z(a, b), z(c, d), z(e, f), z(g, h), z(i, j), z(k, l) 50 #define VIR_MOCK_GET_ARG13(z, a, b, c, d, e, f, g, h, i, j, k, l, m) z(a, b), z(c, d), z(e, f), z(g, h), z(i, j), z(k, l) 51 #define VIR_MOCK_GET_ARG14(z, a, b, c, d, e, f, g, h, i, j, k, l, m, n) z(a, b), z(c, d), z(e, f), z(g, h), z(i, j), z(k, l), z(m, n) 52 #define VIR_MOCK_GET_ARG15(z, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) z(a, b), z(c, d), z(e, f), z(g, h), z(i, j), z(k, l), z(m, n) 53 #define VIR_MOCK_GET_ARG16(z, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) z(a, b), z(c, d), z(e, f), z(g, h), z(i, j), z(k, l), z(m, n), z(o, p) 54 #define VIR_MOCK_GET_ARG17(z, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q) z(a, b), z(c, d), z(e, f), z(g, h), z(i, j), z(k, l), z(m, n), z(o, p) 55 #define VIR_MOCK_GET_ARG18(z, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r) z(a, b), z(c, d), z(e, f), z(g, h), z(i, j), z(k, l), z(m, n), z(o, p), z(q, r) 56 #define VIR_MOCK_GET_ARG19(z, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s) z(a, b), z(c, d), z(e, f), z(g, h), z(i, j), z(k, l), z(m, n), z(o, p), z(q, r) 57 #define VIR_MOCK_GET_ARG20(z, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t) z(a, b), z(c, d), z(e, f), z(g, h), z(i, j), z(k, l), z(m, n), z(o, p), z(q, r), z(s, t) 58 #define VIR_MOCK_GET_ARG21(z, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u) z(a, b), z(c, d), z(e, f), z(g, h), z(i, j), z(k, l), z(m, n), z(o, p), z(q, r), z(s, t) 59 #define VIR_MOCK_GET_ARG22(z, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v) z(a, b), z(c, d), z(e, f), z(g, h), z(i, j), z(k, l), z(m, n), z(o, p), z(q, r), z(s, t), z(u, v) 60 #define VIR_MOCK_GET_ARG23(z, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w) z(a, b), z(c, d), z(e, f), z(g, h), z(i, j), z(k, l), z(m, n), z(o, p), z(q, r), z(s, t), z(u, v) 61 #define VIR_MOCK_GET_ARG24(z, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x) z(a, b), z(c, d), z(e, f), z(g, h), z(i, j), z(k, l), z(m, n), z(o, p), z(q, r), z(s, t), z(u, v), z(w, x) 62 #define VIR_MOCK_GET_ARG25(z, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y) z(a, b), z(c, d), z(e, f), z(g, h), z(i, j), z(k, l), z(m, n), z(o, p), z(q, r), z(s, t), z(u, v), z(w, x) 63 #define VIR_MOCK_GET_ARG26(z, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, aa) z(a, b), z(c, d), z(e, f), z(g, h), z(i, j), z(k, l), z(m, n), z(o, p), z(q, r), z(s, t), z(u, v), z(w, x), z(y, aa) 64 #define VIR_MOCK_GET_ARG27(z, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, aa, ab) z(a, b), z(c, d), z(e, f), z(g, h), z(i, j), z(k, l), z(m, n), z(o, p), z(q, r), z(s, t), z(u, v), z(w, x), z(y, aa) 65 66 67 #define VIR_MOCK_ARGNAMES_EXPAND(a, b, ...) VIR_MOCK_ARG_PASTE(a, b, __VA_ARGS__) 68 #define VIR_MOCK_ARGNAMES(...) \ 69 VIR_MOCK_ARGNAMES_EXPAND(VIR_MOCK_GET_ARG, VIR_MOCK_COUNT_ARGS(__VA_ARGS__), VIR_MOCK_ARGNAME, __VA_ARGS__) 70 71 #define VIR_MOCK_ARGTYPES_EXPAND(a, b, ...) VIR_MOCK_ARG_PASTE(a, b, __VA_ARGS__) 72 #define VIR_MOCK_ARGTYPES(...) \ 73 VIR_MOCK_ARGTYPES_EXPAND(VIR_MOCK_GET_ARG, VIR_MOCK_COUNT_ARGS(__VA_ARGS__), VIR_MOCK_ARGTYPE, __VA_ARGS__) 74 75 #define VIR_MOCK_ARGTYPENAMES_EXPAND(a, b, ...) VIR_MOCK_ARG_PASTE(a, b, __VA_ARGS__) 76 #define VIR_MOCK_ARGTYPENAMES(...) \ 77 VIR_MOCK_ARGTYPENAMES_EXPAND(VIR_MOCK_GET_ARG, VIR_MOCK_COUNT_ARGS(__VA_ARGS__), VIR_MOCK_ARGTYPENAME, __VA_ARGS__) 78 79 #define VIR_MOCK_ARGTYPENAMES_UNUSED_EXPAND(a, b, ...) VIR_MOCK_ARG_PASTE(a, b, __VA_ARGS__) 80 #define VIR_MOCK_ARGTYPENAMES_UNUSED(...) \ 81 VIR_MOCK_ARGTYPENAMES_UNUSED_EXPAND(VIR_MOCK_GET_ARG, VIR_MOCK_COUNT_ARGS(__VA_ARGS__), VIR_MOCK_ARGTYPENAME_UNUSED, __VA_ARGS__) 82 83 84 /* 85 * The VIR_MOCK_LINK_NNN_MMM() macros are intended for use in 86 * LD_PRELOAD based wrappers. They provide a replacement for 87 * for an existing shared library symbol export. They will 88 * then lookup the same symbol name but with 'wrap_' prefixed 89 * on it, and call that. 90 * 91 * The actual test suite should provide the implementation of 92 * the wrap_XXXX symbol, using the VIR_MOCK_WRAP_NNN_MMM 93 * macros. 94 */ 95 96 97 /** 98 * VIR_MOCK_LINK_RET_ARGS: 99 * @name: the symbol name to replace 100 * @rettype: the return type 101 * @...: pairs of parameter type and parameter name 102 * 103 * Define a replacement for @name which invokes wrap_@name 104 * forwarding on all args, and passing back the return value. 105 */ 106 #define VIR_MOCK_LINK_RET_ARGS(name, rettype, ...) \ 107 rettype name(VIR_MOCK_ARGTYPENAMES(__VA_ARGS__)) \ 108 { \ 109 static rettype (*wrap_##name)(VIR_MOCK_ARGTYPES(__VA_ARGS__)); \ 110 if (wrap_##name == NULL && \ 111 !(wrap_##name = dlsym(RTLD_DEFAULT, \ 112 "wrap_" #name))) { \ 113 fprintf(stderr, "Missing symbol 'wrap_" #name "'\n"); \ 114 abort(); \ 115 } \ 116 \ 117 return wrap_##name(VIR_MOCK_ARGNAMES(__VA_ARGS__)); \ 118 } 119 120 /** 121 * VIR_MOCK_LINK_RET_VOID: 122 * @name: the symbol name to replace 123 * @rettype: the return type 124 * 125 * Define a replacement for @name which invokes wrap_@name 126 * with no arguments, and passing back the return value. 127 */ 128 #define VIR_MOCK_LINK_RET_VOID(name, rettype) \ 129 rettype name(void) \ 130 { \ 131 static rettype (*wrap_##name)(void); \ 132 if (wrap_##name == NULL && \ 133 !(wrap_##name = dlsym(RTLD_DEFAULT, \ 134 "wrap_" #name))) { \ 135 fprintf(stderr, "Missing symbol 'wrap_" #name "'\n"); \ 136 abort(); \ 137 } \ 138 \ 139 return wrap_##name(); \ 140 } 141 142 /** 143 * VIR_MOCK_LINK_VOID_ARGS: 144 * @name: the symbol name to replace 145 * @...: pairs of parameter type and parameter name 146 * 147 * Define a replacement for @name which invokes wrap_@name 148 * forwarding on all args, but with no return value. 149 */ 150 #define VIR_MOCK_LINK_VOID_ARGS(name, ...) \ 151 void name(VIR_MOCK_ARGTYPENAMES(__VA_ARGS__)) \ 152 { \ 153 static void (*wrap_##name)(VIR_MOCK_ARGTYPES(__VA_ARGS__)); \ 154 if (wrap_##name == NULL && \ 155 !(wrap_##name = dlsym(RTLD_DEFAULT, \ 156 "wrap_" #name))) { \ 157 fprintf(stderr, "Missing symbol 'wrap_" #name "'\n"); \ 158 abort(); \ 159 } \ 160 \ 161 wrap_##name(VIR_MOCK_ARGNAMES(__VA_ARGS__)); \ 162 } 163 164 165 166 /* 167 * The VIR_MOCK_STUB_NNN_MMM() macros are intended for use in 168 * LD_PRELOAD based wrappers. They provide a replacement for 169 * for an existing shared library symbol export. They will 170 * be a pure no-op, optionally returning a dummy value. 171 */ 172 173 174 /** 175 * VIR_MOCK_STUB_RET_ARGS: 176 * @name: the symbol name to replace 177 * @rettype: the return type 178 * @retval: the return value 179 * @...: pairs of parameter type and parameter name 180 * 181 * Define a replacement for @name which doesn't invoke anything, just 182 * returns @retval. 183 */ 184 #define VIR_MOCK_STUB_RET_ARGS(name, rettype, retval, ...) \ 185 rettype name(VIR_MOCK_ARGTYPENAMES_UNUSED(__VA_ARGS__)) \ 186 { \ 187 return retval; \ 188 } 189 190 /** 191 * VIR_MOCK_STUB_RET_VOID: 192 * @name: the symbol name to replace 193 * @rettype: the return type 194 * @retval: value to return 195 * 196 * Define a replacement for @name which doesn't invoke anything, just 197 * returns @retval. 198 */ 199 #define VIR_MOCK_STUB_RET_VOID(name, rettype, retval) \ 200 rettype name(void) \ 201 { \ 202 return retval; \ 203 } 204 205 /** 206 * VIR_MOCK_STUB_VOID_ARGS: 207 * @name: the symbol name to replace 208 * @...: pairs of parameter type and parameter name 209 * 210 * Define a replacement for @name which doesn't invoke or return 211 * anything. 212 */ 213 #define VIR_MOCK_STUB_VOID_ARGS(name, ...) \ 214 void name(VIR_MOCK_ARGTYPENAMES_UNUSED(__VA_ARGS__)) \ 215 { \ 216 } 217 218 219 220 /** 221 * VIR_MOCK_STUB_VOID_VOID: 222 * @name: the symbol name to replace 223 * 224 * Define a replacement for @name which doesn't invoke or return 225 * anything. 226 */ 227 #define VIR_MOCK_STUB_VOID_VOID(name) \ 228 void name(void) \ 229 { \ 230 } 231 232 233 /* 234 * The VIR_MOCK_IMPL_NNN_MMM() macros are intended for use in the 235 * individual test suites. The define a stub implementation of 236 * the wrapped method and insert the caller provided code snippet 237 * as the body of the method. 238 */ 239 240 #define VIR_MOCK_IMPL_RET_ARGS(name, rettype, ...) \ 241 rettype name(VIR_MOCK_ARGTYPENAMES(__VA_ARGS__)); \ 242 static rettype (*real_##name)(VIR_MOCK_ARGTYPES(__VA_ARGS__)); \ 243 rettype name(VIR_MOCK_ARGTYPENAMES_UNUSED(__VA_ARGS__)) 244 245 #define VIR_MOCK_IMPL_RET_VOID(name, rettype) \ 246 rettype name(void); \ 247 static rettype (*real_##name)(void); \ 248 rettype name(void) 249 250 #define VIR_MOCK_IMPL_VOID_ARGS(name, ...) \ 251 void name(VIR_MOCK_ARGTYPENAMES(__VA_ARGS__)); \ 252 static void (*real_##name)(VIR_MOCK_ARGTYPES(__VA_ARGS__)); \ 253 void name(VIR_MOCK_ARGTYPENAMES_UNUSED(__VA_ARGS__)) 254 255 #define VIR_MOCK_IMPL_VOID_VOID(name) \ 256 void name(void); \ 257 static void (*real_##name)(void); \ 258 void name(void) 259 260 /* 261 * The VIR_MOCK_WRAP_NNN_MMM() macros are intended for use in the 262 * individual test suites. The define a stub implementation of 263 * the wrapped method and insert the caller provided code snippet 264 * as the body of the method. 265 */ 266 267 #define VIR_MOCK_WRAP_RET_ARGS(name, rettype, ...) \ 268 rettype wrap_##name(VIR_MOCK_ARGTYPENAMES(__VA_ARGS__)); \ 269 static rettype (*real_##name)(VIR_MOCK_ARGTYPES(__VA_ARGS__)); \ 270 rettype wrap_##name(VIR_MOCK_ARGTYPENAMES_UNUSED(__VA_ARGS__)) 271 272 #define VIR_MOCK_WRAP_RET_VOID(name, rettype) \ 273 rettype wrap_##name(void); \ 274 static rettype (*real_##name)(void); \ 275 rettype wrap_##name(void) 276 277 #define VIR_MOCK_WRAP_VOID_ARGS(name, ...) \ 278 void wrap_##name(VIR_MOCK_ARGTYPENAMES(__VA_ARGS__)); \ 279 static void (*real_##name)(VIR_MOCK_ARGTYPES(__VA_ARGS__)); \ 280 void wrap_##name(VIR_MOCK_ARGTYPENAMES_UNUSED(__VA_ARGS__)) 281 282 #define VIR_MOCK_WRAP_VOID_VOID(name) \ 283 void wrap_##name(void); \ 284 static void (*real_##name)(void); \ 285 void wrap_##name(void) 286 287 #if defined(VIR_MOCK_LOOKUP_MAIN) && defined(__APPLE__) 288 # define VIR_MOCK_REAL_INIT_MAIN(name, alias) \ 289 do { \ 290 if (real_##name == NULL) { \ 291 real_##name = dlsym(RTLD_MAIN_ONLY, alias); \ 292 } \ 293 } while (0) 294 #else 295 # define VIR_MOCK_REAL_INIT_MAIN(name, alias) \ 296 do {} while (0) 297 #endif 298 299 #define VIR_MOCK_REAL_INIT(name) \ 300 do { \ 301 VIR_MOCK_REAL_INIT_MAIN(name, #name); \ 302 if (real_##name == NULL && \ 303 !(real_##name = dlsym(RTLD_NEXT, \ 304 #name))) { \ 305 fprintf(stderr, "Missing symbol '" #name "'\n"); \ 306 abort(); \ 307 } \ 308 } while (0) 309 310 #define VIR_MOCK_REAL_INIT_ALIASED(name, alias) \ 311 do { \ 312 VIR_MOCK_REAL_INIT_MAIN(name, alias); \ 313 if (real_##name == NULL && \ 314 !(real_##name = dlsym(RTLD_NEXT, \ 315 alias))) { \ 316 fprintf(stderr, "Missing symbol '" alias "'\n"); \ 317 abort(); \ 318 } \ 319 } while (0) 320