Merge branch 'maint-0.4.8'
[tor.git] / src / lib / testsupport / testsupport.h
blob72e76a6d96041fcca6b8586723638b50e87ed787
1 /* Copyright (c) 2013-2021, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
4 /**
5 * \file testsupport.h
7 * \brief Macros to implement mocking and selective exposure for the test code.
9 * Each Tor source file is built twice: once with TOR_UNIT_TESTS defined, and
10 * once with it undefined. The only difference between these configurations
11 * should be that when building for the tests, more functions are exposed as
12 * non-static, and a number of functions are declared as mockable.
13 **/
15 #ifndef TOR_TESTSUPPORT_H
16 #define TOR_TESTSUPPORT_H
18 /** The "STATIC" macro marks a function or variable that is static when
19 * building Tor for production, but non-static when building the unit
20 * tests.
22 * For example, a function declared as:
24 * STATIC int internal_function(void);
26 * should be only visible for the file on which it is declared, and in the
27 * unit tests.
29 #ifdef TOR_UNIT_TESTS
30 #define STATIC
31 #else /* !defined(TOR_UNIT_TESTS) */
32 #define STATIC static
33 #endif /* defined(TOR_UNIT_TESTS) */
35 /** The "EXTERN" macro is used along with "STATIC" for variables declarations:
36 * it expands to an extern declaration when Tor building unit tests, and to
37 * nothing otherwise.
39 * For example, to declare a variable as visible only visible in one
40 * file and in the unit tests, you would put this in the header:
42 * EXTERN(int, local_variable)
44 * and this in the source:
46 * STATIC int local_variable;
48 #ifdef TOR_UNIT_TESTS
49 #define EXTERN(type, name) extern type name;
50 #else
51 #define EXTERN(type, name)
52 #endif
54 /** Quick and dirty macros to implement test mocking.
56 * To use them, suppose that you have a function you'd like to mock
57 * with the signature "void writebuf(size_t n, char *buf)". You can then
58 * declare the function as:
60 * MOCK_DECL(void, writebuf, (size_t n, char *buf));
62 * and implement it as:
64 * MOCK_IMPL(void,
65 * writebuf,(size_t n, char *buf))
66 * {
67 * ...
68 * }
70 * For the non-testing build, this will expand simply into:
72 * void writebuf(size_t n, char *buf);
73 * void
74 * writebuf(size_t n, char *buf)
75 * {
76 * ...
77 * }
79 * But for the testing case, it will expand into:
81 * void writebuf__real(size_t n, char *buf);
82 * extern void (*writebuf)(size_t n, char *buf);
84 * void (*writebuf)(size_t n, char *buf) = writebuf__real;
85 * void
86 * writebuf__real(size_t n, char *buf)
87 * {
88 * ...
89 * }
91 * This is not a great mocking system! It is deliberately "the simplest
92 * thing that could work", and pays for its simplicity in its lack of
93 * features, and in its uglification of the Tor code. Replacing it with
94 * something clever would be a fine thing.
96 * @{ */
97 #ifdef TOR_UNIT_TESTS
98 /** Declare a mocked function. For use in headers. */
99 #define MOCK_DECL(rv, funcname, arglist) \
100 rv funcname ##__real arglist; \
101 extern rv(*funcname) arglist
102 /** Define the implementation of a mocked function. */
103 #define MOCK_IMPL(rv, funcname, arglist) \
104 rv(*funcname) arglist = funcname ##__real; \
105 rv funcname ##__real arglist
106 /** As MOCK_DECL(), but allow attributes. */
107 #define MOCK_DECL_ATTR(rv, funcname, arglist, attr) \
108 rv funcname ##__real arglist attr; \
109 extern rv(*funcname) arglist
111 * Replace <b>func</b> (a mockable function) with a replacement function.
113 * Only usable when Tor has been built for unit tests. */
114 #define MOCK(func, replacement) \
115 do { \
116 (func) = (replacement); \
117 } while (0)
118 /** Replace <b>func</b> (a mockable function) with its original value.
120 * Only usable when Tor has been built for unit tests. */
121 #define UNMOCK(func) \
122 do { \
123 func = func ##__real; \
124 } while (0)
125 #else /* !defined(TOR_UNIT_TESTS) */
126 /** Declare a mocked function. For use in headers. */
127 #define MOCK_DECL(rv, funcname, arglist) \
128 rv funcname arglist
129 /** As MOCK_DECL(), but allow */
130 #define MOCK_DECL_ATTR(rv, funcname, arglist, attr) \
131 rv funcname arglist attr
132 /** Define the implementation of a mocked function. */
133 #define MOCK_IMPL(rv, funcname, arglist) \
134 rv funcname arglist
135 #endif /* defined(TOR_UNIT_TESTS) */
136 /** @} */
138 #endif /* !defined(TOR_TESTSUPPORT_H) */