Tor 0.4.9.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) */