#ifndef lib_test_h #define lib_test_h /* Cesar project {{{ * * Copyright (C) 2007 Spidcom * * <<>> * * }}} */ /** * \file lib/test.h * \brief Test infrastructure. * \ingroup lib */ #include "lib/try.h" /** Test context. */ struct test_t { /** Current test suite. */ const char *current_test_suite; /** Current test case name. */ const char *current_test_case; /** Current test name. */ const char *current_test; /** Number of attempted tests. */ uint test_nb; /** Number of failed tests. */ uint fail_nb; /** Verbosity, 0 to 3. */ uint verbose; }; typedef struct test_t test_t[1]; /** * Initialise the test context. * \param t test context * \param argc program arguments count * \param argv program arguments values * * Does not complain on unrecognised arguments. */ void test_init (test_t t, int argc, char **argv); /** * Initialise the test context without command line. * \param t test context * \param verbose verbosity, see test_t. */ void test_init_basic (test_t t, uint verbose); /** * Clean up test context and print a test summary. * \param t test context */ void test_result (test_t t); /** * Query the number of attempted tests. * \param t test context * \return number of attempted tests */ extern inline uint test_nb_attempted (test_t t) { return t->test_nb; } /** * Query the number of failed tests. * \param t test context * \return number of failed tests */ extern inline uint test_nb_failed (test_t t) { return t->fail_nb; } /** * Begin a new test suite. * \param t test context * \param name test suite name */ void test_suite_begin (test_t t, const char *name); /** * Begin a new test case. * \param t test context * \param name test case name */ void test_case_begin (test_t t, const char *name); /** * Just a empty function to place a breakpoint. */ void test_failled (void); /** * Format a test related message. * \param t test context * \param file source file name * \param line source file line * \param type message type ('F': fail, 'P': pass, 'V': verbose message) * \param ufmt unformatted message, used if fmt is NULL * \param fmt printf-like formatted message */ void test_format_ (test_t t, const char *file, int line, char type, const char *ufmt, const char *fmt, ...); /** * Begin a test. * \param t test context * \param name test name * * This macro and its peer \c test_end use a syntax similar to a do { ... } * while (); block. On failure, non volatile local variables have unspecified * value, see \c setjmp for details. */ #define test_begin(t, name) test_begin_ ((t), (name)) /** End a test, see \c test_begin(). */ #define test_end test_end_ /** * Use this macro when at the start of a function called within a test. * \param t test context */ #define test_within(t) test_within_ (t) #define test_begin_(t, name) \ { \ struct test_t *please_use_test_begin__ = (t); \ please_use_test_begin__->current_test = (name); \ please_use_test_begin__->test_nb++; \ try_begin \ { \ dbg_fatal_try_begin \ { #define test_end_ \ } \ dbg_fatal_try_catch (const char *fatal_msg) \ { \ test_fail_unless_ (0, NULL, "assertion caught:\n%s", fatal_msg); \ } \ dbg_fatal_try_end; \ test_format_ (please_use_test_begin__, __FILE__, __LINE__, 'P', \ "passed", NULL); \ } \ try_catch (TRY_CODE_TEST_FAILURE) \ { \ please_use_test_begin__->fail_nb++; \ } \ try_always \ { \ please_use_test_begin__->current_test = NULL; \ } \ try_end; \ } #define test_within_(t) \ struct test_t *please_use_test_begin__ = (t) #define test_abort_() \ try_throw (TRY_CODE_TEST_FAILURE) /** * Report the test failure unless the provided expression evaluate to true. * \param expr the assumed truth * \param msg optional printf-like formated message */ #define test_fail_unless(expr, msg...) \ test_fail_unless_ ((expr), "`" #expr "' failed", ## msg) /** * Report the test failure if the provided expression evaluate to true. * \param expr the fatal expression * \param msg optional printf-like formated message */ #define test_fail_if(expr, msg...) \ test_fail_unless_ (!(expr), "`" #expr "' triggered", ## msg) /** * Report the test failure unconditionally. * \param msg optional printf-like formated message */ #define test_fail(msg...) \ test_fail_unless_ (0, "failed", ## msg) #define test_fail_unless_(expr, exprs, msg...) \ do { \ if (!(expr)) \ { \ test_format_ (please_use_test_begin__, __FILE__, __LINE__, 'F', \ exprs, ##msg, NULL); \ test_abort_ (); \ } \ } while (0) /** * Print additional information only when very verbose. * \param msg printf-like formated message */ #define test_verbose_print(msg...) test_verbose_print_ (msg) #define test_verbose_print_(msg...) \ do { \ test_format_ (please_use_test_begin__, __FILE__, __LINE__, 'V', \ NULL, msg, NULL); \ } while (0) /** * Print debug information. * \param msg printf-like formated message */ void test_debug_print (const char *msg, ...); #endif /* lib_test_h */