tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

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) */