diff options
Diffstat (limited to 'src/libstrongswan/tests/test_suite.h')
-rw-r--r-- | src/libstrongswan/tests/test_suite.h | 350 |
1 files changed, 286 insertions, 64 deletions
diff --git a/src/libstrongswan/tests/test_suite.h b/src/libstrongswan/tests/test_suite.h index 2a2861323..c44f149f5 100644 --- a/src/libstrongswan/tests/test_suite.h +++ b/src/libstrongswan/tests/test_suite.h @@ -1,6 +1,8 @@ /* * Copyright (C) 2013 Tobias Brunner * Hochschule fuer Technik Rapperswil + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -13,98 +15,318 @@ * for more details. */ -#ifndef TEST_UTILS_H_ -#define TEST_UTILS_H_ +/** + * @defgroup test_suite test_suite + * @{ @ingroup libtest + */ + +#ifndef TEST_SUITE_H_ +#define TEST_SUITE_H_ + +#define _GNU_SOURCE +#include <setjmp.h> -#include <check.h> #include <library.h> #include <utils/debug.h> +#include <utils/backtrace.h> +#include <collections/array.h> + +typedef struct test_suite_t test_suite_t; +typedef struct test_case_t test_case_t; +typedef struct test_function_t test_function_t; +typedef struct test_fixture_t test_fixture_t; /** - * Used to mark test cases that use test fixtures. + * Default timeout for a single test function */ -#define UNIT_TEST_FIXTURE_USED "UNIT_TEST_FIXTURE_USED" +#define TEST_FUNCTION_DEFAULT_TIMEOUT 2 /** - * Check for memory leaks and fail if any are encountered. + * Test function implementation */ -#define CHECK_FOR_LEAKS() do \ -{ \ - if (lib->leak_detective) \ - { \ - if (lib->leak_detective->leaks(lib->leak_detective)) { \ - lib->leak_detective->report(lib->leak_detective, TRUE); \ - } \ - ck_assert_int_eq(lib->leak_detective->leaks(lib->leak_detective), 0); \ - } \ -} \ -while(0) +typedef void (*test_function_cb_t)(int); + +/** + * Fixture for a test case. + */ +typedef void (*test_fixture_cb_t)(void); + +/** + * A test suite; a collection of test cases with fixtures + */ +struct test_suite_t { + /** name of the test suite */ + const char *name; + /** test cases registered, as test_case_t* */ + array_t *tcases; +}; /** - * Extended versions of the START|END_TEST macros that use leak detective. + * A test case; multiple test functions using the same fixtures + */ +struct test_case_t { + /** name of the test case */ + const char *name; + /** tests registered, as test_function_t */ + array_t *functions; + /** fixture for tests, as test_fixture_t */ + array_t *fixtures; + /** timeout for each function, in s */ + int timeout; +}; + +/** + * A test function, with optional loop setup + */ +struct test_function_t { + /** name of test function */ + char *name; + /** tests function registered, test_function_t* */ + test_function_cb_t cb; + /** start for loop test */ + int start; + /** end for loop test */ + int end; +}; + +/** + * Registered fixture for a test case + */ +struct test_fixture_t { + test_fixture_cb_t setup; + test_fixture_cb_t teardown; +}; + +/** + * Create a new test suite * - * Since each test case runs in its own fork of the test runner the stuff - * allocated before the test starts is not freed, so leak detective is disabled - * by default to prevent false positives. By enabling it right when the test - * starts we at least capture leaks created by the tested objects/functions and - * the test case itself. This allows writing test cases for cleanup functions. + * @param name name of the test suite + * @return test suite + */ +test_suite_t* test_suite_create(const char *name); + +/** + * Create a new test case * - * To define test fixture with possibly allocated/destroyed memory that is - * allocated/freed in a test case use the START|END_SETUP|TEARDOWN macros. + * @param name name of test case + * @return test case */ -#undef START_TEST -#define START_TEST(name) \ -static void name (int _i CK_ATTRIBUTE_UNUSED) \ -{ \ - tcase_fn_start(""#name, __FILE__, __LINE__); \ - dbg_default_set_level(LEVEL_SILENT); \ - if (lib->leak_detective) \ - { \ - lib->leak_detective->set_state(lib->leak_detective, TRUE); \ - } +test_case_t* test_case_create(const char *name); -#undef END_TEST -#define END_TEST \ - if (!lib->get(lib, UNIT_TEST_FIXTURE_USED)) \ - { \ - CHECK_FOR_LEAKS(); \ - } \ -} +/** + * Add a setup/teardown function to the test case + * + * @param tcase test case to add a fixture to + * @param setup setup function called before each test + * @param teardown cleanup function called after each test + */ +void test_case_add_checked_fixture(test_case_t *tcase, test_fixture_cb_t setup, + test_fixture_cb_t teardown); + +/** + * Add a test function to a test case, with a name, looped several times + * + * @param name name of the test case + * @param tcase test case to add test function to + * @param cb callback function to invoke for test + * @param start start of loop counter + * @param end end of loop counter + */ +void test_case_add_test_name(test_case_t *tcase, char *name, + test_function_cb_t cb, int start, int end); + +/** + * Add a test function to a test case + * + * @param tcase test case to add test function to + * @param cb callback function to invoke for test + */ +#define test_case_add_test(tcase, cb) \ + test_case_add_test_name(tcase, #cb, cb, 0, 1) + +/** + * Add a test function to a test case, looped several times + * + * @param tcase test case to add test function to + * @param cb callback function to invoke for test + * @param start start of loop counter + * @param end end of loop counter + */ +#define test_case_add_loop_test(tcase, cb, start, end) \ + test_case_add_test_name(tcase, #cb, cb, start, end) + +/** + * Set a custom timeout for test functions in a test case + * + * @param tcase test case to set timeout for + * @param s test timeout in s + */ +void test_case_set_timeout(test_case_t *tcase, int s); + +/** + * Add a test function to a test case, looped several times + * + * @param suite test suite to add test case to + * @param tcase test case to add + */ +void test_suite_add_case(test_suite_t *suite, test_case_t *tcase); /** - * Define a function to setup a test fixture that can be used with the above - * macros. + * sigjmp restore point used by test_restore_point + */ +extern sigjmp_buf test_restore_point_env; + +/** + * Set or return from an execution restore point + * + * This call sets a restore execution point and returns TRUE after it has + * been set up. On test failure, the execution is returned to the restore point + * and FALSE is returned to indicate test failure. + * + * @return TRUE if restore point set, FALSE when restored */ -#define START_SETUP(name) \ -static void name() \ -{ \ - lib->set(lib, UNIT_TEST_FIXTURE_USED, (void*)TRUE); \ - if (lib->leak_detective) \ +#define test_restore_point() (sigsetjmp(test_restore_point_env, 1) == 0) + +/** + * Set up signal handlers for test cases + */ +void test_setup_handler(); + +/** + * Set up a timeout to let a test fail + * + * @param s timeout, 0 to disable timeout + */ +void test_setup_timeout(int s); + +/** + * Get info about a test failure + * + * @param msg buffer receiving failure info + * @param len size of msg buffer + * @param file pointer receiving source code file + * @return source code line number + */ +int test_failure_get(char *msg, int len, const char **file); + +/** + * Get a backtrace for a failure. + * + * @return allocated backtrace of test failure, if any + */ +backtrace_t *test_failure_backtrace(); + +/** + * Let a test fail and set a message using vprintf style arguments. + * + * @param file source code file name + * @param line source code line number + * @param fmt printf format string + * @param args argument list for fmt + */ +void test_fail_vmsg(const char *file, int line, char *fmt, va_list args); + +/** + * Let a test fail and set a message using printf style arguments. + * + * @param file source code file name + * @param line source code line number + * @param fmt printf format string + * @param ... arguments for fmt + */ +void test_fail_msg(const char *file, int line, char *fmt, ...); + +/** + * Check if two integers equal, fail test if not + * + * @param a first integer + * @param b second integer + */ +#define test_int_eq(a, b) \ +({ \ + typeof(a) _a = a; \ + typeof(b) _b = b; \ + if (_a != _b) \ { \ - lib->leak_detective->set_state(lib->leak_detective, TRUE); \ - } + test_fail_msg(__FILE__, __LINE__, #a " != " #b " (%d != %d)", _a, _b); \ + } \ +}) /** - * End a setup function + * Check if two strings equal, fail test if not + * + * @param a first string + * @param b second string */ -#define END_SETUP } +#define test_str_eq(a, b) \ +({ \ + char* _a = (char*)a; \ + char* _b = (char*)b; \ + if (!_a || !_b || !streq(_a, _b)) \ + { \ + test_fail_msg(__FILE__, __LINE__, \ + #a " != " #b " (\"%s\" != \"%s\")", _a, _b); \ + } \ +}) /** - * Define a function to teardown a test fixture that can be used with the above - * macros. + * Check if a statement evaluates to TRUE, fail test if not + * + * @param x statement to evaluate */ -#define START_TEARDOWN(name) \ -static void name() \ -{ +#define test_assert(x) \ +({ \ + if (!(x)) \ + { \ + test_fail_msg(__FILE__, __LINE__, #x); \ + } \ +}) /** - * End a teardown function + * Check if a statement evaluates to TRUE, fail and print a message if not + * + * @param x statement to evaluate + * @param fmt message format string + * @param ... fmt printf arguments */ -#define END_TEARDOWN \ - if (lib->get(lib, UNIT_TEST_FIXTURE_USED)) \ +#define test_assert_msg(x, fmt, ...) \ +({ \ + if (!(x)) \ { \ - CHECK_FOR_LEAKS(); \ + test_fail_msg(__FILE__, __LINE__, #x ": " fmt, ##__VA_ARGS__); \ } \ -} +}) + + + +/* "check unit testing" compatibility */ +#define Suite test_suite_t +#define TCase test_case_t +#define ck_assert_int_eq test_int_eq +#define ck_assert test_assert +#define ck_assert_msg test_assert_msg +#define ck_assert_str_eq test_str_eq +#define fail(fmt, ...) test_fail_msg(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define fail_if(x, fmt, ...) \ +({ \ + if (x) \ + { \ + test_fail_msg(__FILE__, __LINE__, #x ": " fmt, ##__VA_ARGS__); \ + } \ +}) +#define fail_unless test_assert_msg +#define suite_create test_suite_create +#define tcase_create test_case_create +#define tcase_add_checked_fixture test_case_add_checked_fixture +#define tcase_add_test test_case_add_test +#define tcase_add_loop_test test_case_add_loop_test +#define tcase_set_timeout test_case_set_timeout +#define suite_add_tcase test_suite_add_case +#define START_TEST(name) static void name (int _i) { +#define END_TEST } +#define START_SETUP(name) static void name() { +#define END_SETUP } +#define START_TEARDOWN(name) static void name() { +#define END_TEARDOWN } -#endif /** TEST_UTILS_H_ */ +#endif /** TEST_SUITE_H_ @}*/ |