testsupport.h (4417B)
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) */