#define TTY(color) tty_escape_get(2, TTY_FG_##color)
/**
- * Initialize the lookup table for testable functions (defined in
- * libstrongswan). We don't use the constructor attribute as the order can't
- * really be defined (clang does not support it and gcc does not adhere to it in
- * the monolithic build). The function here is a weak symbol in libstrongswan.
+ * A global symbol indicating libtest linkage
*/
-void testable_functions_create()
-{
- if (!testable_functions)
- {
- /* as this is executed before chunk_hash() seed initialization used
- * by hashtables, we enforce seeding it here. */
- chunk_hash_seed();
- 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));
-static void testable_functions_destroy()
-{
- DESTROY_IF(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, make sure this does not crash */
- testable_functions = NULL;
-}
+#ifdef WIN32
+__declspec(dllexport)
+#endif
+bool test_runner_available = TRUE;
/**
* Destroy a single test suite and associated data
/**
* A collection of testable functions
*/
-hashtable_t *testable_functions;
+static hashtable_t *functions = NULL;
+
+#ifndef WIN32
+bool test_runner_available __attribute__((weak));
+#endif
/**
- * The function that actually initializes the hash table above. Provided
- * by the test runner.
+ * Check if we have libtest linkage and need testable functions
*/
-void testable_functions_create() __attribute__((weak));
+static bool has_libtest_linkage()
+{
+#ifdef WIN32
+ return dlsym(RTLD_DEFAULT, "test_runner_available");
+#else
+ return test_runner_available;
+#endif
+}
/*
* Described in header.
{
bool old = FALSE;
- if (!testable_functions_create)
- { /* not linked to the test runner */
- return;
- }
- else if (!fn && !testable_functions)
- { /* ignore as testable_functions has already been destroyed */
- return;
- }
-
if (lib && lib->leak_detective)
{
old = lib->leak_detective->set_state(lib->leak_detective, FALSE);
}
- if (!testable_functions)
- {
- testable_functions_create();
- }
- if (fn)
- {
- testable_functions->put(testable_functions, name, fn);
- }
- else
+
+ if (has_libtest_linkage())
{
- testable_functions->remove(testable_functions, name);
+ if (!functions)
+ {
+ chunk_hash_seed();
+ functions = hashtable_create(hashtable_hash_str,
+ hashtable_equals_str, 8);
+ }
+ if (fn)
+ {
+ functions->put(functions, name, fn);
+ }
+ else
+ {
+ functions->remove(functions, name);
+ if (functions->get_count(functions) == 0)
+ {
+ functions->destroy(functions);
+ functions = NULL;
+ }
+ }
}
+
if (lib && lib->leak_detective)
{
lib->leak_detective->set_state(lib->leak_detective, old);
}
}
+
+/*
+ * Described in header.
+ */
+void* testable_function_get(char *name)
+{
+ if (functions)
+ {
+ return functions->get(functions, name);
+ }
+ return NULL;
+}
#include "collections/hashtable.h"
/**
- * Collection of testable functions.
+ * Register a (possibly static) function so that it can be called from tests.
*
- * @note Is initialized only if libtest is loaded.
+ * @param name name (namespace/function)
+ * @param fn function to register (set to NULL to unregister)
*/
-extern hashtable_t *testable_functions;
+void testable_function_register(char *name, void *fn);
/**
- * Register a (possibly static) function so that it can be called from tests.
+ * Find a previously registered testable function.
*
* @param name name (namespace/function)
- * @param fn function to register (set to NULL to unregister)
+ * @return function, NULL if not found
*/
-void testable_function_register(char *name, void *fn);
+void* testable_function_get(char *name);
/**
* Macro to automatically register/unregister a function that can be called
*/
#define TEST_FUNCTION(ns, name, ...) \
({ \
- if (testable_functions) \
- { \
- TEST_##ns##name = testable_functions->get(testable_functions, #ns "/" #name); \
- } \
+ TEST_##ns##name = testable_function_get( #ns "/" #name); \
if (!TEST_##ns##name) \
{ \
test_fail_msg(__FILE__, __LINE__, "function " #name " (" #ns ") not found"); \