about summary refs log tree commit diff
path: root/shared/nm-utils
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2020-04-11 21:28:04 +0200
committerMichael Biebl <biebl@debian.org>2020-04-11 21:28:04 +0200
commit1e5977b62f896e844b548c3007ace9e1dfa7f9ed (patch)
tree7a7416ed410e72b6200f3d860fd315ec11cc106b /shared/nm-utils
parentb012fa6e1d808e0736c009799c62d835cbfcc1dd (diff)
New upstream version 1.23.90 upstream/1.23.90
Diffstat (limited to 'shared/nm-utils')
-rw-r--r--shared/nm-utils/nm-test-utils.h277
-rw-r--r--shared/nm-utils/nm-vpn-editor-plugin-call.h2
-rw-r--r--shared/nm-utils/tests/meson.build21
-rw-r--r--shared/nm-utils/tests/test-shared-general.c577
4 files changed, 233 insertions, 644 deletions
diff --git a/shared/nm-utils/nm-test-utils.h b/shared/nm-utils/nm-test-utils.h
index f0ea1179..96e36135 100644
--- a/shared/nm-utils/nm-test-utils.h
+++ b/shared/nm-utils/nm-test-utils.h
@@ -622,7 +622,7 @@ __nmtst_init (int *argc, char ***argv, gboolean assert_logging, const char *log_
 
 #ifdef __NETWORKMANAGER_UTILS_H__
 	/* ensure that monotonic timestamp is called (because it initially logs a line) */
-	nm_utils_get_monotonic_timestamp_s ();
+	nm_utils_get_monotonic_timestamp_sec ();
 #endif
 
 #ifdef NM_UTILS_H
@@ -848,6 +848,15 @@ nmtst_get_rand_uint32 (void)
 	return g_rand_int (nmtst_get_rand ());
 }
 
+static inline guint64
+nmtst_get_rand_uint64 (void)
+{
+	GRand *rand = nmtst_get_rand ();
+
+	return   (((guint64) g_rand_int (rand))      )
+	       | (((guint64) g_rand_int (rand)) << 32);
+}
+
 static inline guint
 nmtst_get_rand_uint (void)
 {
@@ -855,6 +864,16 @@ nmtst_get_rand_uint (void)
 	return nmtst_get_rand_uint32 ();
 }
 
+static inline gsize
+nmtst_get_rand_size (void)
+{
+	G_STATIC_ASSERT_EXPR (   sizeof (gsize) == sizeof (guint32)
+	                      || sizeof (gsize) == sizeof (guint64));
+	if (sizeof (gsize) == sizeof (guint32))
+		return nmtst_get_rand_uint32 ();
+	return nmtst_get_rand_uint64 ();
+}
+
 static inline gboolean
 nmtst_get_rand_bool (void)
 {
@@ -967,6 +986,89 @@ nmtst_rand_perm_gslist (GRand *rand, GSList *list)
 
 /*****************************************************************************/
 
+/**
+ * nmtst_get_rand_word_length:
+ * @rand: (allow-none): #GRand instance or %NULL to use the singleton.
+ *
+ * Returns: a random integer >= 0, that most frequently is somewhere between
+ * 0 and 16, but (with decreasing) probability, it can be larger. This can
+ * be used when we generate random input for unit tests.
+ */
+static inline guint
+nmtst_get_rand_word_length (GRand *rand)
+{
+	guint n;
+
+	if (!rand)
+		rand = nmtst_get_rand ();
+
+	n = 0;
+	while (TRUE) {
+		guint32 rnd = g_rand_int (rand);
+		guint probability;
+
+		/* The following python code implements a random sample with this
+		 * distribution:
+		 *
+		 *    def random_histogram(n_tries, scale = None):
+		 *        def probability(n_tok):
+		 *            import math
+		 *            return max(2, math.floor(100 / (2*(n_tok+1))))
+		 *        def n_tokens():
+		 *            import random
+		 *            n_tok = 0
+		 *            while True:
+		 *                if random.randint(0, 0xFFFFFFFF) % probability(n_tok) == 0:
+		 *                   return n_tok
+		 *                n_tok += 1
+		 *        hist = []
+		 *        i = 0;
+		 *        while i < n_tries:
+		 *            n_tok = n_tokens()
+		 *            while n_tok >= len(hist):
+		 *                hist.append(0)
+		 *            hist[n_tok] = hist[n_tok] + 1
+		 *            i += 1
+		 *        if scale is not None:
+		 *            hist = list([round(x / n_tries * scale) for x in hist])
+		 *        return hist
+		 *
+		 * For example, random_histogram(n_tries = 1000000, scale = 1000) may give
+		 *
+		 *   IDX:  [ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
+		 *   SEEN: [20, 39, 59, 73, 80, 91, 92, 90, 91, 73, 73, 54, 55, 36, 24, 16, 16,  8,  4,  2,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0]
+		 *
+		 * which give a sense of the probability with this individual results are returned.
+		 */
+		probability = NM_MAX (2u, (100u / (2u * (n + 1u))));
+		if ((rnd % probability) == 0)
+			return n;
+		n++;
+	}
+}
+
+/*****************************************************************************/
+
+static inline gboolean
+nmtst_g_source_assert_not_called (gpointer user_data)
+{
+	g_assert_not_reached ();
+	return G_SOURCE_CONTINUE;
+}
+
+static inline gboolean
+nmtst_g_source_set_boolean_true (gpointer user_data)
+{
+	gboolean *ptr = user_data;
+
+	g_assert (ptr);
+	g_assert (!*ptr);
+	*ptr = TRUE;
+	return G_SOURCE_CONTINUE;
+}
+
+/*****************************************************************************/
+
 static inline gboolean
 _nmtst_main_loop_run_timeout (gpointer user_data)
 {
@@ -978,13 +1080,13 @@ _nmtst_main_loop_run_timeout (gpointer user_data)
 }
 
 static inline gboolean
-nmtst_main_loop_run (GMainLoop *loop, guint timeout_ms)
+nmtst_main_loop_run (GMainLoop *loop, guint timeout_msec)
 {
 	nm_auto_unref_gsource GSource *source = NULL;
 	GMainLoop *loopx = loop;
 
-	if (timeout_ms > 0) {
-		source = g_timeout_source_new (timeout_ms);
+	if (timeout_msec > 0) {
+		source = g_timeout_source_new (timeout_msec);
 		g_source_set_callback (source, _nmtst_main_loop_run_timeout, &loopx, NULL);
 		g_source_attach (source, g_main_loop_get_context (loop));
 	}
@@ -1010,36 +1112,123 @@ _nmtst_main_loop_quit_on_notify (GObject *object, GParamSpec *pspec, gpointer us
 }
 #define nmtst_main_loop_quit_on_notify ((GCallback) _nmtst_main_loop_quit_on_notify)
 
-static inline gboolean
-_nmtst_main_context_iterate_until_timeout (gpointer user_data)
-{
-	gboolean *p_had_pointer = user_data;
-
-	g_assert (!*p_had_pointer);
-	*p_had_pointer = TRUE;
-	return G_SOURCE_CONTINUE;
-}
-
-#define nmtst_main_context_iterate_until(context, timeout_ms, condition) \
-	G_STMT_START { \
+#define nmtst_main_context_iterate_until(context, timeout_msec, condition) \
+	({ \
 		nm_auto_destroy_and_unref_gsource GSource *_source = NULL; \
 		GMainContext *_context = (context); \
 		gboolean _had_timeout = FALSE; \
 		\
-		_source = g_timeout_source_new (timeout_ms); \
-		g_source_set_callback (_source, _nmtst_main_context_iterate_until_timeout, &_had_timeout, NULL); \
+		_source = g_timeout_source_new (timeout_msec); \
+		g_source_set_callback (_source, nmtst_g_source_set_boolean_true, &_had_timeout, NULL); \
 		g_source_attach (_source, _context); \
 		\
 		while (TRUE) { \
 			if (condition) \
 				break; \
 			g_main_context_iteration (_context, TRUE); \
-			g_assert (!_had_timeout && #condition); \
+			if (_had_timeout) \
+				break; \
 		} \
+		\
+		!_had_timeout; \
+	})
+
+#define nmtst_main_context_iterate_until_assert(context, timeout_msec, condition) \
+	G_STMT_START { \
+		if (!nmtst_main_context_iterate_until (context, timeout_msec, condition)) \
+			g_assert (FALSE && #condition); \
 	} G_STMT_END
 
 /*****************************************************************************/
 
+static inline void
+nmtst_main_context_assert_no_dispatch (GMainContext *context,
+                                       guint timeout_msec)
+{
+	nm_auto_destroy_and_unref_gsource GSource *source = NULL;
+	gboolean timeout_hit = FALSE;
+
+	source = g_timeout_source_new (timeout_msec);
+	g_source_set_callback (source, nmtst_g_source_set_boolean_true, &timeout_hit, NULL);
+	g_source_attach (source, context);
+
+	while (g_main_context_iteration (context, TRUE)) {
+		if (timeout_hit)
+			return;
+		g_assert_not_reached ();
+	}
+}
+
+/*****************************************************************************/
+
+typedef struct {
+	GMainLoop *_main_loop;
+	union {
+		GSList *_list;
+		const void *const is_waiting;
+	};
+} NMTstContextBusyWatcherData;
+
+static inline void
+_nmtst_context_busy_watcher_add_cb (gpointer data,
+                                    GObject *where_the_object_was)
+{
+	NMTstContextBusyWatcherData *watcher_data = data;
+	GSList *l;
+
+	g_assert (watcher_data);
+
+	l = g_slist_find (watcher_data->_list, where_the_object_was);
+	g_assert (l);
+
+	watcher_data->_list = g_slist_delete_link (watcher_data->_list, l);
+	if (!watcher_data->_list)
+		g_main_loop_quit (watcher_data->_main_loop);
+}
+
+static inline void
+nmtst_context_busy_watcher_add (NMTstContextBusyWatcherData *watcher_data,
+                                GObject *object)
+{
+	g_assert (watcher_data);
+	g_assert (G_IS_OBJECT (object));
+
+	if (!watcher_data->_main_loop) {
+		watcher_data->_main_loop = g_main_loop_new (g_main_context_get_thread_default (),
+		                                            FALSE);
+		g_assert (!watcher_data->_list);
+	} else {
+		g_assert (   g_main_loop_get_context (watcher_data->_main_loop)
+		          == (g_main_context_get_thread_default () ?: g_main_context_default ()));
+	}
+
+	g_object_weak_ref (object,
+	                   _nmtst_context_busy_watcher_add_cb,
+	                   watcher_data);
+	watcher_data->_list = g_slist_prepend (watcher_data->_list, object);
+}
+
+static inline void
+nmtst_context_busy_watcher_wait (NMTstContextBusyWatcherData *watcher_data)
+{
+	g_assert (watcher_data);
+
+	if (!watcher_data->_main_loop) {
+		g_assert (!watcher_data->_list);
+		return;
+	}
+
+	if (watcher_data->_list) {
+		if (!nmtst_main_loop_run (watcher_data->_main_loop, 5000))
+			g_error ("timeout running mainloop waiting for GObject to destruct");
+	}
+
+	g_assert (!watcher_data->_list);
+	nm_clear_pointer (&watcher_data->_main_loop, g_main_loop_unref);
+}
+
+/*****************************************************************************/
+
 static inline const char *
 nmtst_get_sudo_cmd (void)
 {
@@ -1156,15 +1345,6 @@ nmtst_uuid_generate (void)
 
 #endif
 
-#define NMTST_SWAP(x, y) \
-	G_STMT_START { \
-		char __nmtst_swap_temp[sizeof((x)) == sizeof((y)) ? (signed) sizeof((x)) : -1]; \
-		\
-		memcpy(__nmtst_swap_temp, &(y),              sizeof (__nmtst_swap_temp)); \
-		memcpy(&(y),              &(x),              sizeof (__nmtst_swap_temp)); \
-		memcpy(&(x),              __nmtst_swap_temp, sizeof (__nmtst_swap_temp)); \
-	} G_STMT_END
-
 #define nmtst_assert_str_has_substr(str, substr) \
 	G_STMT_START { \
 		const char *__str = (str); \
@@ -1362,15 +1542,27 @@ nmtst_file_get_contents (const char *filename)
 	return contents;
 }
 
-#define nmtst_file_set_contents(filename, content) \
+#define nmtst_file_set_contents_size(filename, content, size) \
 	G_STMT_START { \
 		GError *_error = NULL; \
 		gboolean _success; \
+		const char *_content = (content); \
+		gssize _size = (size); \
+		\
+		g_assert (_content); \
 		\
-		_success = g_file_set_contents ((filename), (content), -1, &_error); \
+		if (_size < 0) { \
+			g_assert (_size == -1); \
+			_size = strlen (_content); \
+		} \
+		\
+		_success = g_file_set_contents ((filename), _content, _size, &_error); \
 		nmtst_assert_success (_success, _error); \
 	} G_STMT_END
 
+#define nmtst_file_set_contents(filename, content) \
+	nmtst_file_set_contents_size (filename, content, -1)
+
 /*****************************************************************************/
 
 static inline void
@@ -1478,9 +1670,9 @@ nmtst_setting_ip_config_add_address (NMSettingIPConfig *s_ip,
 
 	g_assert (s_ip);
 
-	if (nm_utils_ipaddr_valid (AF_INET, address))
+	if (nm_utils_ipaddr_is_valid (AF_INET, address))
 		family = AF_INET;
-	else if (nm_utils_ipaddr_valid (AF_INET6, address))
+	else if (nm_utils_ipaddr_is_valid (AF_INET6, address))
 		family = AF_INET6;
 	else
 		g_assert_not_reached ();
@@ -1503,9 +1695,9 @@ nmtst_setting_ip_config_add_route (NMSettingIPConfig *s_ip,
 
 	g_assert (s_ip);
 
-	if (nm_utils_ipaddr_valid (AF_INET, dest))
+	if (nm_utils_ipaddr_is_valid (AF_INET, dest))
 		family = AF_INET;
-	else if (nm_utils_ipaddr_valid (AF_INET6, dest))
+	else if (nm_utils_ipaddr_is_valid (AF_INET6, dest))
 		family = AF_INET6;
 	else
 		g_assert_not_reached ();
@@ -1611,8 +1803,12 @@ nmtst_create_minimal_connection (const char *id, const char *uuid, const char *t
 	con = nm_connection_new ();
 #endif
 
+	g_assert (con);
+
 	s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ());
 
+	g_assert (s_con);
+
 	g_object_set (s_con,
 	              NM_SETTING_CONNECTION_ID, id,
 	              NM_SETTING_CONNECTION_UUID, uuid,
@@ -1959,14 +2155,14 @@ nmtst_assert_setting_is_equal (gconstpointer /* const NMSetting * */ a,
 	g_assert (NM_IS_SETTING (b));
 
 	if (NM_FLAGS_HAS (r, 0x4))
-		NMTST_SWAP (a, b);
+		NM_SWAP (a, b);
 
 	g_assert (nm_setting_compare ((NMSetting *) a,
 	                              (NMSetting *) b,
 	                              flags));
 
 	if (NM_FLAGS_HAS (r, 0x8))
-		NMTST_SWAP (a, b);
+		NM_SWAP (a, b);
 
 	g_assert (nm_setting_diff ((NMSetting *) a,
 	                           (NMSetting *) b,
@@ -2311,13 +2507,4 @@ nmtst_keyfile_get_num_keys (GKeyFile *keyfile,
 
 /*****************************************************************************/
 
-static inline gboolean
-nmtst_g_source_assert_not_called (gpointer user_data)
-{
-	g_assert_not_reached ();
-	return G_SOURCE_CONTINUE;
-}
-
-/*****************************************************************************/
-
 #endif /* __NM_TEST_UTILS_H__ */
diff --git a/shared/nm-utils/nm-vpn-editor-plugin-call.h b/shared/nm-utils/nm-vpn-editor-plugin-call.h
index ab473083..b2c39e29 100644
--- a/shared/nm-utils/nm-vpn-editor-plugin-call.h
+++ b/shared/nm-utils/nm-vpn-editor-plugin-call.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+// SPDX-License-Identifier: LGPL-2.1+
 /*
  * Copyright (C) 2016 Red Hat, Inc.
  */
diff --git a/shared/nm-utils/tests/meson.build b/shared/nm-utils/tests/meson.build
deleted file mode 100644
index 1ee5efff..00000000
--- a/shared/nm-utils/tests/meson.build
+++ /dev/null
@@ -1,21 +0,0 @@
-test_unit = 'test-shared-general'
-
-c_flags = [
-  '-DNETWORKMANAGER_COMPILATION_TEST',
-  '-DNETWORKMANAGER_COMPILATION=(NM_NETWORKMANAGER_COMPILATION_GLIB|NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_PROG)',
-]
-
-exe = executable(
-  test_unit,
-  test_unit + '.c',
-  c_args: c_flags,
-  dependencies: libnm_utils_base_dep,
-  link_with: libnm_systemd_logging_stub,
-)
-
-test(
-  'shared/nm-utils/' + test_unit,
-  test_script,
-  args: test_args + [exe.full_path()],
-  timeout: default_test_timeout,
-)
diff --git a/shared/nm-utils/tests/test-shared-general.c b/shared/nm-utils/tests/test-shared-general.c
deleted file mode 100644
index 34da19b3..00000000
--- a/shared/nm-utils/tests/test-shared-general.c
+++ /dev/null
@@ -1,577 +0,0 @@
-// SPDX-License-Identifier: LGPL-2.1+
-/*
- * Copyright (C) 2018 Red Hat, Inc.
- */
-
-#define NM_TEST_UTILS_NO_LIBNM 1
-
-#include "nm-default.h"
-
-#include "nm-std-aux/unaligned.h"
-#include "nm-glib-aux/nm-random-utils.h"
-#include "nm-glib-aux/nm-time-utils.h"
-#include "nm-glib-aux/nm-ref-string.h"
-
-#include "nm-utils/nm-test-utils.h"
-
-/*****************************************************************************/
-
-static void
-test_gpid (void)
-{
-	const int *int_ptr;
-	GPid pid = 42;
-
-	/* We redefine G_PID_FORMAT, because it's only available since glib 2.53.5.
-	 *
-	 * Also, this is the format for GPid, which for glib is always a typedef
-	 * for "int". Add a check for that here.
-	 *
-	 * G_PID_FORMAT is not about pid_t, which might be a smaller int, and which we would
-	 * check with SIZEOF_PID_T. */
-	G_STATIC_ASSERT (sizeof (GPid) == sizeof (int));
-
-	g_assert_cmpstr (""G_PID_FORMAT, ==, "i");
-
-	/* check that it's really "int". We will get a compiler warning, if that's not
-	 * the case. */
-	int_ptr = &pid;
-	g_assert_cmpint (*int_ptr, ==, 42);
-}
-
-/*****************************************************************************/
-
-static void
-test_monotonic_timestamp (void)
-{
-	g_assert (nm_utils_get_monotonic_timestamp_s () > 0);
-}
-
-/*****************************************************************************/
-
-static void
-test_nmhash (void)
-{
-	int rnd;
-
-	nm_utils_random_bytes (&rnd, sizeof (rnd));
-
-	g_assert (nm_hash_val (555, 4) != 0);
-}
-
-/*****************************************************************************/
-
-static const char *
-_make_strv_foo (void)
-{
-	return "foo";
-}
-
-static const char *const*const _tst_make_strv_1 = NM_MAKE_STRV ("1", "2");
-
-static void
-test_make_strv (void)
-{
-	const char *const*v1a = NM_MAKE_STRV ("a");
-	const char *const*v1b = NM_MAKE_STRV ("a", );
-	const char *const*v2a = NM_MAKE_STRV ("a", "b");
-	const char *const*v2b = NM_MAKE_STRV ("a", "b", );
-	const char *const v3[] = { "a", "b", };
-	const char *const*v4b = NM_MAKE_STRV ("a", _make_strv_foo (), );
-
-	g_assert (NM_PTRARRAY_LEN (v1a) == 1);
-	g_assert (NM_PTRARRAY_LEN (v1b) == 1);
-	g_assert (NM_PTRARRAY_LEN (v2a) == 2);
-	g_assert (NM_PTRARRAY_LEN (v2b) == 2);
-
-	g_assert (NM_PTRARRAY_LEN (_tst_make_strv_1) == 2);
-	g_assert_cmpstr (_tst_make_strv_1[0], ==, "1");
-	g_assert_cmpstr (_tst_make_strv_1[1], ==, "2");
-	/* writing the static read-only variable leads to crash .*/
-	//((char **) _tst_make_strv_1)[0] = NULL;
-	//((char **) _tst_make_strv_1)[2] = "c";
-
-	G_STATIC_ASSERT_EXPR (G_N_ELEMENTS (v3) == 2);
-
-	g_assert (NM_PTRARRAY_LEN (v4b) == 2);
-
-	G_STATIC_ASSERT_EXPR (G_N_ELEMENTS (NM_MAKE_STRV ("a", "b"  )) == 3);
-	G_STATIC_ASSERT_EXPR (G_N_ELEMENTS (NM_MAKE_STRV ("a", "b", )) == 3);
-
-	nm_strquote_a (300, "");
-}
-
-/*****************************************************************************/
-
-typedef enum {
-	TEST_NM_STRDUP_ENUM_m1 = -1,
-	TEST_NM_STRDUP_ENUM_3  = 3,
-} TestNMStrdupIntEnum;
-
-static void
-test_nm_strdup_int (void)
-{
-#define _NM_STRDUP_INT_TEST(num, str) \
-	G_STMT_START { \
-		gs_free char *_s1 = NULL; \
-		\
-		_s1 = nm_strdup_int ((num)); \
-		\
-		g_assert (_s1); \
-		g_assert_cmpstr (_s1, ==, str); \
-	} G_STMT_END
-
-#define _NM_STRDUP_INT_TEST_TYPED(type, num) \
-	G_STMT_START { \
-		type _num = ((type) num); \
-		\
-		_NM_STRDUP_INT_TEST (_num, G_STRINGIFY (num)); \
-	} G_STMT_END
-
-	_NM_STRDUP_INT_TEST_TYPED (char, 0);
-	_NM_STRDUP_INT_TEST_TYPED (char, 1);
-	_NM_STRDUP_INT_TEST_TYPED (guint8, 0);
-	_NM_STRDUP_INT_TEST_TYPED (gint8, 25);
-	_NM_STRDUP_INT_TEST_TYPED (char, 47);
-	_NM_STRDUP_INT_TEST_TYPED (short, 47);
-	_NM_STRDUP_INT_TEST_TYPED (int, 47);
-	_NM_STRDUP_INT_TEST_TYPED (long, 47);
-	_NM_STRDUP_INT_TEST_TYPED (unsigned char, 47);
-	_NM_STRDUP_INT_TEST_TYPED (unsigned short, 47);
-	_NM_STRDUP_INT_TEST_TYPED (unsigned, 47);
-	_NM_STRDUP_INT_TEST_TYPED (unsigned long, 47);
-	_NM_STRDUP_INT_TEST_TYPED (gint64, 9223372036854775807);
-	_NM_STRDUP_INT_TEST_TYPED (gint64, -9223372036854775807);
-	_NM_STRDUP_INT_TEST_TYPED (guint64, 0);
-	_NM_STRDUP_INT_TEST_TYPED (guint64, 9223372036854775807);
-
-	_NM_STRDUP_INT_TEST (TEST_NM_STRDUP_ENUM_m1, "-1");
-	_NM_STRDUP_INT_TEST (TEST_NM_STRDUP_ENUM_3,  "3");
-}
-
-/*****************************************************************************/
-
-static void
-test_nm_strndup_a (void)
-{
-	int run;
-
-	for (run = 0; run < 20; run++) {
-		gs_free char *input = NULL;
-		char ch;
-		gsize i, l;
-
-		input = g_strnfill (nmtst_get_rand_uint32 () % 20, 'x');
-
-		for (i = 0; input[i]; i++) {
-			while ((ch = ((char) nmtst_get_rand_uint32 ())) == '\0') {
-				/* repeat. */
-			}
-			input[i] = ch;
-		}
-
-		{
-			gs_free char *dup_free = NULL;
-			const char *dup;
-
-			l = strlen (input) + 1;
-			dup = nm_strndup_a (10, input, l - 1, &dup_free);
-			g_assert_cmpstr (dup, ==, input);
-			if (strlen (dup) < 10)
-				g_assert (!dup_free);
-			else
-				g_assert (dup == dup_free);
-		}
-
-		{
-			gs_free char *dup_free = NULL;
-			const char *dup;
-
-			l = nmtst_get_rand_uint32 () % 23;
-			dup = nm_strndup_a (10, input, l, &dup_free);
-			g_assert (strncmp (dup, input, l) == 0);
-			g_assert (strlen (dup) <= l);
-			if (l < 10)
-				g_assert (!dup_free);
-			else
-				g_assert (dup == dup_free);
-			if (strlen (input) < l)
-				g_assert (nm_utils_memeqzero (&dup[strlen (input)], l - strlen (input)));
-		}
-	}
-}
-
-/*****************************************************************************/
-
-static void
-test_nm_ip4_addr_is_localhost (void)
-{
-	g_assert ( nm_ip4_addr_is_localhost (nmtst_inet4_from_string ("127.0.0.0")));
-	g_assert ( nm_ip4_addr_is_localhost (nmtst_inet4_from_string ("127.0.0.1")));
-	g_assert ( nm_ip4_addr_is_localhost (nmtst_inet4_from_string ("127.5.0.1")));
-	g_assert (!nm_ip4_addr_is_localhost (nmtst_inet4_from_string ("126.5.0.1")));
-	g_assert (!nm_ip4_addr_is_localhost (nmtst_inet4_from_string ("128.5.0.1")));
-	g_assert (!nm_ip4_addr_is_localhost (nmtst_inet4_from_string ("129.5.0.1")));
-}
-
-/*****************************************************************************/
-
-static void
-test_unaligned (void)
-{
-	int shift;
-
-	for (shift = 0; shift <= 32; shift++) {
-		guint8 buf[100] = { };
-		guint8 val = 0;
-
-		while (val == 0)
-			val = nmtst_get_rand_uint32 () % 256;
-
-		buf[shift] = val;
-
-		g_assert_cmpint (unaligned_read_le64 (&buf[shift]), ==, (guint64) val);
-		g_assert_cmpint (unaligned_read_be64 (&buf[shift]), ==, ((guint64) val) << 56);
-		g_assert_cmpint (unaligned_read_ne64 (&buf[shift]), !=, 0);
-
-		g_assert_cmpint (unaligned_read_le32 (&buf[shift]), ==, (guint32) val);
-		g_assert_cmpint (unaligned_read_be32 (&buf[shift]), ==, ((guint32) val) << 24);
-		g_assert_cmpint (unaligned_read_ne32 (&buf[shift]), !=, 0);
-
-		g_assert_cmpint (unaligned_read_le16 (&buf[shift]), ==, (guint16) val);
-		g_assert_cmpint (unaligned_read_be16 (&buf[shift]), ==, ((guint16) val) << 8);
-		g_assert_cmpint (unaligned_read_ne16 (&buf[shift]), !=, 0);
-	}
-}
-
-/*****************************************************************************/
-
-static void
-_strv_cmp_fuzz_input (const char *const*in,
-                      gssize l,
-                      const char ***out_strv_free_shallow,
-                      char ***out_strv_free_deep,
-                      const char *const* *out_s1,
-                      const char *const* *out_s2)
-{
-	const char **strv;
-	gsize i;
-
-	/* Fuzz the input argument. It will return two output arrays that are semantically
-	 * equal the input. */
-
-	if (nmtst_get_rand_bool ()) {
-		char **ss;
-
-		if (l < 0)
-			ss = g_strdupv ((char **) in);
-		else if (l == 0) {
-			ss =   nmtst_get_rand_bool ()
-			     ? NULL
-			     : g_new0 (char *, 1);
-		} else {
-			ss = nm_memdup (in, sizeof (const char *) * l);
-			for (i = 0; i < (gsize) l; i++)
-				ss[i] = g_strdup (ss[i]);
-		}
-		strv = (const char **) ss;
-		*out_strv_free_deep = ss;
-	} else {
-		if (l < 0) {
-			strv =   in
-			       ? nm_memdup (in, sizeof (const char *) * (NM_PTRARRAY_LEN (in) + 1))
-			       : NULL;
-		} else if (l == 0) {
-			strv =   nmtst_get_rand_bool ()
-			       ? NULL
-			       : g_new0 (const char *, 1);
-		} else
-			strv = nm_memdup (in, sizeof (const char *) * l);
-		*out_strv_free_shallow = strv;
-	}
-
-	*out_s1 = in;
-	*out_s2 = strv;
-
-	if (nmtst_get_rand_bool ()) {
-		/* randomly swap the original and the clone. That means, out_s1 is either
-		 * the input argument (as-is) or the sementically equal clone. */
-		NMTST_SWAP (*out_s1, *out_s2);
-	}
-	if (nmtst_get_rand_bool ()) {
-		/* randomly make s1 and s2 the same. This is for testing that
-		 * comparing two identical pointers yields the same result. */
-		*out_s2 = *out_s1;
-	}
-}
-
-static void
-_strv_cmp_free_deep (char **strv,
-                     gssize len)
-{
-	gssize i;
-
-	if (strv) {
-		if (len < 0)
-			g_strfreev (strv);
-		else {
-			for (i = 0; i < len; i++)
-				g_free (strv[i]);
-			g_free (strv);
-		}
-	}
-}
-
-static void
-test_strv_cmp (void)
-{
-	const char *const strv0[1] = { };
-	const char *const strv1[2] = { "", };
-
-#define _STRV_CMP(a1, l1, a2, l2, equal) \
-	G_STMT_START { \
-		gssize _l1 = (l1); \
-		gssize _l2 = (l2); \
-		const char *const*_a1; \
-		const char *const*_a2; \
-		const char *const*_a1x; \
-		const char *const*_a2x; \
-		char **_a1_free_deep = NULL; \
-		char **_a2_free_deep = NULL; \
-		gs_free const char **_a1_free_shallow = NULL; \
-		gs_free const char **_a2_free_shallow = NULL; \
-		int _c1, _c2; \
-		\
-		_strv_cmp_fuzz_input ((a1), _l1, &_a1_free_shallow, &_a1_free_deep, &_a1, &_a1x); \
-		_strv_cmp_fuzz_input ((a2), _l2, &_a2_free_shallow, &_a2_free_deep, &_a2, &_a2x); \
-		\
-		_c1 = _nm_utils_strv_cmp_n (_a1, _l1, _a2, _l2); \
-		_c2 = _nm_utils_strv_cmp_n (_a2, _l2, _a1, _l1); \
-		if (equal) { \
-			g_assert_cmpint (_c1, ==, 0); \
-			g_assert_cmpint (_c2, ==, 0); \
-		} else { \
-			g_assert_cmpint (_c1, ==, -1); \
-			g_assert_cmpint (_c2, ==, 1); \
-		} \
-		\
-		/* Compare with self. _strv_cmp_fuzz_input() randomly swapped the arguments (_a1 and _a1x).
-		 * Either way, the arrays must compare equal to their semantically equal alternative. */ \
-		g_assert_cmpint (_nm_utils_strv_cmp_n (_a1, _l1, _a1x, _l1), ==, 0); \
-		g_assert_cmpint (_nm_utils_strv_cmp_n (_a2, _l2, _a2x, _l2), ==, 0); \
-		\
-		_strv_cmp_free_deep (_a1_free_deep, _l1); \
-		_strv_cmp_free_deep (_a2_free_deep, _l2); \
-	} G_STMT_END
-
-	_STRV_CMP (NULL,  -1, NULL,  -1, TRUE);
-
-	_STRV_CMP (NULL,  -1, NULL,   0, FALSE);
-	_STRV_CMP (NULL,  -1, strv0,  0, FALSE);
-	_STRV_CMP (NULL,  -1, strv0, -1, FALSE);
-
-	_STRV_CMP (NULL,   0, NULL,   0, TRUE);
-	_STRV_CMP (NULL,   0, strv0,  0, TRUE);
-	_STRV_CMP (NULL,   0, strv0, -1, TRUE);
-	_STRV_CMP (strv0,  0, strv0,  0, TRUE);
-	_STRV_CMP (strv0,  0, strv0, -1, TRUE);
-	_STRV_CMP (strv0, -1, strv0, -1, TRUE);
-
-	_STRV_CMP (NULL,   0, strv1, -1, FALSE);
-	_STRV_CMP (NULL,   0, strv1,  1, FALSE);
-	_STRV_CMP (strv0,  0, strv1, -1, FALSE);
-	_STRV_CMP (strv0,  0, strv1,  1, FALSE);
-	_STRV_CMP (strv0, -1, strv1, -1, FALSE);
-	_STRV_CMP (strv0, -1, strv1,  1, FALSE);
-
-	_STRV_CMP (strv1, -1, strv1,  1, TRUE);
-	_STRV_CMP (strv1,  1, strv1,  1, TRUE);
-}
-
-/*****************************************************************************/
-
-static void
-_do_strstrip_avoid_copy (const char *str)
-{
-	gs_free char *str1 = g_strdup (str);
-	gs_free char *str2 = g_strdup (str);
-	gs_free char *str3 = NULL;
-	gs_free char *str4 = NULL;
-	const char *s3;
-	const char *s4;
-
-	if (str1)
-		g_strstrip (str1);
-
-	nm_strstrip (str2);
-
-	g_assert_cmpstr (str1, ==, str2);
-
-	s3 = nm_strstrip_avoid_copy (str, &str3);
-	g_assert_cmpstr (str1, ==, s3);
-
-	s4 = nm_strstrip_avoid_copy_a (10, str, &str4);
-	g_assert_cmpstr (str1, ==, s4);
-	g_assert (!str == !s4);
-	g_assert (!s4 || strlen (s4) <= strlen (str));
-	if (s4 && s4 == &str[strlen (str) - strlen (s4)]) {
-		g_assert (!str4);
-		g_assert (s3 == s4);
-	} else if (s4 && strlen (s4) >= 10) {
-		g_assert (str4);
-		g_assert (s4 == str4);
-	} else
-		g_assert (!str4);
-
-	if (!nm_streq0 (str1, str))
-		_do_strstrip_avoid_copy (str1);
-}
-
-static void
-test_strstrip_avoid_copy (void)
-{
-	_do_strstrip_avoid_copy (NULL);
-	_do_strstrip_avoid_copy ("");
-	_do_strstrip_avoid_copy (" ");
-	_do_strstrip_avoid_copy (" a ");
-	_do_strstrip_avoid_copy (" 012345678 ");
-	_do_strstrip_avoid_copy (" 0123456789 ");
-	_do_strstrip_avoid_copy (" 01234567890 ");
-	_do_strstrip_avoid_copy (" 012345678901 ");
-}
-
-/*****************************************************************************/
-
-static void
-test_nm_utils_bin2hexstr (void)
-{
-	int n_run;
-
-	for (n_run = 0; n_run < 100; n_run++) {
-		guint8 buf[100];
-		guint8 buf2[G_N_ELEMENTS (buf) + 1];
-		gsize len = nmtst_get_rand_uint32 () % (G_N_ELEMENTS (buf) + 1);
-		char strbuf1[G_N_ELEMENTS (buf) * 3];
-		gboolean allocate = nmtst_get_rand_bool ();
-		char delimiter = nmtst_get_rand_bool () ? ':' : '\0';
-		gboolean upper_case = nmtst_get_rand_bool ();
-		gsize expected_strlen;
-		char *str_hex;
-		gsize required_len;
-		gboolean outlen_set;
-		gsize outlen;
-		guint8 *bin2;
-
-		nmtst_rand_buf (NULL, buf, len);
-
-		if (len == 0)
-			expected_strlen = 0;
-		else if (delimiter != '\0')
-			expected_strlen = (len * 3u) - 1;
-		else
-			expected_strlen = len * 2u;
-
-		g_assert_cmpint (expected_strlen, <, G_N_ELEMENTS (strbuf1));
-
-		str_hex = nm_utils_bin2hexstr_full (buf, len, delimiter, upper_case, !allocate ? strbuf1 : NULL);
-
-		g_assert (str_hex);
-		if (!allocate)
-			g_assert (str_hex == strbuf1);
-		g_assert_cmpint (strlen (str_hex), ==, expected_strlen);
-
-		g_assert (NM_STRCHAR_ALL (str_hex, ch,    (ch >= '0' && ch <= '9')
-		                                       || ch == delimiter
-		                                       || (  upper_case
-		                                           ? (ch >= 'A' && ch <= 'F')
-		                                           : (ch >= 'a' && ch <= 'f'))));
-
-		required_len = nmtst_get_rand_bool () ? len : 0u;
-
-		outlen_set = required_len == 0 || nmtst_get_rand_bool ();
-
-		memset (buf2, 0, sizeof (buf2));
-
-		bin2 = nm_utils_hexstr2bin_full (str_hex,
-		                                 nmtst_get_rand_bool (),
-		                                 delimiter != '\0' && nmtst_get_rand_bool (),
-		                                   delimiter != '\0'
-		                                 ? nmtst_rand_select ((const char *) ":", ":-")
-		                                 : nmtst_rand_select ((const char *) ":", ":-", "", NULL),
-		                                 required_len,
-		                                 buf2,
-		                                 len,
-		                                 outlen_set ? &outlen : NULL);
-		if (len > 0) {
-			g_assert (bin2);
-			g_assert (bin2 == buf2);
-		} else
-			g_assert (!bin2);
-
-		if (outlen_set)
-			g_assert_cmpint (outlen, ==, len);
-
-		g_assert_cmpmem (buf, len, buf2, len);
-
-		g_assert (buf2[len] == '\0');
-
-		if (allocate)
-			g_free (str_hex);
-	}
-}
-
-/*****************************************************************************/
-
-static void
-test_nm_ref_string (void)
-{
-	nm_auto_ref_string NMRefString *s1 = NULL;
-	NMRefString *s2;
-
-	s1 = nm_ref_string_new ("hallo");
-	g_assert (s1);
-	g_assert_cmpstr (s1->str, ==, "hallo");
-	g_assert_cmpint (s1->len, ==, strlen ("hallo"));
-
-	s2 = nm_ref_string_new ("hallo");
-	g_assert (s2 == s1);
-	nm_ref_string_unref (s2);
-
-	s2 = nm_ref_string_new (NULL);
-	g_assert (!s2);
-	nm_ref_string_unref (s2);
-
-#define STR_WITH_NUL "hallo\0test\0"
-	s2 = nm_ref_string_new_len (STR_WITH_NUL, NM_STRLEN (STR_WITH_NUL));
-	g_assert (s2);
-	g_assert_cmpstr (s2->str, ==, "hallo");
-	g_assert_cmpint (s2->len, ==, NM_STRLEN (STR_WITH_NUL));
-	g_assert_cmpint (s2->len, >, strlen (s2->str));
-	g_assert_cmpmem (s2->str, s2->len, STR_WITH_NUL, NM_STRLEN (STR_WITH_NUL));
-	g_assert (s2->str[s2->len] == '\0');
-	nm_ref_string_unref (s2);
-}
-
-/*****************************************************************************/
-
-NMTST_DEFINE ();
-
-int main (int argc, char **argv)
-{
-	nmtst_init (&argc, &argv, TRUE);
-
-	g_test_add_func ("/general/test_gpid", test_gpid);
-	g_test_add_func ("/general/test_monotonic_timestamp", test_monotonic_timestamp);
-	g_test_add_func ("/general/test_nmhash", test_nmhash);
-	g_test_add_func ("/general/test_nm_make_strv", test_make_strv);
-	g_test_add_func ("/general/test_nm_strdup_int", test_nm_strdup_int);
-	g_test_add_func ("/general/test_nm_strndup_a", test_nm_strndup_a);
-	g_test_add_func ("/general/test_nm_ip4_addr_is_localhost", test_nm_ip4_addr_is_localhost);
-	g_test_add_func ("/general/test_unaligned", test_unaligned);
-	g_test_add_func ("/general/test_strv_cmp", test_strv_cmp);
-	g_test_add_func ("/general/test_strstrip_avoid_copy", test_strstrip_avoid_copy);
-	g_test_add_func ("/general/test_nm_utils_bin2hexstr", test_nm_utils_bin2hexstr);
-	g_test_add_func ("/general/test_nm_ref_string", test_nm_ref_string);
-
-	return g_test_run ();
-}