summary refs log tree commit diff
path: root/src/libnm-glib-aux/nm-test-utils.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/libnm-glib-aux/nm-test-utils.h')
-rw-r--r--src/libnm-glib-aux/nm-test-utils.h256
1 files changed, 212 insertions, 44 deletions
diff --git a/src/libnm-glib-aux/nm-test-utils.h b/src/libnm-glib-aux/nm-test-utils.h
index d338d0af..41e1a6ce 100644
--- a/src/libnm-glib-aux/nm-test-utils.h
+++ b/src/libnm-glib-aux/nm-test-utils.h
@@ -39,7 +39,7 @@
  *   depending on the test. See nmtst_is_debug().
  *   Known differences:
  *    - a test might leave the logging level unspecified. In this case, running in
- *      debug mode, will turn on DEBUG logging, otherwise WARN logging only.
+ *      debug mode, will turn on TRACE logging, otherwise WARN logging only.
  *    - if G_MESSAGES_DEBUG is unset, nm-test will set G_MESSAGES_DEBUG=all
  *      for tests that don't do assert-logging.
  *   Debug mode is determined as follows (highest priority first):
@@ -85,6 +85,9 @@
 #undef g_assertion_message_expr
 #endif
 
+#undef NDEBUG
+#include <assert.h>
+
 #include <arpa/inet.h>
 #include <stdio.h>
 #include <unistd.h>
@@ -221,17 +224,24 @@
 
 /*****************************************************************************/
 
+struct __nmtst_testdata_track {
+    gpointer       data;
+    GDestroyNotify destroy_notify;
+};
+
 struct __nmtst_internal {
-    GRand   *rand0;
-    guint32  rand_seed;
-    GRand   *rand;
-    gboolean is_debug;
-    gboolean assert_logging;
-    gboolean no_expect_message;
-    gboolean test_quick;
-    gboolean test_tap_log;
-    char    *sudo_cmd;
-    char   **orig_argv;
+    GRand      *rand0;
+    guint32     rand_seed;
+    GRand      *rand;
+    gboolean    is_debug;
+    gboolean    assert_logging;
+    gboolean    no_expect_message;
+    gboolean    test_quick;
+    gboolean    test_tap_log;
+    char       *sudo_cmd;
+    char      **orig_argv;
+    const char *testpath;
+    GArray     *testdata_track_array;
 };
 
 extern struct __nmtst_internal __nmtst_internal;
@@ -252,6 +262,62 @@ nmtst_initialized(void)
     return !!__nmtst_internal.rand0;
 }
 
+/*****************************************************************************/
+
+static inline void
+_nmtst_testdata_track_clear_func(gpointer ptr)
+{
+    struct __nmtst_testdata_track *d = ptr;
+
+    if (d->destroy_notify)
+        d->destroy_notify(d->data);
+    memset(d, 0, sizeof(*d));
+}
+
+static inline void
+_nmtst_testdata_track_add(gpointer data, GDestroyNotify destroy_notify)
+{
+    struct __nmtst_testdata_track d = {
+        .data           = data,
+        .destroy_notify = destroy_notify,
+    };
+
+    g_assert(data);
+    g_assert(destroy_notify);
+    g_assert(__nmtst_internal.testdata_track_array);
+
+    g_array_append_val(__nmtst_internal.testdata_track_array, d);
+}
+
+static inline void
+_nmtst_testdata_track_steal(gpointer data)
+{
+    struct __nmtst_testdata_track *d;
+    guint                          i;
+
+    g_assert(data);
+    g_assert(__nmtst_internal.testdata_track_array);
+
+    for (i = 0; i < __nmtst_internal.testdata_track_array->len; i++) {
+        d = &g_array_index(__nmtst_internal.testdata_track_array, struct __nmtst_testdata_track, i);
+
+        if (d->data != data)
+            continue;
+
+        d->destroy_notify = NULL;
+        g_array_remove_index_fast(__nmtst_internal.testdata_track_array, i);
+        return;
+    }
+    g_assert_not_reached();
+}
+
+static inline void
+_nmtst_testdata_track_steal_and_free(gpointer data)
+{
+    _nmtst_testdata_track_steal(data);
+    g_free(data);
+}
+
 #define __NMTST_LOG(cmd, ...)                                                                  \
     G_STMT_START                                                                               \
     {                                                                                          \
@@ -309,7 +375,7 @@ BREAK_INNER_LOOPS:
         str = &str[i];
     }
 
-    return (char **) g_array_free(result, FALSE);
+    return (char **) ((gpointer) g_array_free(result, FALSE));
 }
 
 /* free instances allocated by nmtst (especially nmtst_init()) on shutdown
@@ -320,6 +386,9 @@ nmtst_free(void)
     if (!nmtst_initialized())
         return;
 
+    g_array_set_size(__nmtst_internal.testdata_track_array, 0);
+    g_array_unref(__nmtst_internal.testdata_track_array);
+
     g_rand_free(__nmtst_internal.rand0);
     if (__nmtst_internal.rand)
         g_rand_free(__nmtst_internal.rand);
@@ -576,10 +645,14 @@ __nmtst_init(int        *argc,
     __nmtst_internal.sudo_cmd          = sudo_cmd;
     __nmtst_internal.no_expect_message = no_expect_message;
 
+    __nmtst_internal.testdata_track_array =
+        g_array_new(FALSE, FALSE, sizeof(struct __nmtst_testdata_track));
+    g_array_set_clear_func(__nmtst_internal.testdata_track_array, _nmtst_testdata_track_clear_func);
+
     if (!log_level && log_domains) {
         /* if the log level is not specified (but the domain is), we assume
          * the caller wants to set it depending on is_debug */
-        log_level = is_debug ? "DEBUG" : "WARN";
+        log_level = is_debug ? "TRACE" : "WARN";
     }
 
     if (!__nmtst_internal.assert_logging) {
@@ -661,9 +734,9 @@ __nmtst_init(int        *argc,
 
     /* Delay messages until we setup logging. */
     for (i = 0; i < debug_messages->len; i++)
-        __NMTST_LOG(g_message, "%s", g_array_index(debug_messages, const char *, i));
+        __NMTST_LOG(g_message, "%s", nm_g_array_index(debug_messages, const char *, i));
 
-    g_strfreev((char **) g_array_free(debug_messages, FALSE));
+    g_strfreev((char **) ((gpointer) g_array_free(debug_messages, FALSE)));
     g_free(c_log_level);
     g_free(c_log_domains);
 
@@ -699,6 +772,12 @@ nmtst_init(int *argc, char ***argv, gboolean assert_logging)
 static inline gboolean
 nmtst_is_debug(void)
 {
+    /* This is based on the "debug"/"no-debug" flag in "$NMTST_DEBUG".
+     *
+     * If debugging is enabled, print more information. However, make sure
+     * that the test behaves still in a similar manner and that the same code
+     * path are taken where it matters (it matters for example, if the code path
+     * consumes random numbers). */
     g_assert(nmtst_initialized());
     return __nmtst_internal.is_debug;
 }
@@ -774,15 +853,12 @@ typedef struct _NmtstTestData NmtstTestData;
 typedef void (*NmtstTestHandler)(const NmtstTestData *test_data);
 
 struct _NmtstTestData {
-    union {
-        const char *testpath;
-        char       *_testpath;
-    };
+    const char      *testpath;
     gsize            n_args;
-    gpointer        *args;
     NmtstTestHandler _func_setup;
     GTestDataFunc    _func_test;
     NmtstTestHandler _func_teardown;
+    gpointer         args[];
 };
 
 static inline void
@@ -807,15 +883,20 @@ _nmtst_test_data_unpack(const NmtstTestData *test_data, gsize n_args, ...)
 #define nmtst_test_data_unpack(test_data, ...) \
     _nmtst_test_data_unpack(test_data, NM_NARG(__VA_ARGS__), ##__VA_ARGS__)
 
-static inline void
-_nmtst_test_data_free(gpointer data)
+static inline const char *
+nmtst_test_get_path(void)
 {
-    NmtstTestData *test_data = data;
+    g_assert(nmtst_initialized());
+    g_assert(__nmtst_internal.testpath);
 
-    g_assert(test_data);
+    /* Similar to g_test_get_path() (which only exists since glib 2.68).
+     *
+     * This is the test name while running the test added with
+     * nmtst_add_test_func*().
+     *
+     * You are only allowed to call this from inside such a test. */
 
-    g_free(test_data->_testpath);
-    g_free(test_data);
+    return __nmtst_internal.testpath;
 }
 
 static inline void
@@ -823,6 +904,13 @@ _nmtst_test_run(gconstpointer data)
 {
     const NmtstTestData *test_data = data;
 
+    g_assert(test_data);
+    g_assert(nmtst_initialized());
+    g_assert(test_data->testpath);
+    g_assert(!__nmtst_internal.testpath);
+
+    __nmtst_internal.testpath = test_data->testpath;
+
     if (test_data->_func_setup)
         test_data->_func_setup(test_data);
 
@@ -830,6 +918,10 @@ _nmtst_test_run(gconstpointer data)
 
     if (test_data->_func_teardown)
         test_data->_func_teardown(test_data);
+
+    g_assert(__nmtst_internal.testpath);
+    g_assert(__nmtst_internal.testpath == test_data->testpath);
+    __nmtst_internal.testpath = NULL;
 }
 
 static inline void
@@ -843,26 +935,41 @@ _nmtst_add_test_func_full(const char      *testpath,
     gsize          i;
     NmtstTestData *data;
     va_list        ap;
+    gsize          testpath_len;
 
     g_assert(testpath && testpath[0]);
     g_assert(func_test);
 
-    data = g_malloc0(sizeof(NmtstTestData) + (sizeof(gpointer) * (n_args + 1)));
+    testpath_len = strlen(testpath) + 1u;
+
+    data = g_malloc(G_STRUCT_OFFSET(NmtstTestData, args)
+                    + (sizeof(gpointer) * (n_args + 1u) + testpath_len));
+
+    *data = (NmtstTestData){
+        .testpath       = (gpointer) &data->args[n_args + 1u],
+        ._func_test     = func_test,
+        ._func_setup    = func_setup,
+        ._func_teardown = func_teardown,
+        .n_args         = n_args,
+    };
 
-    data->_testpath      = g_strdup(testpath);
-    data->_func_test     = func_test;
-    data->_func_setup    = func_setup;
-    data->_func_teardown = func_teardown;
-    data->n_args         = n_args;
-    data->args           = (gpointer) &data[1];
     va_start(ap, n_args);
     for (i = 0; i < n_args; i++)
         data->args[i] = va_arg(ap, gpointer);
     data->args[i] = NULL;
     va_end(ap);
 
-    g_test_add_data_func_full(testpath, data, _nmtst_test_run, _nmtst_test_data_free);
+    g_assert(data->testpath == (gpointer) &data->args[i + 1]);
+
+    memcpy((char *) data->testpath, testpath, testpath_len);
+
+    _nmtst_testdata_track_add(data, g_free);
+    g_test_add_data_func_full(testpath,
+                              data,
+                              _nmtst_test_run,
+                              _nmtst_testdata_track_steal_and_free);
 }
+
 #define nmtst_add_test_func_full(testpath, func_test, func_setup, func_teardown, ...) \
     _nmtst_add_test_func_full(testpath,                                               \
                               func_test,                                              \
@@ -870,6 +977,7 @@ _nmtst_add_test_func_full(const char      *testpath,
                               func_teardown,                                          \
                               NM_NARG(__VA_ARGS__),                                   \
                               ##__VA_ARGS__)
+
 #define nmtst_add_test_func(testpath, func_test, ...) \
     nmtst_add_test_func_full(testpath, func_test, NULL, NULL, ##__VA_ARGS__)
 
@@ -1192,6 +1300,28 @@ nmtst_get_rand_word_length(GRand *rand)
 /*****************************************************************************/
 
 static inline gboolean
+nmtst_true_once(gboolean *state, gboolean new_val)
+{
+    /* Returns only once a TRUE flag. When returning TRUE,
+     * it will be remembered in "state" and future invocations
+     * return FALSE.
+     *
+     * Also, if "new_val" is FALSE, it won't return TRUE.
+     *
+     * The point is to do an action once (depending on "new_val"),
+     * and remember it in "state".
+     */
+    if (!new_val)
+        return FALSE;
+    if (*state)
+        return FALSE;
+    *state = TRUE;
+    return TRUE;
+}
+
+/*****************************************************************************/
+
+static inline gboolean
 nmtst_g_source_assert_not_called(gpointer user_data)
 {
     g_assert_not_reached();
@@ -1564,7 +1694,7 @@ nmtst_inet4_from_string(const char *str)
 }
 
 static inline const struct in6_addr *
-nmtst_inet6_from_string(const char *str)
+nmtst_inet6_from_string_p(const char *str)
 {
     static _nm_thread_local struct in6_addr addr;
     int                                     success;
@@ -1579,6 +1709,22 @@ nmtst_inet6_from_string(const char *str)
     return &addr;
 }
 
+static inline struct in6_addr
+nmtst_inet6_from_string(const char *str)
+{
+    struct in6_addr addr;
+    int             success;
+
+    if (!str)
+        addr = in6addr_any;
+    else {
+        success = inet_pton(AF_INET6, str, &addr);
+        g_assert(success == 1);
+    }
+
+    return addr;
+}
+
 static inline gconstpointer
 nmtst_inet_from_string(int addr_family, const char *str)
 {
@@ -1589,7 +1735,7 @@ nmtst_inet_from_string(int addr_family, const char *str)
         return &a;
     }
     if (addr_family == AF_INET6)
-        return nmtst_inet6_from_string(str);
+        return nmtst_inet6_from_string_p(str);
 
     g_assert_not_reached();
     return NULL;
@@ -1648,7 +1794,7 @@ _nmtst_assert_ip6_address(const char            *file,
     if (!addr)
         addr = &any;
 
-    if (memcmp(nmtst_inet6_from_string(str_expected), addr, sizeof(*addr)) != 0) {
+    if (memcmp(nmtst_inet6_from_string_p(str_expected), addr, sizeof(*addr)) != 0) {
         char buf[100];
 
         g_error("%s:%d: Unexpected IPv6 address: expected %s, got %s",
@@ -1917,7 +2063,7 @@ nmtst_logging_disable(gboolean always)
         return NULL;
     }
 
-    p = g_memdup(_nm_logging_enabled_state, sizeof(_nm_logging_enabled_state));
+    p = nm_memdup(_nm_logging_enabled_state, sizeof(_nm_logging_enabled_state));
     memset(_nm_logging_enabled_state, 0, sizeof(_nm_logging_enabled_state));
     return p;
 }
@@ -1944,9 +2090,9 @@ nmtst_setting_ip_config_add_address(NMSettingIPConfig *s_ip, const char *address
 
     g_assert(s_ip);
 
-    if (nm_utils_ipaddr_is_valid(AF_INET, address))
+    if (nm_inet_is_valid(AF_INET, address))
         family = AF_INET;
-    else if (nm_utils_ipaddr_is_valid(AF_INET6, address))
+    else if (nm_inet_is_valid(AF_INET6, address))
         family = AF_INET6;
     else
         g_assert_not_reached();
@@ -1969,9 +2115,9 @@ nmtst_setting_ip_config_add_route(NMSettingIPConfig *s_ip,
 
     g_assert(s_ip);
 
-    if (nm_utils_ipaddr_is_valid(AF_INET, dest))
+    if (nm_inet_is_valid(AF_INET, dest))
         family = AF_INET;
-    else if (nm_utils_ipaddr_is_valid(AF_INET6, dest))
+    else if (nm_inet_is_valid(AF_INET6, dest))
         family = AF_INET6;
     else
         g_assert_not_reached();
@@ -2682,7 +2828,8 @@ _nmtst_variant_new_vardict(int dummy, ...)
     G_STMT_END
 #else
 #define _nmtst_assert_variant_bytestring_cmp_str(_ptr, _ptr2, _len) \
-    G_STMT_START {}                                                 \
+    G_STMT_START                                                    \
+    {}                                                              \
     G_STMT_END
 #endif
 
@@ -2913,7 +3060,7 @@ nmtst_ip_address_new(int addr_family, const char *str)
     GError      *error = NULL;
     NMIPAddress *a;
 
-    if (!nm_utils_parse_inaddr_prefix_bin(addr_family, str, &addr_family, &addr, &plen))
+    if (!nm_inet_parse_with_prefix_bin(addr_family, str, &addr_family, &addr, &plen))
         g_assert_not_reached();
 
     if (plen == -1)
@@ -2928,6 +3075,27 @@ nmtst_ip_address_new(int addr_family, const char *str)
 
 /*****************************************************************************/
 
+static inline gpointer
+nmtst_keeper_add(GPtrArray **p_arr, gpointer ptr)
+{
+    if (!p_arr) {
+        /* If not GPtrArray in/out argument is given, track the pointer
+         * via _nmtst_testdata_track_add(), which means it stays alive
+         * until the end of the test. */
+        _nmtst_testdata_track_add(ptr, g_free);
+    } else {
+        if (!*p_arr)
+            *p_arr = g_ptr_array_new_with_free_func(g_free);
+
+        g_ptr_array_add(*p_arr, ptr);
+    }
+    return ptr;
+}
+
+#define nmtst_keeper_printf(p_ptr, ...) nmtst_keeper_add((p_ptr), g_strdup_printf(__VA_ARGS__))
+
+/*****************************************************************************/
+
 #define nmtst_gbytes_from_arr(...)           \
     ({                                       \
         const guint8 _arr[] = {__VA_ARGS__}; \