From: Tobias Brunner Date: Thu, 28 Nov 2013 17:02:18 +0000 (+0100) Subject: unit-tests: Add facility to register testable functions X-Git-Tag: 5.1.2.dr2~7 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4cea186b64c573a2030a66377c51857b401dbea0;p=thirdparty%2Fstrongswan.git unit-tests: Add facility to register testable functions These can be defined in plugins, or other parts of the tested libraries. They can even be static. --- diff --git a/src/libstrongswan/Android.mk b/src/libstrongswan/Android.mk index 1b26157639..492522ff5d 100644 --- a/src/libstrongswan/Android.mk +++ b/src/libstrongswan/Android.mk @@ -36,7 +36,7 @@ selectors/traffic_selector.c threading/thread.c threading/thread_value.c \ threading/mutex.c threading/semaphore.c threading/rwlock.c threading/spinlock.c \ utils/utils.c utils/chunk.c utils/debug.c utils/enum.c utils/identification.c \ utils/lexparser.c utils/optionsfrom.c utils/capabilities.c utils/backtrace.c \ -utils/printf_hook/printf_hook_builtin.c utils/settings.c +utils/printf_hook/printf_hook_builtin.c utils/settings.c utils/test.c # adding the plugin source files diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index 0b2bbffffe..28d78df31e 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -34,7 +34,7 @@ selectors/traffic_selector.c threading/thread.c threading/thread_value.c \ threading/mutex.c threading/semaphore.c threading/rwlock.c threading/spinlock.c \ utils/utils.c utils/chunk.c utils/debug.c utils/enum.c utils/identification.c \ utils/lexparser.c utils/optionsfrom.c utils/capabilities.c utils/backtrace.c \ -utils/settings.c +utils/settings.c utils/test.c if USE_DEV_HEADERS strongswan_includedir = ${dev_headers} @@ -82,7 +82,7 @@ utils/utils.h utils/chunk.h utils/debug.h utils/enum.h utils/identification.h \ utils/lexparser.h utils/optionsfrom.h utils/capabilities.h utils/backtrace.h \ utils/leak_detective.h utils/printf_hook/printf_hook.h \ utils/printf_hook/printf_hook_vstr.h utils/printf_hook/printf_hook_builtin.h \ -utils/settings.h utils/integrity_checker.h +utils/settings.h utils/test.h utils/integrity_checker.h endif library.lo : $(top_builddir)/config.status diff --git a/src/libstrongswan/tests/test_runner.c b/src/libstrongswan/tests/test_runner.c index 0bb1ab309b..bf18f16fb3 100644 --- a/src/libstrongswan/tests/test_runner.c +++ b/src/libstrongswan/tests/test_runner.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -30,6 +31,30 @@ */ #define TTY(color) tty_escape_get(2, TTY_FG_##color) +/** + * Initialize the lookup table for testable functions (defined in libstrongswan) + */ +static void testable_functions_create() __attribute__ ((constructor(1000))); +static void testable_functions_create() +{ + testable_functions = hashtable_create(hashtable_hash_str, + hashtable_equals_str, 8); +} + +/** + * Destroy the lookup table for testable functions + */ +static void testable_functions_destroy() __attribute__ ((destructor(1000))); +static void testable_functions_destroy() +{ + testable_functions->destroy(testable_functions); + /* if leak detective is enabled plugins are not actually unloaded, which + * means their destructor is called AFTER this one when the process + * terminates, even though the priority says differently, make sure this + * does not crash */ + testable_functions = NULL; +} + /** * Load all available test suites */ diff --git a/src/libstrongswan/utils/test.c b/src/libstrongswan/utils/test.c new file mode 100644 index 0000000000..7de5a76615 --- /dev/null +++ b/src/libstrongswan/utils/test.c @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2013 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * 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 + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "test.h" + +#include + +/** + * A collection of testable functions + */ +hashtable_t *testable_functions; + +/* + * Described in header. + */ +void testable_function_register(char *name, void *fn) +{ + if (testable_functions) + { + bool old = FALSE; + if (lib->leak_detective) + { + old = lib->leak_detective->set_state(lib->leak_detective, FALSE); + } + if (fn) + { + testable_functions->put(testable_functions, name, fn); + } + else + { + testable_functions->remove(testable_functions, name); + } + if (lib->leak_detective) + { + lib->leak_detective->set_state(lib->leak_detective, old); + } + } +} diff --git a/src/libstrongswan/utils/test.h b/src/libstrongswan/utils/test.h new file mode 100644 index 0000000000..d3c6416748 --- /dev/null +++ b/src/libstrongswan/utils/test.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2013 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * 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 + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup test test + * @{ @ingroup utils + */ + +#ifndef TEST_H_ +#define TEST_H_ + +#include "collections/hashtable.h" + +/** + * Collection of testable functions. + * + * @note Is initialized only if libtest is loaded. + */ +extern hashtable_t *testable_functions; + +/** + * Register a (possibly static) function so that it can be called from tests. + * + * @param name name (namespace/function) + * @param fn function to register (set to NULL to unregister) + */ +void testable_function_register(char *name, void *fn); + +/** + * Macro to automatically register/unregister a function that can be called + * from tests. + * + * @param ns namespace + * @param fn function to register + */ +#define EXPORT_FUNCTION_FOR_TESTS(ns, fn) \ +static void testable_function_register_##fn() __attribute__ ((constructor(2000))); \ +static void testable_function_register_##fn() \ +{ \ + testable_function_register(#ns "/" #fn, fn); \ +} \ +static void testable_function_unregister_##fn() __attribute__ ((destructor(2000))); \ +static void testable_function_unregister_##fn() \ +{ \ + testable_function_register(#ns "/" #fn, NULL); \ +} + +/** + * Import a registered function so that it can be called from tests. + * + * @note If the imported function is static (or no conflicting header files + * are included) ret can be prefixed with static to declare the function static. + * + * @note We allocate an arbitrary amount of stack space, hopefully enough for + * all arguments. + * + * @param ns namespace of the function + * @param name name of the function + * @param ret return type of the function + * @param ... arguments of the function + */ +#define IMPORT_FUNCTION_FOR_TESTS(ns, name, ret, ...) \ +ret name(__VA_ARGS__) \ +{ \ + void (*fn)() = NULL; \ + if (testable_functions) \ + { \ + fn = testable_functions->get(testable_functions, #ns "/" #name); \ + } \ + if (fn) \ + { \ + void *args = __builtin_apply_args(); \ + __builtin_return(__builtin_apply(fn, args, 16*sizeof(void*))); \ + } \ + test_fail_msg(__FILE__, __LINE__, "function " #name " (" #ns ") not found"); \ + __builtin_return(NULL); \ +} + +#endif /** TEST_H_ @}*/