]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
unit-tests: Support testable functions on Windows, avoid weak GCC symbols
authorMartin Willi <martin@revosec.ch>
Thu, 3 Apr 2014 10:25:38 +0000 (12:25 +0200)
committerMartin Willi <martin@revosec.ch>
Wed, 4 Jun 2014 13:53:12 +0000 (15:53 +0200)
Instead of using weak symbols, we use dlsym() on Windows to find an arbitrary
symbol in libtest to detect its linkage. Instead of creating the associated
hashtable in the test runner, we maintain it in libstrongswan, making it
significantly simpler.

src/libstrongswan/tests/test_runner.c
src/libstrongswan/utils/test.c
src/libstrongswan/utils/test.h

index 63d79199f5645900571e2eb1d82353cce4357a46..443c0ae137c8ccc9525551cb2a9d0b0c19b79695 100644 (file)
 #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
index 624ac4b3475aaf5363a5c8b49a9c07dad0e162a0..0b0a80f424a3d8906b1651344f11bbb2b7cd2b8a 100644 (file)
 /**
  * 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.
@@ -35,33 +45,48 @@ void testable_function_register(char *name, void *fn)
 {
        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;
+}
index a1b2a2d9b93f5752b7637430ae7d95053e2239a4..f9a84713e2e06d8f620bbca84487312bf0e5ad88 100644 (file)
 #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
@@ -82,10 +83,7 @@ static ret (*TEST_##ns##name)(__VA_ARGS__);
  */
 #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"); \