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