about summary refs log tree commit diff
path: root/shared/nm-glib-aux/tests
diff options
context:
space:
mode:
Diffstat (limited to 'shared/nm-glib-aux/tests')
-rw-r--r--shared/nm-glib-aux/tests/meson.build42
-rw-r--r--shared/nm-glib-aux/tests/test-json-aux.c167
-rw-r--r--shared/nm-glib-aux/tests/test-shared-general.c1774
3 files changed, 1322 insertions, 661 deletions
diff --git a/shared/nm-glib-aux/tests/meson.build b/shared/nm-glib-aux/tests/meson.build
index f6328db9..8136eff9 100644
--- a/shared/nm-glib-aux/tests/meson.build
+++ b/shared/nm-glib-aux/tests/meson.build
@@ -1,23 +1,43 @@
 # SPDX-License-Identifier: LGPL-2.1+
 
-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,
+  'test-shared-general',
+  'test-shared-general.c',
+  c_args: [
+    '-DNETWORKMANAGER_COMPILATION_TEST',
+    '-DNETWORKMANAGER_COMPILATION=(NM_NETWORKMANAGER_COMPILATION_GLIB|NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_PROG)',
+  ],
   dependencies: libnm_utils_base_dep,
   link_with: libnm_systemd_logging_stub,
 )
 
 test(
-  'shared/nm-glib-aux/' + test_unit,
+  'shared/nm-glib-aux/test-shared-general',
   test_script,
   args: test_args + [exe.full_path()],
   timeout: default_test_timeout,
 )
+
+if jansson_dep.found()
+  exe = executable(
+    'test-json-aux',
+    'test-json-aux.c',
+    c_args: [
+      '-DNETWORKMANAGER_COMPILATION_TEST',
+      '-DNETWORKMANAGER_COMPILATION=(NM_NETWORKMANAGER_COMPILATION_GLIB|NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_PROG)',
+    ],
+    dependencies: [
+      libnm_utils_base_dep,
+      jansson_dep,
+      dl_dep,
+    ],
+    link_with: libnm_systemd_logging_stub,
+  )
+
+  test(
+    'shared/nm-glib-aux/test-json-aux',
+    test_script,
+    args: test_args + [exe.full_path()],
+    timeout: default_test_timeout,
+  )
+endif
diff --git a/shared/nm-glib-aux/tests/test-json-aux.c b/shared/nm-glib-aux/tests/test-json-aux.c
new file mode 100644
index 00000000..5331c015
--- /dev/null
+++ b/shared/nm-glib-aux/tests/test-json-aux.c
@@ -0,0 +1,167 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#define NM_TEST_UTILS_NO_LIBNM 1
+
+#include "nm-default.h"
+
+#include <jansson.h>
+
+#include "nm-glib-aux/nm-json-aux.h"
+
+#include "nm-utils/nm-test-utils.h"
+
+/*****************************************************************************/
+
+static void
+test_jansson(void)
+{
+    const NMJsonVt *    vt;
+    nm_auto_decref_json nm_json_t *js1 = NULL;
+    nm_auto_decref_json nm_json_t *js2 = NULL;
+
+#define _ASSERT_FIELD(type1, type2, field)                                                        \
+    G_STMT_START                                                                                  \
+    {                                                                                             \
+        G_STATIC_ASSERT_EXPR(sizeof(((type1 *) NULL)->field) == sizeof(((type2 *) NULL)->field)); \
+        G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(type1, field) == G_STRUCT_OFFSET(type2, field));     \
+    }                                                                                             \
+    G_STMT_END
+
+    G_STATIC_ASSERT_EXPR(NM_JSON_REJECT_DUPLICATES == JSON_REJECT_DUPLICATES);
+
+    G_STATIC_ASSERT_EXPR(sizeof(nm_json_type) == sizeof(json_type));
+
+    G_STATIC_ASSERT_EXPR((int) NM_JSON_OBJECT == JSON_OBJECT);
+    G_STATIC_ASSERT_EXPR((int) NM_JSON_ARRAY == JSON_ARRAY);
+    G_STATIC_ASSERT_EXPR((int) NM_JSON_STRING == JSON_STRING);
+    G_STATIC_ASSERT_EXPR((int) NM_JSON_INTEGER == JSON_INTEGER);
+    G_STATIC_ASSERT_EXPR((int) NM_JSON_REAL == JSON_REAL);
+    G_STATIC_ASSERT_EXPR((int) NM_JSON_TRUE == JSON_TRUE);
+    G_STATIC_ASSERT_EXPR((int) NM_JSON_FALSE == JSON_FALSE);
+    G_STATIC_ASSERT_EXPR((int) NM_JSON_NULL == JSON_NULL);
+
+    G_STATIC_ASSERT_EXPR(sizeof(nm_json_int_t) == sizeof(json_int_t));
+
+    G_STATIC_ASSERT_EXPR(sizeof(nm_json_t) == sizeof(json_t));
+    _ASSERT_FIELD(nm_json_t, json_t, refcount);
+    _ASSERT_FIELD(nm_json_t, json_t, type);
+
+    G_STATIC_ASSERT_EXPR(NM_JSON_ERROR_TEXT_LENGTH == JSON_ERROR_TEXT_LENGTH);
+    G_STATIC_ASSERT_EXPR(NM_JSON_ERROR_SOURCE_LENGTH == JSON_ERROR_SOURCE_LENGTH);
+
+    G_STATIC_ASSERT_EXPR(sizeof(nm_json_error_t) == sizeof(json_error_t));
+    _ASSERT_FIELD(nm_json_error_t, json_error_t, line);
+    _ASSERT_FIELD(nm_json_error_t, json_error_t, column);
+    _ASSERT_FIELD(nm_json_error_t, json_error_t, position);
+    _ASSERT_FIELD(nm_json_error_t, json_error_t, source);
+    _ASSERT_FIELD(nm_json_error_t, json_error_t, text);
+
+    vt = nm_json_vt();
+
+    g_assert(vt);
+    g_assert(vt->loaded);
+
+    js1 = vt->nm_json_loads("{ \"a\": 5 }", 0, NULL);
+    g_assert(js1);
+    nm_json_decref(vt, g_steal_pointer(&js1));
+
+    js2 = vt->nm_json_loads("{ \"a\": 6 }", 0, NULL);
+    g_assert(js2);
+
+#define CHECK_FCN(vt, fcn, nm_type, js_type)             \
+    G_STMT_START                                         \
+    {                                                    \
+        const NMJsonVt *const _vt     = (vt);            \
+        _nm_unused            nm_type = (_vt->nm_##fcn); \
+        _nm_unused            js_type = (fcn);           \
+                                                         \
+        g_assert(_vt->nm_##fcn);                         \
+        g_assert(_f_nm);                                 \
+        g_assert(_f_js);                                 \
+        g_assert(_f_nm == _vt->nm_##fcn);                \
+    }                                                    \
+    G_STMT_END
+
+    CHECK_FCN(vt, json_array, nm_json_t * (*_f_nm)(void), json_t * (*_f_js)(void) );
+    CHECK_FCN(vt,
+              json_array_append_new,
+              int (*_f_nm)(nm_json_t *, nm_json_t *),
+              int (*_f_js)(json_t *, json_t *));
+    CHECK_FCN(vt,
+              json_array_get,
+              nm_json_t * (*_f_nm)(const nm_json_t *, gsize),
+              json_t * (*_f_js)(const json_t *, size_t));
+    CHECK_FCN(vt,
+              json_array_size,
+              gsize(*_f_nm)(const nm_json_t *),
+              size_t(*_f_js)(const json_t *));
+    CHECK_FCN(vt, json_delete, void (*_f_nm)(nm_json_t *), void (*_f_js)(json_t *));
+    CHECK_FCN(vt,
+              json_dumps,
+              char *(*_f_nm)(const nm_json_t *, gsize),
+              char *(*_f_js)(const json_t *, size_t));
+    CHECK_FCN(vt, json_false, nm_json_t * (*_f_nm)(void), json_t * (*_f_js)(void) );
+    CHECK_FCN(vt, json_integer, nm_json_t * (*_f_nm)(nm_json_int_t), json_t * (*_f_js)(json_int_t));
+    CHECK_FCN(vt,
+              json_integer_value,
+              nm_json_int_t(*_f_nm)(const nm_json_t *),
+              json_int_t(*_f_js)(const json_t *));
+    CHECK_FCN(vt,
+              json_loads,
+              nm_json_t * (*_f_nm)(const char *, gsize, nm_json_error_t *),
+              json_t * (*_f_js)(const char *, size_t, json_error_t *) );
+    CHECK_FCN(vt, json_object, nm_json_t * (*_f_nm)(void), json_t * (*_f_js)(void) );
+    CHECK_FCN(vt,
+              json_object_del,
+              int (*_f_nm)(nm_json_t *, const char *),
+              int (*_f_js)(json_t *, const char *));
+    CHECK_FCN(vt,
+              json_object_get,
+              nm_json_t * (*_f_nm)(const nm_json_t *, const char *),
+              json_t * (*_f_js)(const json_t *, const char *) );
+    CHECK_FCN(vt, json_object_iter, void *(*_f_nm)(nm_json_t *), void *(*_f_js)(json_t *) );
+    CHECK_FCN(vt,
+              json_object_iter_key,
+              const char *(*_f_nm)(void *),
+              const char *(*_f_js)(void *) );
+    CHECK_FCN(vt,
+              json_object_iter_next,
+              void *(*_f_nm)(nm_json_t *, void *),
+              void *(*_f_js)(json_t *, void *) );
+    CHECK_FCN(vt, json_object_iter_value, nm_json_t * (*_f_nm)(void *), json_t * (*_f_js)(void *) );
+    CHECK_FCN(vt,
+              json_object_key_to_iter,
+              void *(*_f_nm)(const char *),
+              void *(*_f_js)(const char *) );
+    CHECK_FCN(vt,
+              json_object_set_new,
+              int (*_f_nm)(nm_json_t *, const char *, nm_json_t *),
+              int (*_f_js)(json_t *, const char *, json_t *));
+    CHECK_FCN(vt,
+              json_object_size,
+              gsize(*_f_nm)(const nm_json_t *),
+              size_t(*_f_js)(const json_t *));
+    CHECK_FCN(vt,
+              json_string,
+              nm_json_t * (*_f_nm)(const char *),
+              json_t * (*_f_js)(const char *) );
+    CHECK_FCN(vt,
+              json_string_value,
+              const char *(*_f_nm)(const nm_json_t *),
+              const char *(*_f_js)(const json_t *) );
+    CHECK_FCN(vt, json_true, nm_json_t * (*_f_nm)(void), json_t * (*_f_js)(void) );
+}
+
+/*****************************************************************************/
+
+NMTST_DEFINE();
+
+int
+main(int argc, char **argv)
+{
+    nmtst_init(&argc, &argv, TRUE);
+
+    g_test_add_func("/general/test_jansson", test_jansson);
+
+    return g_test_run();
+}
diff --git a/shared/nm-glib-aux/tests/test-shared-general.c b/shared/nm-glib-aux/tests/test-shared-general.c
index 5c8bdf18..84e0a6f0 100644
--- a/shared/nm-glib-aux/tests/test-shared-general.c
+++ b/shared/nm-glib-aux/tests/test-shared-general.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: LGPL-2.1+
+/* SPDX-License-Identifier: LGPL-2.1+ */
 /*
  * Copyright (C) 2018 Red Hat, Inc.
  */
@@ -17,781 +17,1255 @@
 
 /*****************************************************************************/
 
+G_STATIC_ASSERT(NM_AF_UNSPEC == AF_UNSPEC);
+G_STATIC_ASSERT(NM_AF_INET == AF_INET);
+G_STATIC_ASSERT(NM_AF_INET6 == AF_INET6);
+
+G_STATIC_ASSERT(NM_AF_INET_SIZE == sizeof(in_addr_t));
+G_STATIC_ASSERT(NM_AF_INET_SIZE == sizeof(struct in_addr));
+G_STATIC_ASSERT(NM_AF_INET6_SIZE == sizeof(struct in6_addr));
+
+G_STATIC_ASSERT(4 == _nm_alignof(in_addr_t));
+G_STATIC_ASSERT(4 == _nm_alignof(struct in_addr));
+G_STATIC_ASSERT(4 == _nm_alignof(struct in6_addr));
+G_STATIC_ASSERT(4 == _nm_alignof(NMIPAddr));
+
+/*****************************************************************************/
+
 static void
-test_gpid (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);
+    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)
+test_monotonic_timestamp(void)
 {
-	g_assert (nm_utils_get_monotonic_timestamp_sec () > 0);
+    g_assert(nm_utils_get_monotonic_timestamp_sec() > 0);
 }
 
 /*****************************************************************************/
 
 static void
-test_nmhash (void)
+test_nmhash(void)
 {
-	int rnd;
+    int rnd;
 
-	nm_utils_random_bytes (&rnd, sizeof (rnd));
+    nm_utils_random_bytes(&rnd, sizeof(rnd));
 
-	g_assert (nm_hash_val (555, 4) != 0);
+    g_assert(nm_hash_val(555, 4) != 0);
 }
 
 /*****************************************************************************/
 
 static const char *
-_make_strv_foo (void)
+_make_strv_foo(void)
 {
-	return "foo";
+    return "foo";
 }
 
-static const char *const*const _tst_make_strv_1 = NM_MAKE_STRV ("1", "2");
+static const char *const *const _tst_make_strv_1 = NM_MAKE_STRV("1", "2");
 
 static void
-test_make_strv (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, "");
+    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,
+    TEST_NM_STRDUP_ENUM_m1 = -1,
+    TEST_NM_STRDUP_ENUM_3  = 3,
 } TestNMStrdupIntEnum;
 
 static void
-test_nm_strdup_int (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");
+#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)
+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)));
-		}
-	}
+    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)
+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")));
+    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)
+test_unaligned(void)
 {
-	int shift;
+    int shift;
 
-	for (shift = 0; shift <= 32; shift++) {
-		guint8 buf[100] = { };
-		guint8 val = 0;
+    for (shift = 0; shift <= 32; shift++) {
+        guint8 buf[100] = {};
+        guint8 val      = 0;
 
-		while (val == 0)
-			val = nmtst_get_rand_uint32 () % 256;
+        while (val == 0)
+            val = nmtst_get_rand_uint32() % 256;
 
-		buf[shift] = val;
+        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_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_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);
-	}
+        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)
+_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. */
-		NM_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;
-	}
+    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. */
+        NM_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)
+_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);
-		}
-	}
+    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)
+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);
+    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)
+_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);
+    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)
+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 ");
+    _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)
+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);
-	}
+    int n_run;
+
+    for (n_run = 0; n_run < 500; 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();
+        gboolean hexdigit_pairs_mangled;
+        gsize    expected_strlen;
+        char *   str_hex;
+        gsize    required_len;
+        gboolean outlen_set;
+        gsize    outlen;
+        guint8 * bin2;
+        guint    i, j;
+
+        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'))));
+
+        hexdigit_pairs_mangled = FALSE;
+        if (delimiter && len > 1 && nmtst_get_rand_bool()) {
+            /* randomly convert "0?" sequences to single digits, so we can get hexdigit_pairs_required
+             * parameter. */
+            g_assert(strlen(str_hex) >= 5);
+            g_assert(str_hex[2] == delimiter);
+            i = 0;
+            j = 0;
+            for (;;) {
+                g_assert(g_ascii_isxdigit(str_hex[i]));
+                g_assert(g_ascii_isxdigit(str_hex[i + 1]));
+                g_assert(NM_IN_SET(str_hex[i + 2], delimiter, '\0'));
+                if (str_hex[i] == '0' && nmtst_get_rand_bool()) {
+                    i++;
+                    str_hex[j++]           = str_hex[i++];
+                    hexdigit_pairs_mangled = TRUE;
+                } else {
+                    str_hex[j++] = str_hex[i++];
+                    str_hex[j++] = str_hex[i++];
+                }
+                if (str_hex[i] == '\0') {
+                    str_hex[j] = '\0';
+                    break;
+                }
+                g_assert(str_hex[i] == delimiter);
+                str_hex[j++] = str_hex[i++];
+            }
+        }
+
+        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(),
+                                        !hexdigit_pairs_mangled && 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 (hexdigit_pairs_mangled) {
+            /* we mangled the hexstr to contain single digits. Trying to parse with
+             * hexdigit_pairs_required must now fail. */
+            bin2 = nm_utils_hexstr2bin_full(
+                str_hex,
+                nmtst_get_rand_bool(),
+                delimiter != '\0' && nmtst_get_rand_bool(),
+                TRUE,
+                delimiter != '\0' ? nmtst_rand_select((const char *) ":", ":-")
+                                  : nmtst_rand_select((const char *) ":", ":-", "", NULL),
+                required_len,
+                buf2,
+                len,
+                outlen_set ? &outlen : NULL);
+            g_assert(!bin2);
+        }
+
+        if (allocate)
+            g_free(str_hex);
+    }
 }
 
 /*****************************************************************************/
 
 static void
-test_nm_ref_string (void)
+test_nm_ref_string(void)
 {
-	nm_auto_ref_string NMRefString *s1 = NULL;
-	NMRefString *s2;
+    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"));
+    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("hallo");
+    g_assert(s2 == s1);
+    nm_ref_string_unref(s2);
 
-	s2 = nm_ref_string_new (NULL);
-	g_assert (!s2);
-	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);
+    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);
+}
+
+/*****************************************************************************/
+
+static NM_UTILS_STRING_TABLE_LOOKUP_DEFINE(
+    _do_string_table_lookup,
+    int,
+    { ; },
+    { return -1; },
+    {"0", 0},
+    {"1", 1},
+    {"2", 2},
+    {"3", 3}, )
+
+    static void test_string_table_lookup(void)
+{
+    const char *const args[] = {
+        NULL,
+        "0",
+        "1",
+        "2",
+        "3",
+        "x",
+    };
+    int i;
+
+    for (i = 0; i < G_N_ELEMENTS(args); i++) {
+        const char *needle = args[i];
+        const int   val2   = _nm_utils_ascii_str_to_int64(needle, 10, 0, 100, -1);
+        int         val;
+
+        val = _do_string_table_lookup(needle);
+        g_assert_cmpint(val, ==, val2);
+    }
+}
+
+/*****************************************************************************/
+
+static void
+test_nm_utils_get_next_realloc_size(void)
+{
+    static const struct {
+        gsize requested;
+        gsize reserved_true;
+        gsize reserved_false;
+    } test_data[] = {
+        {0, 8, 8},
+        {1, 8, 8},
+        {8, 8, 8},
+        {9, 16, 16},
+        {16, 16, 16},
+        {17, 32, 32},
+        {32, 32, 32},
+        {33, 40, 40},
+        {40, 40, 40},
+        {41, 104, 104},
+        {104, 104, 104},
+        {105, 232, 232},
+        {232, 232, 232},
+        {233, 488, 488},
+        {488, 488, 488},
+        {489, 1000, 1000},
+        {1000, 1000, 1000},
+        {1001, 2024, 2024},
+        {2024, 2024, 2024},
+        {2025, 4072, 4072},
+        {4072, 4072, 4072},
+        {4073, 8168, 8168},
+        {8168, 8168, 8168},
+        {8169, 12264, 16360},
+        {12263, 12264, 16360},
+        {12264, 12264, 16360},
+        {12265, 16360, 16360},
+        {16360, 16360, 16360},
+        {16361, 20456, 32744},
+        {20456, 20456, 32744},
+        {20457, 24552, 32744},
+        {24552, 24552, 32744},
+        {24553, 28648, 32744},
+        {28648, 28648, 32744},
+        {28649, 32744, 32744},
+        {32744, 32744, 32744},
+        {32745, 36840, 65512},
+        {36840, 36840, 65512},
+        {G_MAXSIZE - 0x1000u, G_MAXSIZE, G_MAXSIZE},
+        {G_MAXSIZE - 25u, G_MAXSIZE, G_MAXSIZE},
+        {G_MAXSIZE - 24u, G_MAXSIZE, G_MAXSIZE},
+        {G_MAXSIZE - 1u, G_MAXSIZE, G_MAXSIZE},
+        {G_MAXSIZE, G_MAXSIZE, G_MAXSIZE},
+        {NM_UTILS_GET_NEXT_REALLOC_SIZE_32,
+         NM_UTILS_GET_NEXT_REALLOC_SIZE_32,
+         NM_UTILS_GET_NEXT_REALLOC_SIZE_32},
+        {NM_UTILS_GET_NEXT_REALLOC_SIZE_40,
+         NM_UTILS_GET_NEXT_REALLOC_SIZE_40,
+         NM_UTILS_GET_NEXT_REALLOC_SIZE_40},
+        {NM_UTILS_GET_NEXT_REALLOC_SIZE_104,
+         NM_UTILS_GET_NEXT_REALLOC_SIZE_104,
+         NM_UTILS_GET_NEXT_REALLOC_SIZE_104},
+        {NM_UTILS_GET_NEXT_REALLOC_SIZE_1000,
+         NM_UTILS_GET_NEXT_REALLOC_SIZE_1000,
+         NM_UTILS_GET_NEXT_REALLOC_SIZE_1000},
+    };
+    guint i;
+
+    G_STATIC_ASSERT_EXPR(NM_UTILS_GET_NEXT_REALLOC_SIZE_104 == 104u);
+    G_STATIC_ASSERT_EXPR(NM_UTILS_GET_NEXT_REALLOC_SIZE_1000 == 1000u);
+
+    for (i = 0; i < G_N_ELEMENTS(test_data) + 5000u; i++) {
+        gsize requested0;
+
+        if (i < G_N_ELEMENTS(test_data))
+            requested0 = test_data[i].requested;
+        else {
+            /* find some interesting random values for testing. */
+            switch (nmtst_get_rand_uint32() % 5) {
+            case 0:
+                requested0 = nmtst_get_rand_size();
+                break;
+            case 1:
+                /* values close to G_MAXSIZE. */
+                requested0 = G_MAXSIZE - (nmtst_get_rand_uint32() % 12000u);
+                break;
+            case 2:
+                /* values around G_MAXSIZE/2. */
+                requested0 = (G_MAXSIZE / 2u) + 6000u - (nmtst_get_rand_uint32() % 12000u);
+                break;
+            case 3:
+                /* values around powers of 2. */
+                requested0 = (((gsize) 1) << (nmtst_get_rand_uint32() % (sizeof(gsize) * 8u)))
+                             + 6000u - (nmtst_get_rand_uint32() % 12000u);
+                break;
+            case 4:
+                /* values around 4k borders. */
+                requested0 = (nmtst_get_rand_size() & ~((gsize) 0xFFFu)) + 30u
+                             - (nmtst_get_rand_uint32() % 60u);
+                break;
+            default:
+                g_assert_not_reached();
+            }
+        }
+
+        {
+            const gsize requested      = requested0;
+            const gsize reserved_true  = nm_utils_get_next_realloc_size(TRUE, requested);
+            const gsize reserved_false = nm_utils_get_next_realloc_size(FALSE, requested);
+
+            g_assert_cmpuint(reserved_true, >, 0);
+            g_assert_cmpuint(reserved_false, >, 0);
+            g_assert_cmpuint(reserved_true, >=, requested);
+            g_assert_cmpuint(reserved_false, >=, requested);
+            g_assert_cmpuint(reserved_false, >=, reserved_true);
+
+            if (i < G_N_ELEMENTS(test_data)) {
+                g_assert_cmpuint(reserved_true, ==, test_data[i].reserved_true);
+                g_assert_cmpuint(reserved_false, ==, test_data[i].reserved_false);
+            }
+
+            /* reserved_false is generally the next power of two - 24. */
+            if (reserved_false == G_MAXSIZE)
+                g_assert_cmpuint(requested, >, G_MAXSIZE / 2u - 24u);
+            else {
+                g_assert_cmpuint(reserved_false, <=, G_MAXSIZE - 24u);
+                if (reserved_false >= 40) {
+                    const gsize _pow2 = reserved_false + 24u;
+
+                    /* reserved_false must always be a power of two minus 24. */
+                    g_assert_cmpuint(_pow2, >=, 64u);
+                    g_assert_cmpuint(_pow2, >, requested);
+                    g_assert(nm_utils_is_power_of_two(_pow2));
+
+                    /* but _pow2/2 must also be smaller than what we requested. */
+                    g_assert_cmpuint(_pow2 / 2u - 24u, <, requested);
+                } else {
+                    /* smaller values are hard-coded. */
+                }
+            }
+
+            /* reserved_true is generally the next 4k border - 24. */
+            if (reserved_true == G_MAXSIZE)
+                g_assert_cmpuint(requested, >, G_MAXSIZE - 0x1000u - 24u);
+            else {
+                g_assert_cmpuint(reserved_true, <=, G_MAXSIZE - 24u);
+                if (reserved_true > 8168u) {
+                    const gsize page_border = reserved_true + 24u;
+
+                    /* reserved_true must always be aligned to 4k (minus 24). */
+                    g_assert_cmpuint(page_border % 0x1000u, ==, 0);
+                    if (requested > 0x1000u - 24u) {
+                        /* page_border not be more than 4k above requested. */
+                        g_assert_cmpuint(page_border, >=, 0x1000u - 24u);
+                        g_assert_cmpuint(page_border - 0x1000u - 24u, <, requested);
+                    }
+                } else {
+                    /* for smaller sizes, reserved_true and reserved_false are the same. */
+                    g_assert_cmpuint(reserved_true, ==, reserved_false);
+                }
+            }
+        }
+    }
 }
 
 /*****************************************************************************/
 
-static
-NM_UTILS_STRING_TABLE_LOOKUP_DEFINE (
-	_do_string_table_lookup,
-	int,
-	{ ; },
-	{ return -1; },
-	{ "0", 0 },
-	{ "1", 1 },
-	{ "2", 2 },
-	{ "3", 3 },
-)
+static void
+test_nm_str_buf(void)
+{
+    guint i_run;
+
+    for (i_run = 0; TRUE; i_run++) {
+        nm_auto_str_buf NMStrBuf strbuf    = {};
+        nm_auto_free_gstring GString *gstr = NULL;
+        int                           i, j, k;
+        int                           c;
+
+        nm_str_buf_init(&strbuf, nmtst_get_rand_uint32() % 200u + 1u, nmtst_get_rand_bool());
+
+        if (i_run < 1000) {
+            c = nmtst_get_rand_word_length(NULL);
+            for (i = 0; i < c; i++)
+                nm_str_buf_append_c(&strbuf, '0' + (i % 10));
+            gstr = g_string_new(nm_str_buf_get_str(&strbuf));
+            j    = nmtst_get_rand_uint32() % (strbuf.len + 1);
+            k    = nmtst_get_rand_uint32() % (strbuf.len - j + 2) - 1;
+
+            nm_str_buf_erase(&strbuf, j, k, nmtst_get_rand_bool());
+            g_string_erase(gstr, j, k);
+            g_assert_cmpstr(gstr->str, ==, nm_str_buf_get_str(&strbuf));
+        } else
+            return;
+    }
+}
+
+/*****************************************************************************/
 
 static void
-test_string_table_lookup (void)
+test_nm_utils_parse_next_line(void)
 {
-	const char *const args[] = { NULL, "0", "1", "2", "3", "x", };
-	int i;
+    const char *data;
+    const char *data0;
+    gsize       data_len;
+    const char *line_start;
+    gsize       line_len;
+    int         i_run;
+    gsize       j, k;
+
+    data     = NULL;
+    data_len = 0;
+    g_assert(!nm_utils_parse_next_line(&data, &data_len, &line_start, &line_len));
+
+    for (i_run = 0; i_run < 1000; i_run++) {
+        gs_unref_ptrarray GPtrArray *strv     = g_ptr_array_new_with_free_func(g_free);
+        gs_unref_ptrarray GPtrArray *strv2    = g_ptr_array_new_with_free_func(g_free);
+        gsize                        strv_len = nmtst_get_rand_word_length(NULL);
+        nm_auto_str_buf NMStrBuf     strbuf   = NM_STR_BUF_INIT(0, nmtst_get_rand_bool());
+
+        /* create a list of random words. */
+        for (j = 0; j < strv_len; j++) {
+            gsize    w_len = nmtst_get_rand_word_length(NULL);
+            NMStrBuf w_buf =
+                NM_STR_BUF_INIT(nmtst_get_rand_uint32() % (w_len + 1), nmtst_get_rand_bool());
+
+            for (k = 0; k < w_len; k++)
+                nm_str_buf_append_c(&w_buf, '0' + (k % 10));
+            nm_str_buf_maybe_expand(&w_buf, 1, TRUE);
+            g_ptr_array_add(strv, nm_str_buf_finalize(&w_buf, NULL));
+        }
+
+        /* join the list of random words with (random) line delimiters
+         * ("\0", "\n", "\r" or EOF). */
+        for (j = 0; j < strv_len; j++) {
+            nm_str_buf_append(&strbuf, strv->pdata[j]);
+again:
+            switch (nmtst_get_rand_uint32() % 5) {
+            case 0:
+                nm_str_buf_append_c(&strbuf, '\0');
+                break;
+            case 1:
+                if (strbuf.len > 0
+                    && (nm_str_buf_get_str_unsafe(&strbuf))[strbuf.len - 1] == '\r') {
+                    /* the previous line was empty and terminated by "\r". We
+                     * must not join with "\n". Retry. */
+                    goto again;
+                }
+                nm_str_buf_append_c(&strbuf, '\n');
+                break;
+            case 2:
+                nm_str_buf_append_c(&strbuf, '\r');
+                break;
+            case 3:
+                nm_str_buf_append(&strbuf, "\r\n");
+                break;
+            case 4:
+                /* the last word randomly is delimited or not, but not if the last
+                 * word is "". */
+                if (j + 1 < strv_len) {
+                    /* it's not the last word. Retry. */
+                    goto again;
+                }
+                g_assert(j == strv_len - 1);
+                if (((const char *) strv->pdata[j])[0] == '\0') {
+                    /* if the last word was "", we need a delimiter (to parse it back).
+                     * Retry. */
+                    goto again;
+                }
+                /* The final delimiter gets omitted. It's EOF. */
+                break;
+            }
+        }
+
+        data0 = nm_str_buf_get_str_unsafe(&strbuf);
+        if (!data0 && nmtst_get_rand_bool()) {
+            nm_str_buf_maybe_expand(&strbuf, 1, TRUE);
+            data0 = nm_str_buf_get_str_unsafe(&strbuf);
+            g_assert(data0);
+        }
+        data_len = strbuf.len;
+        g_assert((data_len > 0 && data0) || data_len == 0);
+        data = data0;
+        while (nm_utils_parse_next_line(&data, &data_len, &line_start, &line_len)) {
+            g_assert(line_start);
+            g_assert(line_start >= data0);
+            g_assert(line_start < &data0[strbuf.len]);
+            g_assert(!memchr(line_start, '\0', line_len));
+            g_ptr_array_add(strv2, g_strndup(line_start, line_len));
+        }
+        g_assert(data_len == 0);
+        if (data0)
+            g_assert(data == &data0[strbuf.len]);
+        else
+            g_assert(!data);
+
+        g_assert(_nm_utils_strv_cmp_n((const char *const *) strv->pdata,
+                                      strv->len,
+                                      (const char *const *) strv2->pdata,
+                                      strv2->len)
+                 == 0);
+    }
+}
 
-	for (i = 0; i < G_N_ELEMENTS (args); i++) {
-		const char *needle = args[i];
-		const int val2 = _nm_utils_ascii_str_to_int64 (needle, 10, 0, 100, -1);
-		int val;
+/*****************************************************************************/
 
-		val = _do_string_table_lookup (needle);
-		g_assert_cmpint (val, ==, val2);
-	}
+static void
+test_in_strset_ascii_case(void)
+{
+    const char *x;
+
+    x = NULL;
+    g_assert(NM_IN_STRSET_ASCII_CASE(x, NULL));
+    g_assert(NM_IN_STRSET_ASCII_CASE(x, NULL, "b"));
+    g_assert(!NM_IN_STRSET_ASCII_CASE(x, "b"));
+
+    x = "b";
+    g_assert(NM_IN_STRSET(x, "b"));
+    g_assert(NM_IN_STRSET_ASCII_CASE(x, "b"));
+    g_assert(!NM_IN_STRSET(x, "B"));
+    g_assert(NM_IN_STRSET_ASCII_CASE(x, "B"));
 }
 
 /*****************************************************************************/
 
 static void
-test_nm_utils_get_next_realloc_size (void)
+test_is_specific_hostname(void)
 {
-	static const struct {
-		gsize requested;
-		gsize reserved_true;
-		gsize reserved_false;
-	} test_data[] = {
-		{      0,     8,     8 },
-		{      1,     8,     8 },
-		{      8,     8,     8 },
-		{      9,    16,    16 },
-		{     16,    16,    16 },
-		{     17,    32,    32 },
-		{     32,    32,    32 },
-		{     33,    40,    40 },
-		{     40,    40,    40 },
-		{     41,   104,   104 },
-		{    104,   104,   104 },
-		{    105,   232,   232 },
-		{    232,   232,   232 },
-		{    233,   488,   488 },
-		{    488,   488,   488 },
-		{    489,  1000,  1000 },
-		{   1000,  1000,  1000 },
-		{   1001,  2024,  2024 },
-		{   2024,  2024,  2024 },
-		{   2025,  4072,  4072 },
-		{   4072,  4072,  4072 },
-		{   4073,  8168,  8168 },
-		{   8168,  8168,  8168 },
-		{   8169, 12264, 16360 },
-		{  12263, 12264, 16360 },
-		{  12264, 12264, 16360 },
-		{  12265, 16360, 16360 },
-		{  16360, 16360, 16360 },
-		{  16361, 20456, 32744 },
-		{  20456, 20456, 32744 },
-		{  20457, 24552, 32744 },
-		{  24552, 24552, 32744 },
-		{  24553, 28648, 32744 },
-		{  28648, 28648, 32744 },
-		{  28649, 32744, 32744 },
-		{  32744, 32744, 32744 },
-		{  32745, 36840, 65512 },
-		{  36840, 36840, 65512 },
-		{  G_MAXSIZE - 0x1000u,  G_MAXSIZE, G_MAXSIZE },
-		{  G_MAXSIZE - 25u,      G_MAXSIZE, G_MAXSIZE },
-		{  G_MAXSIZE - 24u,      G_MAXSIZE, G_MAXSIZE },
-		{  G_MAXSIZE - 1u,       G_MAXSIZE, G_MAXSIZE },
-		{  G_MAXSIZE,            G_MAXSIZE, G_MAXSIZE },
-		{  NM_UTILS_GET_NEXT_REALLOC_SIZE_104,  NM_UTILS_GET_NEXT_REALLOC_SIZE_104,  NM_UTILS_GET_NEXT_REALLOC_SIZE_104 },
-		{  NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, NM_UTILS_GET_NEXT_REALLOC_SIZE_1000 },
-	};
-	guint i;
-
-	G_STATIC_ASSERT_EXPR (NM_UTILS_GET_NEXT_REALLOC_SIZE_104  == 104u);
-	G_STATIC_ASSERT_EXPR (NM_UTILS_GET_NEXT_REALLOC_SIZE_1000 == 1000u);
-
-	for (i = 0; i < G_N_ELEMENTS (test_data) + 5000u; i++) {
-		gsize requested0;
-
-		if (i < G_N_ELEMENTS (test_data))
-			requested0 = test_data[i].requested;
-		else {
-			/* find some interesting random values for testing. */
-			switch (nmtst_get_rand_uint32 () % 5) {
-			case 0:
-				requested0 = nmtst_get_rand_size ();
-				break;
-			case 1:
-				/* values close to G_MAXSIZE. */
-				requested0 = G_MAXSIZE - (nmtst_get_rand_uint32 () % 12000u);
-				break;
-			case 2:
-				/* values around G_MAXSIZE/2. */
-				requested0 = (G_MAXSIZE / 2u) + 6000u - (nmtst_get_rand_uint32 () % 12000u);
-				break;
-			case 3:
-				/* values around powers of 2. */
-				requested0 = (((gsize) 1) << (nmtst_get_rand_uint32 () % (sizeof (gsize) * 8u))) + 6000u - (nmtst_get_rand_uint32 () % 12000u);
-				break;
-			case 4:
-				/* values around 4k borders. */
-				requested0 = (nmtst_get_rand_size () & ~((gsize) 0xFFFu)) + 30u - (nmtst_get_rand_uint32 () % 60u);
-				break;
-			default: g_assert_not_reached ();
-			}
-		}
-
-		{
-			const gsize requested = requested0;
-			const gsize reserved_true = nm_utils_get_next_realloc_size (TRUE, requested);
-			const gsize reserved_false = nm_utils_get_next_realloc_size (FALSE, requested);
-
-			g_assert_cmpuint (reserved_true, >, 0);
-			g_assert_cmpuint (reserved_false, >, 0);
-			g_assert_cmpuint (reserved_true, >=, requested);
-			g_assert_cmpuint (reserved_false, >=, requested);
-			g_assert_cmpuint (reserved_false, >=, reserved_true);
-
-			if (i < G_N_ELEMENTS (test_data)) {
-				g_assert_cmpuint (reserved_true, ==, test_data[i].reserved_true);
-				g_assert_cmpuint (reserved_false, ==, test_data[i].reserved_false);
-			}
-
-			/* reserved_false is generally the next power of two - 24. */
-			if (reserved_false == G_MAXSIZE)
-				g_assert_cmpuint (requested, >, G_MAXSIZE / 2u - 24u);
-			else {
-				g_assert_cmpuint (reserved_false, <=, G_MAXSIZE - 24u);
-				if (reserved_false >= 40) {
-					const gsize _pow2 = reserved_false + 24u;
-
-					/* reserved_false must always be a power of two minus 24. */
-					g_assert_cmpuint (_pow2, >=, 64u);
-					g_assert_cmpuint (_pow2, >, requested);
-					g_assert (nm_utils_is_power_of_two (_pow2));
-
-					/* but _pow2/2 must also be smaller than what we requested. */
-					g_assert_cmpuint (_pow2 / 2u - 24u, <, requested);
-				} else {
-					/* smaller values are hard-coded. */
-				}
-			}
-
-			/* reserved_true is generally the next 4k border - 24. */
-			if (reserved_true == G_MAXSIZE)
-				g_assert_cmpuint (requested, >, G_MAXSIZE - 0x1000u - 24u);
-			else {
-				g_assert_cmpuint (reserved_true, <=, G_MAXSIZE - 24u);
-				if (reserved_true > 8168u) {
-					const gsize page_border = reserved_true + 24u;
-
-					/* reserved_true must always be aligned to 4k (minus 24). */
-					g_assert_cmpuint (page_border % 0x1000u, ==, 0);
-					if (requested > 0x1000u - 24u) {
-						/* page_border not be more than 4k above requested. */
-						g_assert_cmpuint (page_border, >=, 0x1000u - 24u);
-						g_assert_cmpuint (page_border - 0x1000u - 24u, <, requested);
-					}
-				} else {
-					/* for smaller sizes, reserved_true and reserved_false are the same. */
-					g_assert_cmpuint (reserved_true, ==, reserved_false);
-				}
-			}
-
-		}
-	}
+    g_assert(!nm_utils_is_specific_hostname(NULL));
+    g_assert(!nm_utils_is_specific_hostname(""));
+    g_assert(!nm_utils_is_specific_hostname("(none)"));
+    g_assert(nm_utils_is_specific_hostname("(NONE)"));
+
+    g_assert(!nm_utils_is_specific_hostname("localhost"));
+    g_assert(!nm_utils_is_specific_hostname("lOcalHost"));
+    g_assert(!nm_utils_is_specific_hostname("LOCALHOST"));
+
+    g_assert(!nm_utils_is_specific_hostname("LOCALHOST.localdomain"));
+
+    g_assert(nm_utils_is_specific_hostname("xlocalhost"));
+    g_assert(nm_utils_is_specific_hostname("lOcalHxost"));
+    g_assert(nm_utils_is_specific_hostname("LOCALxHOST"));
+
+    g_assert(!nm_utils_is_specific_hostname("foo.LOCALHOST"));
+    g_assert(!nm_utils_is_specific_hostname("foo.LOCALHOsT6."));
+    g_assert(!nm_utils_is_specific_hostname("foo.LOCALHOsT6.localdomain6"));
+    g_assert(!nm_utils_is_specific_hostname(".LOCALHOsT6.localdomain6"));
+    g_assert(!nm_utils_is_specific_hostname("LOCALHOsT6.localdomain6"));
+    g_assert(!nm_utils_is_specific_hostname("LOCALHOsT6.localdomain6."));
+    g_assert(nm_utils_is_specific_hostname("LOCALHOsT6.localdomain."));
+
+    g_assert(nm_utils_is_specific_hostname(" "));
 }
 
 /*****************************************************************************/
 
 static void
-test_nm_str_buf (void)
+test_strv_dup_packed(void)
 {
-	guint i_run;
-
-	for (i_run = 0; TRUE; i_run++) {
-		nm_auto_str_buf NMStrBuf strbuf = { };
-		nm_auto_free_gstring GString *gstr = NULL;
-		int i, j, k;
-		int c;
-
-		nm_str_buf_init (&strbuf,
-		                 nmtst_get_rand_uint32 () % 200u + 1u,
-		                 nmtst_get_rand_bool ());
-
-		if (i_run < 1000) {
-			c = nmtst_get_rand_word_length (NULL);
-			for (i = 0; i < c; i++)
-				nm_str_buf_append_c (&strbuf, '0' + (i % 10));
-			gstr = g_string_new (nm_str_buf_get_str (&strbuf));
-			j = nmtst_get_rand_uint32 () % (strbuf.len + 1);
-			k = nmtst_get_rand_uint32 () % (strbuf.len - j + 2) - 1;
-
-			nm_str_buf_erase (&strbuf, j, k, nmtst_get_rand_bool ());
-			g_string_erase (gstr, j, k);
-			g_assert_cmpstr (gstr->str, ==, nm_str_buf_get_str (&strbuf));
-		} else
-			return;
-	}
+    gs_unref_ptrarray GPtrArray *src = NULL;
+    int                          i_run;
+
+    src = g_ptr_array_new_with_free_func(g_free);
+
+    for (i_run = 0; i_run < 500; i_run++) {
+        const int            strv_len = nmtst_get_rand_word_length(NULL);
+        gs_free const char **strv_cpy = NULL;
+        const char *const *  strv_src;
+        int                  i, j;
+
+        g_ptr_array_set_size(src, 0);
+        for (i = 0; i < strv_len; i++) {
+            const int word_len = nmtst_get_rand_word_length(NULL);
+            NMStrBuf  sbuf     = NM_STR_BUF_INIT(0, nmtst_get_rand_bool());
+
+            for (j = 0; j < word_len; j++)
+                nm_str_buf_append_c(&sbuf, 'a' + (nmtst_get_rand_uint32() % 20));
+
+            g_ptr_array_add(src, nm_str_buf_finalize(&sbuf, NULL) ?: g_new0(char, 1));
+        }
+        g_ptr_array_add(src, NULL);
+
+        strv_src = (const char *const *) src->pdata;
+        g_assert(strv_src);
+        g_assert(NM_PTRARRAY_LEN(strv_src) == strv_len);
+
+        strv_cpy =
+            nm_utils_strv_dup_packed(strv_src,
+                                     nmtst_get_rand_bool() ? (gssize) strv_len : (gssize) -1);
+        if (strv_len == 0)
+            g_assert(!strv_cpy);
+        else
+            g_assert(strv_cpy);
+        g_assert(NM_PTRARRAY_LEN(strv_cpy) == strv_len);
+        if (strv_cpy)
+            g_assert(_nm_utils_strv_equal((char **) strv_cpy, (char **) strv_src));
+    }
+}
+
+/*****************************************************************************/
+
+static int
+_hash_func_cmp_direct(gconstpointer a, gconstpointer b, gpointer user_data)
+{
+    NM_CMP_DIRECT(GPOINTER_TO_INT(a), GPOINTER_TO_INT(b));
+    return 0;
+}
+
+static void
+test_utils_hashtable_cmp(void)
+{
+    static struct {
+        int         val_i;
+        const char *val_s;
+    } vals[] = {
+        {
+            0,
+            "0",
+        },
+        {
+            1,
+            "1",
+        },
+        {
+            2,
+            "2",
+        },
+        {
+            3,
+            "3",
+        },
+        {
+            4,
+            "4",
+        },
+        {
+            5,
+            "5",
+        },
+        {
+            6,
+            "6",
+        },
+        {
+            7,
+            "7",
+        },
+        {
+            8,
+            "8",
+        },
+        {
+            9,
+            "9",
+        },
+        {
+            0,
+            "a",
+        },
+        {
+            1,
+            "a",
+        },
+        {
+            2,
+            "a",
+        },
+        {
+            3,
+            "a",
+        },
+        {
+            4,
+            "a",
+        },
+        {
+            5,
+            "a",
+        },
+        {
+            0,
+            "0",
+        },
+        {
+            0,
+            "1",
+        },
+        {
+            0,
+            "2",
+        },
+        {
+            0,
+            "3",
+        },
+        {
+            0,
+            "4",
+        },
+        {
+            0,
+            "5",
+        },
+    };
+    guint test_run;
+    int   is_num_key;
+
+    for (test_run = 0; test_run < 30; test_run++) {
+        for (is_num_key = 0; is_num_key < 2; is_num_key++) {
+            GHashFunc        func_key_hash  = is_num_key ? nm_direct_hash : nm_str_hash;
+            GEqualFunc       func_key_equal = is_num_key ? g_direct_equal : g_str_equal;
+            GCompareDataFunc func_key_cmp =
+                is_num_key ? _hash_func_cmp_direct : (GCompareDataFunc) nm_strcmp_with_data;
+            GCompareDataFunc func_val_cmp =
+                !is_num_key ? _hash_func_cmp_direct : (GCompareDataFunc) nm_strcmp_with_data;
+            gs_unref_hashtable GHashTable *h1 = NULL;
+            gs_unref_hashtable GHashTable *h2 = NULL;
+            gboolean                       has_same_keys;
+            guint                          i, n;
+
+            h1 = g_hash_table_new(func_key_hash, func_key_equal);
+            h2 = g_hash_table_new(func_key_hash, func_key_equal);
+
+            n = nmtst_get_rand_word_length(NULL);
+            for (i = 0; i < n; i++) {
+                typeof(vals[0]) *v     = &vals[nmtst_get_rand_uint32() % G_N_ELEMENTS(vals)];
+                gconstpointer    v_key = is_num_key ? GINT_TO_POINTER(v->val_i) : v->val_s;
+                gconstpointer    v_val = !is_num_key ? GINT_TO_POINTER(v->val_i) : v->val_s;
+
+                g_hash_table_insert(h1, (gpointer) v_key, (gpointer) v_val);
+                g_hash_table_insert(h2, (gpointer) v_key, (gpointer) v_val);
+            }
+
+            g_assert(nm_utils_hashtable_same_keys(h1, h2));
+            g_assert(nm_utils_hashtable_equal(h1, h2, NULL, NULL));
+            g_assert(nm_utils_hashtable_equal(h1, h2, func_val_cmp, NULL));
+            g_assert(nm_utils_hashtable_cmp(h1, h2, FALSE, func_key_cmp, NULL, NULL) == 0);
+            g_assert(nm_utils_hashtable_cmp(h1, h2, TRUE, func_key_cmp, NULL, NULL) == 0);
+            g_assert(nm_utils_hashtable_cmp(h1, h2, FALSE, func_key_cmp, func_val_cmp, NULL) == 0);
+            g_assert(nm_utils_hashtable_cmp(h1, h2, TRUE, func_key_cmp, func_val_cmp, NULL) == 0);
+
+            n             = nmtst_get_rand_word_length(NULL) + 1;
+            has_same_keys = TRUE;
+            for (i = 0; i < n; i++) {
+again:
+{
+    typeof(vals[0]) *v     = &vals[nmtst_get_rand_uint32() % G_N_ELEMENTS(vals)];
+    gconstpointer    v_key = is_num_key ? GINT_TO_POINTER(v->val_i) : v->val_s;
+    gconstpointer    v_val = !is_num_key ? GINT_TO_POINTER(v->val_i) : v->val_s;
+    gpointer         v_key2;
+    gpointer         v_val2;
+
+    if (g_hash_table_lookup_extended(h1, v_key, &v_key2, &v_val2)) {
+        g_assert(func_key_cmp(v_key, v_key2, NULL) == 0);
+        if (func_val_cmp(v_val, v_val2, NULL) == 0)
+            goto again;
+    } else
+        has_same_keys = FALSE;
+
+    g_hash_table_insert(h2, (gpointer) v_key, (gpointer) v_val);
+}
+            }
+
+            if (has_same_keys) {
+                g_assert(nm_utils_hashtable_same_keys(h1, h2));
+                g_assert(nm_utils_hashtable_equal(h1, h2, NULL, NULL));
+                g_assert(nm_utils_hashtable_cmp(h1, h2, FALSE, func_key_cmp, NULL, NULL) == 0);
+                g_assert(nm_utils_hashtable_cmp(h1, h2, TRUE, func_key_cmp, NULL, NULL) == 0);
+            } else {
+                g_assert(!nm_utils_hashtable_same_keys(h1, h2));
+                g_assert(!nm_utils_hashtable_equal(h1, h2, NULL, NULL));
+                g_assert(nm_utils_hashtable_cmp(h1, h2, FALSE, func_key_cmp, NULL, NULL) != 0);
+                g_assert(nm_utils_hashtable_cmp(h1, h2, TRUE, func_key_cmp, NULL, NULL) != 0);
+            }
+            g_assert(!nm_utils_hashtable_equal(h1, h2, func_val_cmp, NULL));
+            g_assert(nm_utils_hashtable_cmp(h1, h2, FALSE, func_key_cmp, func_val_cmp, NULL) != 0);
+            g_assert(nm_utils_hashtable_cmp(h1, h2, TRUE, func_key_cmp, func_val_cmp, NULL) != 0);
+        }
+    }
 }
 
 /*****************************************************************************/
 
-NMTST_DEFINE ();
+NMTST_DEFINE();
 
-int main (int argc, char **argv)
+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);
-	g_test_add_func ("/general/test_string_table_lookup", test_string_table_lookup);
-	g_test_add_func ("/general/test_nm_utils_get_next_realloc_size", test_nm_utils_get_next_realloc_size);
-	g_test_add_func ("/general/test_nm_str_buf", test_nm_str_buf);
-
-	return g_test_run ();
+    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);
+    g_test_add_func("/general/test_string_table_lookup", test_string_table_lookup);
+    g_test_add_func("/general/test_nm_utils_get_next_realloc_size",
+                    test_nm_utils_get_next_realloc_size);
+    g_test_add_func("/general/test_nm_str_buf", test_nm_str_buf);
+    g_test_add_func("/general/test_nm_utils_parse_next_line", test_nm_utils_parse_next_line);
+    g_test_add_func("/general/test_in_strset_ascii_case", test_in_strset_ascii_case);
+    g_test_add_func("/general/test_is_specific_hostname", test_is_specific_hostname);
+    g_test_add_func("/general/test_strv_dup_packed", test_strv_dup_packed);
+    g_test_add_func("/general/test_utils_hashtable_cmp", test_utils_hashtable_cmp);
+
+    return g_test_run();
 }