Tor  0.4.7.0-alpha-dev
testsupport.h
Go to the documentation of this file.
1 /* Copyright (c) 2013-2021, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
3 
4 /**
5  * \file testsupport.h
6  *
7  * \brief Macros to implement mocking and selective exposure for the test code.
8  *
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  **/
14 
15 #ifndef TOR_TESTSUPPORT_H
16 #define TOR_TESTSUPPORT_H
17 
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.
21  *
22  * For example, a function declared as:
23  *
24  * STATIC int internal_function(void);
25  *
26  * should be only visible for the file on which it is declared, and in the
27  * unit tests.
28  */
29 #ifdef TOR_UNIT_TESTS
30 #define STATIC
31 #else /* !defined(TOR_UNIT_TESTS) */
32 #define STATIC static
33 #endif /* defined(TOR_UNIT_TESTS) */
34 
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.
38  *
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:
41  *
42  * EXTERN(int, local_variable)
43  *
44  * and this in the source:
45  *
46  * STATIC int local_variable;
47  */
48 #ifdef TOR_UNIT_TESTS
49 #define EXTERN(type, name) extern type name;
50 #else
51 #define EXTERN(type, name)
52 #endif
53 
54 /** Quick and dirty macros to implement test mocking.
55  *
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:
59  *
60  * MOCK_DECL(void, writebuf, (size_t n, char *buf));
61  *
62  * and implement it as:
63  *
64  * MOCK_IMPL(void,
65  * writebuf,(size_t n, char *buf))
66  * {
67  * ...
68  * }
69  *
70  * For the non-testing build, this will expand simply into:
71  *
72  * void writebuf(size_t n, char *buf);
73  * void
74  * writebuf(size_t n, char *buf)
75  * {
76  * ...
77  * }
78  *
79  * But for the testing case, it will expand into:
80  *
81  * void writebuf__real(size_t n, char *buf);
82  * extern void (*writebuf)(size_t n, char *buf);
83  *
84  * void (*writebuf)(size_t n, char *buf) = writebuf__real;
85  * void
86  * writebuf__real(size_t n, char *buf)
87  * {
88  * ...
89  * }
90  *
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.
95  *
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
110 /**
111  * Replace <b>func</b> (a mockable function) with a replacement function.
112  *
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.
119  *
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 /** @} */
137 
138 #endif /* !defined(TOR_TESTSUPPORT_H) */