summary refs log tree commit diff
path: root/shared
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2016-03-01 16:55:22 +0100
committerMichael Biebl <biebl@debian.org>2016-03-01 16:55:22 +0100
commitc2de0d98ba39e0a1a970d066fd19be786092f376 (patch)
tree3838363c06a6019db6cf1f882ea34ebded63c38b /shared
parent494f296a3baab08522617b24b1f126d8f9a17502 (diff)
Imported Upstream version 1.1.91 upstream/1.1.91
Diffstat (limited to 'shared')
-rw-r--r--shared/Makefile.am4
-rw-r--r--shared/Makefile.in4
-rw-r--r--shared/nm-default.h55
-rw-r--r--shared/nm-glib.h21
-rw-r--r--shared/nm-macros-internal.h240
-rw-r--r--shared/nm-test-utils-impl.c3
-rw-r--r--shared/nm-test-utils.h242
-rw-r--r--shared/nm-version-macros.h2
8 files changed, 412 insertions, 159 deletions
diff --git a/shared/Makefile.am b/shared/Makefile.am
index f0a1dba9..03fad123 100644
--- a/shared/Makefile.am
+++ b/shared/Makefile.am
@@ -3,8 +3,10 @@ EXTRA_DIST = \
      nm-dbus-compat.h \
      nm-default.h \
      nm-glib.h \
-     nm-test-utils.h \
      nm-macros-internal.h \
+     nm-test-libnm-utils.h \
+     nm-test-utils.h \
+     nm-test-utils-impl.c \
      nm-version-macros.h.in
 
 CLEANFILES=nm-version.h
diff --git a/shared/Makefile.in b/shared/Makefile.in
index ffa641d8..0b3284f0 100644
--- a/shared/Makefile.in
+++ b/shared/Makefile.in
@@ -400,8 +400,10 @@ EXTRA_DIST = \
      nm-dbus-compat.h \
      nm-default.h \
      nm-glib.h \
-     nm-test-utils.h \
      nm-macros-internal.h \
+     nm-test-libnm-utils.h \
+     nm-test-utils.h \
+     nm-test-utils-impl.c \
      nm-version-macros.h.in
 
 CLEANFILES = nm-version.h
diff --git a/shared/nm-default.h b/shared/nm-default.h
index 045ad8db..36527772 100644
--- a/shared/nm-default.h
+++ b/shared/nm-default.h
@@ -41,9 +41,17 @@
 
 /* always include these headers for our internal source files. */
 
+#ifndef ___CONFIG_H__
+#define ___CONFIG_H__
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+
 #include "nm-glib.h"
 #include "nm-version.h"
 #include "gsystem-local-alloc.h"
+#include "nm-macros-internal.h"
 
 /*****************************************************************************/
 
@@ -71,51 +79,4 @@
 
 /*****************************************************************************/
 
-/**
- * The boolean type _Bool is C99 while we mostly stick to C89. However, _Bool is too
- * convinient to miss and is effectively available in gcc and clang. So, just use it.
- *
- * Usually, one would include "stdbool.h" to get the "bool" define which aliases
- * _Bool. We provide this define here, because we want to make use of it anywhere.
- * (also, stdbool.h is again C99).
- *
- * Using _Bool has advantages over gboolean:
- *
- * - commonly _Bool is one byte large, instead of gboolean's 4 bytes (because gboolean
- *   is a typedef for gint). Especially when having boolean fields in a struct, we can
- *   thereby easily save some space.
- *
- * - _Bool type guarantees that two "true" expressions compare equal. E.g. the follwing
- *   will not work:
- *        gboolean v1 = 1;
- *        gboolean v2 = 2;
- *        g_assert_cmpint (v1, ==, v2); // will fail
- *   For that, we often to use !! to coerce gboolean values to 0 or 1:
- *        g_assert_cmpint (!!v2, ==, TRUE);
- *   With _Bool type, this will be handled properly by the compiler.
- *
- * - For structs, we might want to safe even more space and use bitfields:
- *       struct s1 {
- *           gboolean v1:1;
- *       };
- *   But the problem here is that gboolean is signed, so that
- *   v1 will be either 0 or -1 (not 1, TRUE). Thus, the following
- *   fails:
- *      struct s1 s = { .v1 = TRUE, };
- *      g_assert_cmpint (s1.v1, ==, TRUE);
- *   It will however work just fine with bool/_Bool while retaining the
- *   notion of having a boolean value.
- *
- * Also, add the defines for "true" and "false". Those are nicely highlighted by the editor
- * as special types, contrary to glib's "TRUE"/"FALSE".
- */
-
-#ifndef bool
-#define bool _Bool
-#define true    1
-#define false   0
-#endif
-
-/*****************************************************************************/
-
 #endif /* __NM_DEFAULT_H__ */
diff --git a/shared/nm-glib.h b/shared/nm-glib.h
index c75e91ba..c92d6f0f 100644
--- a/shared/nm-glib.h
+++ b/shared/nm-glib.h
@@ -116,6 +116,20 @@ __g_type_ensure (GType type)
 #define g_test_initialized() (g_test_config_vars->test_initialized)
 #endif
 
+/* g_assert_cmpmem() is only available since glib 2.46. */
+#if !GLIB_CHECK_VERSION (2, 45, 7)
+#define g_assert_cmpmem(m1, l1, m2, l2) G_STMT_START {\
+                                             gconstpointer __m1 = m1, __m2 = m2; \
+                                             int __l1 = l1, __l2 = l2; \
+                                             if (__l1 != __l2) \
+                                               g_assertion_message_cmpnum (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
+                                                                           #l1 " (len(" #m1 ")) == " #l2 " (len(" #m2 "))", __l1, "==", __l2, 'i'); \
+                                             else if (memcmp (__m1, __m2, __l1) != 0) \
+                                               g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
+                                                                    "assertion failed (" #m1 " == " #m2 ")"); \
+                                        } G_STMT_END
+#endif
+
 /* Rumtime check for glib version. First do a compile time check which
  * (if satisfied) shortcuts the runtime check. */
 #define nm_glib_check_version(major, minor, micro) \
@@ -353,4 +367,11 @@ _nm_g_hash_table_get_keys_as_array (GHashTable *hash_table,
 	})
 #endif
 
+#ifndef g_info
+/* g_info was only added with 2.39.2 */
+#define g_info(...)     g_log (G_LOG_DOMAIN,         \
+                               G_LOG_LEVEL_INFO,     \
+                               __VA_ARGS__)
+#endif
+
 #endif  /* __NM_GLIB_H__ */
diff --git a/shared/nm-macros-internal.h b/shared/nm-macros-internal.h
index 7bddb4bd..aa38bacf 100644
--- a/shared/nm-macros-internal.h
+++ b/shared/nm-macros-internal.h
@@ -22,7 +22,17 @@
 #ifndef __NM_MACROS_INTERNAL_H__
 #define __NM_MACROS_INTERNAL_H__
 
-#include "nm-default.h"
+/********************************************************/
+
+#define nm_auto(fcn) __attribute ((cleanup(fcn)))
+
+/**
+ * nm_auto_free:
+ *
+ * Call free() on a variable location when it goes out of scope.
+ */
+#define nm_auto_free nm_auto(_nm_auto_free_impl)
+GS_DEFINE_CLEANUP_FUNCTION(void*, _nm_auto_free_impl, free)
 
 /********************************************************/
 
@@ -107,7 +117,7 @@
 /********************************************************/
 
 /* macro to return strlen() of a compile time string. */
-#define STRLEN(str)     ( sizeof ("" str) - 1 )
+#define NM_STRLEN(str)     ( sizeof ("" str) - 1 )
 
 #define NM_SET_OUT(out_val, value) \
 	G_STMT_START { \
@@ -120,63 +130,130 @@
 
 /********************************************************/
 
-#define _NM_IN_SET_EVAL_1(op, x, y1)                              \
-    ({                                                            \
-        typeof(x) _x = (x);                                       \
-        (   (_x == (y1))                                          \
-        );                                                        \
+#define _NM_IN_SET_EVAL_1(op, _x, y1)                               \
+    (_x == (y1))
+
+#define _NM_IN_SET_EVAL_2(op, _x, y1, y2)                           \
+    (   (_x == (y1))                                                \
+     op (_x == (y2))                                                \
+    )
+
+#define _NM_IN_SET_EVAL_3(op, _x, y1, y2, y3)                       \
+    (   (_x == (y1))                                                \
+     op (_x == (y2))                                                \
+     op (_x == (y3))                                                \
+    )
+
+#define _NM_IN_SET_EVAL_4(op, _x, y1, y2, y3, y4)                   \
+    (   (_x == (y1))                                                \
+     op (_x == (y2))                                                \
+     op (_x == (y3))                                                \
+     op (_x == (y4))                                                \
+    )
+
+#define _NM_IN_SET_EVAL_5(op, _x, y1, y2, y3, y4, y5)               \
+    (   (_x == (y1))                                                \
+     op (_x == (y2))                                                \
+     op (_x == (y3))                                                \
+     op (_x == (y4))                                                \
+     op (_x == (y5))                                                \
+    )
+
+#define _NM_IN_SET_EVAL_6(op, _x, y1, y2, y3, y4, y5, y6)           \
+    (   (_x == (y1))                                                \
+     op (_x == (y2))                                                \
+     op (_x == (y3))                                                \
+     op (_x == (y4))                                                \
+     op (_x == (y5))                                                \
+     op (_x == (y6))                                                \
+    )
+
+#define _NM_IN_SET_EVAL_N2(op, _x, n, ...)        _NM_IN_SET_EVAL_##n(op, _x, __VA_ARGS__)
+#define _NM_IN_SET_EVAL_N(op, x, n, ...)                            \
+    ({                                                              \
+        typeof(x) _x = (x);                                         \
+        !!_NM_IN_SET_EVAL_N2(op, _x, n, __VA_ARGS__);               \
     })
 
-#define _NM_IN_SET_EVAL_2(op, x, y1, y2)                          \
-    ({                                                            \
-        typeof(x) _x = (x);                                       \
-        (   (_x == (y1))                                          \
-         op (_x == (y2))                                          \
-        );                                                        \
-    })
+/* Beware that this does short-circuit evaluation (use "||" instead of "|")
+ * which has a possibly unexpected non-function-like behavior.
+ * Use NM_IN_SET_SE if you need all arguments to be evaluted. */
+#define NM_IN_SET(x, ...)               _NM_IN_SET_EVAL_N(||, x, NM_NARG (__VA_ARGS__), __VA_ARGS__)
 
-#define _NM_IN_SET_EVAL_3(op, x, y1, y2, y3)                      \
-    ({                                                            \
-        typeof(x) _x = (x);                                       \
-        (   (_x == (y1))                                          \
-         op (_x == (y2))                                          \
-         op (_x == (y3))                                          \
-        );                                                        \
-    })
+/* "SE" stands for "side-effect". Contrary to NM_IN_SET(), this does not do
+ * short-circuit evaluation, which can make a difference if the arguments have
+ * side-effects. */
+#define NM_IN_SET_SE(x, ...)            _NM_IN_SET_EVAL_N(|, x, NM_NARG (__VA_ARGS__), __VA_ARGS__)
 
-#define _NM_IN_SET_EVAL_4(op, x, y1, y2, y3, y4)                  \
-    ({                                                            \
-        typeof(x) _x = (x);                                       \
-        (   (_x == (y1))                                          \
-         op (_x == (y2))                                          \
-         op (_x == (y3))                                          \
-         op (_x == (y4))                                          \
-        );                                                        \
-    })
+/********************************************************/
+
+static inline gboolean
+_NM_IN_STRSET_streq (const char *x, const char *s)
+{
+	return s && strcmp (x, s) == 0;
+}
 
-#define _NM_IN_SET_EVAL_5(op, x, y1, y2, y3, y4, y5)              \
+#define _NM_IN_STRSET_EVAL_1(op, _x, y1)                            \
+    _NM_IN_STRSET_streq (_x, y1)
+
+#define _NM_IN_STRSET_EVAL_2(op, _x, y1, y2)                        \
+    (   _NM_IN_STRSET_streq (_x, y1)                                \
+     op _NM_IN_STRSET_streq (_x, y2)                                \
+    )
+
+#define _NM_IN_STRSET_EVAL_3(op, _x, y1, y2, y3)                    \
+    (   _NM_IN_STRSET_streq (_x, y1)                                \
+     op _NM_IN_STRSET_streq (_x, y2)                                \
+     op _NM_IN_STRSET_streq (_x, y3)                                \
+    )
+
+#define _NM_IN_STRSET_EVAL_4(op, _x, y1, y2, y3, y4)                \
+    (   _NM_IN_STRSET_streq (_x, y1)                                \
+     op _NM_IN_STRSET_streq (_x, y2)                                \
+     op _NM_IN_STRSET_streq (_x, y3)                                \
+     op _NM_IN_STRSET_streq (_x, y4)                                \
+    )
+
+#define _NM_IN_STRSET_EVAL_5(op, _x, y1, y2, y3, y4, y5)            \
+    (   _NM_IN_STRSET_streq (_x, y1)                                \
+     op _NM_IN_STRSET_streq (_x, y2)                                \
+     op _NM_IN_STRSET_streq (_x, y3)                                \
+     op _NM_IN_STRSET_streq (_x, y4)                                \
+     op _NM_IN_STRSET_streq (_x, y5)                                \
+    )
+
+#define _NM_IN_STRSET_EVAL_6(op, _x, y1, y2, y3, y4, y5, y6)        \
+    (   _NM_IN_STRSET_streq (_x, y1)                                \
+     op _NM_IN_STRSET_streq (_x, y2)                                \
+     op _NM_IN_STRSET_streq (_x, y3)                                \
+     op _NM_IN_STRSET_streq (_x, y4)                                \
+     op _NM_IN_STRSET_streq (_x, y5)                                \
+     op _NM_IN_STRSET_streq (_x, y6)                                \
+    )
+
+#define _NM_IN_STRSET_EVAL_N2(op, _x, n, ...) _NM_IN_STRSET_EVAL_##n(op, _x, __VA_ARGS__)
+#define _NM_IN_STRSET_EVAL_N(op, x, n, ...)                       \
     ({                                                            \
-        typeof(x) _x = (x);                                       \
-        (   (_x == (y1))                                          \
-         op (_x == (y2))                                          \
-         op (_x == (y3))                                          \
-         op (_x == (y4))                                          \
-         op (_x == (y5))                                          \
-        );                                                        \
+        const char *_x = (x);                                     \
+        (   ((_x == NULL) && _NM_IN_SET_EVAL_N2    (op, (const char *) NULL, n, __VA_ARGS__)) \
+         || ((_x != NULL) && _NM_IN_STRSET_EVAL_N2 (op, _x,                  n, __VA_ARGS__)) \
+        ); \
     })
 
-#define _NM_IN_SET_EVAL_N2(op, x, n, ...)        _NM_IN_SET_EVAL_##n(op, x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_N(op, x, n, ...)         _NM_IN_SET_EVAL_N2(op, x, n, __VA_ARGS__)
-
 /* Beware that this does short-circuit evaluation (use "||" instead of "|")
  * which has a possibly unexpected non-function-like behavior.
- * Use NM_IN_SET_SE if you need all arguments to be evaluted. */
-#define NM_IN_SET(x, ...)               _NM_IN_SET_EVAL_N(||, x, NM_NARG (__VA_ARGS__), __VA_ARGS__)
+ * Use NM_IN_STRSET_SE if you need all arguments to be evaluted. */
+#define NM_IN_STRSET(x, ...)               _NM_IN_STRSET_EVAL_N(||, x, NM_NARG (__VA_ARGS__), __VA_ARGS__)
 
-/* "SE" stands for "side-effect". Contrary to NM_IN_SET(), this does not do
+/* "SE" stands for "side-effect". Contrary to NM_IN_STRSET(), this does not do
  * short-circuit evaluation, which can make a difference if the arguments have
  * side-effects. */
-#define NM_IN_SET_SE(x, ...)            _NM_IN_SET_EVAL_N(|, x, NM_NARG (__VA_ARGS__), __VA_ARGS__)
+#define NM_IN_STRSET_SE(x, ...)            _NM_IN_STRSET_EVAL_N(|, x, NM_NARG (__VA_ARGS__), __VA_ARGS__)
+
+/*****************************************************************************/
+
+#define nm_streq(s1, s2)  (strcmp (s1, s2) == 0)
+#define nm_streq0(s1, s2) (g_strcmp0 (s1, s2) == 0)
 
 /*****************************************************************************/
 
@@ -196,6 +273,26 @@
 
 /*****************************************************************************/
 
+#define NM_GOBJECT_PROPERTIES_DEFINE_BASE(...) \
+typedef enum { \
+	_PROPERTY_ENUMS_0, \
+	__VA_ARGS__ \
+	_PROPERTY_ENUMS_LAST, \
+} _PropertyEnums; \
+static GParamSpec *obj_properties[_PROPERTY_ENUMS_LAST] = { NULL, }
+
+#define NM_GOBJECT_PROPERTIES_DEFINE(obj_type, ...) \
+NM_GOBJECT_PROPERTIES_DEFINE_BASE (__VA_ARGS__); \
+static inline void \
+_notify (obj_type *obj, _PropertyEnums prop) \
+{ \
+	nm_assert (G_IS_OBJECT (obj)); \
+	nm_assert ((gsize) prop < G_N_ELEMENTS (obj_properties)); \
+	g_object_notify_by_pspec ((GObject *) obj, obj_properties[prop]); \
+}
+
+/*****************************************************************************/
+
 static inline gboolean
 nm_clear_g_source (guint *id)
 {
@@ -337,7 +434,7 @@ nm_decode_version (guint version, guint *major, guint *minor, guint *micro) {
 		 * It disallows a buffer size of sizeof(gpointer) to catch that. */ \
 		G_STATIC_ASSERT (G_N_ELEMENTS (buf) == sizeof (buf) && sizeof (buf) != sizeof (char *)); \
 		g_snprintf (_buf, sizeof (buf), \
-		            ""format"", __VA_ARGS__); \
+		            ""format"", ##__VA_ARGS__); \
 		_buf; \
 	})
 
@@ -348,10 +445,57 @@ nm_decode_version (guint version, guint *major, guint *minor, guint *micro) {
 		G_STATIC_ASSERT (sizeof (char[MAX ((n_elements), 1)]) == (n_elements)); \
 		_buf = g_alloca (n_elements); \
 		g_snprintf (_buf, n_elements, \
-		            ""format"", __VA_ARGS__); \
+		            ""format"", ##__VA_ARGS__); \
 		_buf; \
 	})
 
 /*****************************************************************************/
 
+/**
+ * The boolean type _Bool is C99 while we mostly stick to C89. However, _Bool is too
+ * convinient to miss and is effectively available in gcc and clang. So, just use it.
+ *
+ * Usually, one would include "stdbool.h" to get the "bool" define which aliases
+ * _Bool. We provide this define here, because we want to make use of it anywhere.
+ * (also, stdbool.h is again C99).
+ *
+ * Using _Bool has advantages over gboolean:
+ *
+ * - commonly _Bool is one byte large, instead of gboolean's 4 bytes (because gboolean
+ *   is a typedef for gint). Especially when having boolean fields in a struct, we can
+ *   thereby easily save some space.
+ *
+ * - _Bool type guarantees that two "true" expressions compare equal. E.g. the follwing
+ *   will not work:
+ *        gboolean v1 = 1;
+ *        gboolean v2 = 2;
+ *        g_assert_cmpint (v1, ==, v2); // will fail
+ *   For that, we often to use !! to coerce gboolean values to 0 or 1:
+ *        g_assert_cmpint (!!v2, ==, TRUE);
+ *   With _Bool type, this will be handled properly by the compiler.
+ *
+ * - For structs, we might want to safe even more space and use bitfields:
+ *       struct s1 {
+ *           gboolean v1:1;
+ *       };
+ *   But the problem here is that gboolean is signed, so that
+ *   v1 will be either 0 or -1 (not 1, TRUE). Thus, the following
+ *   fails:
+ *      struct s1 s = { .v1 = TRUE, };
+ *      g_assert_cmpint (s1.v1, ==, TRUE);
+ *   It will however work just fine with bool/_Bool while retaining the
+ *   notion of having a boolean value.
+ *
+ * Also, add the defines for "true" and "false". Those are nicely highlighted by the editor
+ * as special types, contrary to glib's "TRUE"/"FALSE".
+ */
+
+#ifndef bool
+#define bool _Bool
+#define true    1
+#define false   0
+#endif
+
+/*****************************************************************************/
+
 #endif /* __NM_MACROS_INTERNAL_H__ */
diff --git a/shared/nm-test-utils-impl.c b/shared/nm-test-utils-impl.c
index 5cdfda3d..613a6dfe 100644
--- a/shared/nm-test-utils-impl.c
+++ b/shared/nm-test-utils-impl.c
@@ -18,11 +18,10 @@
  *
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <string.h>
 
-#include "nm-default.h"
 #include "NetworkManager.h"
 #include "nm-dbus-compat.h"
 
diff --git a/shared/nm-test-utils.h b/shared/nm-test-utils.h
index 0402201c..542081b8 100644
--- a/shared/nm-test-utils.h
+++ b/shared/nm-test-utils.h
@@ -88,6 +88,8 @@
  *
  *******************************************************************************/
 
+#include "nm-default.h"
+
 #include <arpa/inet.h>
 #include <stdio.h>
 #include <unistd.h>
@@ -95,9 +97,7 @@
 #include <string.h>
 #include <errno.h>
 
-#include "nm-default.h"
 #include "nm-utils.h"
-#include "nm-macros-internal.h"
 
 #ifdef __NETWORKMANAGER_LOGGING_H__
 /* We are running tests under src/. Let's include some files by default.
@@ -158,6 +158,12 @@ _nmtst_assert_success (gboolean success, GError *error, const char *file, int li
 }
 #define nmtst_assert_success(success, error) _nmtst_assert_success ((success), (error), __FILE__, __LINE__)
 
+#define nmtst_assert_no_success(success, error) \
+	G_STMT_START { \
+		g_assert (error); \
+		g_assert (!(success)); \
+	} G_STMT_END
+
 /*******************************************************************************/
 
 struct __nmtst_internal
@@ -648,6 +654,82 @@ nmtst_test_quick (void)
 	} G_STMT_END
 #endif
 
+/*****************************************************************************/
+
+typedef struct _NmtstTestData NmtstTestData;
+
+typedef void (*NmtstTestDataRelease) (const NmtstTestData *test_data);
+
+struct _NmtstTestData {
+	const char *testpath;
+	NmtstTestDataRelease fcn_release;
+	gsize n_args;
+	gpointer args[1];
+};
+
+inline static void
+_nmtst_test_data_unpack (const NmtstTestData *test_data, gsize n_args, ...)
+{
+	gsize i;
+	va_list ap;
+	gpointer *p;
+
+	g_assert (test_data);
+	g_assert_cmpint (n_args, ==, test_data->n_args);
+
+	va_start (ap, n_args);
+	for (i = 0; i < n_args; i++) {
+		p = va_arg (ap, gpointer *);
+
+		g_assert (p);
+		*p = test_data->args[i];
+	}
+	va_end (ap);
+}
+#define nmtst_test_data_unpack(test_data, ...) _nmtst_test_data_unpack(test_data, NM_NARG (__VA_ARGS__), ##__VA_ARGS__)
+
+inline static void
+_nmtst_test_data_free (gpointer data)
+{
+	NmtstTestData *test_data = data;
+
+	g_assert (test_data);
+
+	if (test_data->fcn_release)
+		test_data->fcn_release (test_data);
+
+	g_free ((gpointer) test_data->testpath);
+	g_free (test_data);
+}
+
+inline static void
+_nmtst_add_test_func_full (const char *testpath, GTestDataFunc test_func, NmtstTestDataRelease fcn_release, gsize n_args, ...)
+{
+	gsize i;
+	NmtstTestData *data;
+	va_list ap;
+
+	data = g_malloc (G_STRUCT_OFFSET (NmtstTestData, args) + sizeof (gpointer) * (n_args + 1));
+
+	data->testpath = g_strdup (testpath);
+	data->fcn_release = fcn_release;
+	data->n_args = n_args;
+	va_start (ap, n_args);
+	for (i = 0; i < n_args; i++)
+		data->args[i] = va_arg (ap, gpointer);
+	data->args[i] = NULL;
+	va_end (ap);
+
+	g_test_add_data_func_full (testpath,
+	                           data,
+	                           test_func,
+	                           _nmtst_test_data_free);
+}
+#define nmtst_add_test_func_full(testpath, test_func, fcn_release, ...) _nmtst_add_test_func_full(testpath, test_func, fcn_release, NM_NARG (__VA_ARGS__), ##__VA_ARGS__)
+#define nmtst_add_test_func(testpath, test_func, ...) nmtst_add_test_func_full(testpath, test_func, NULL, ##__VA_ARGS__)
+
+/*****************************************************************************/
+
 inline static GRand *
 nmtst_get_rand0 (void)
 {
@@ -962,26 +1044,6 @@ _nmtst_assert_ip6_address (const char *file, int line, const struct in6_addr *ad
 }
 #define nmtst_assert_ip6_address(addr, str_expected) _nmtst_assert_ip6_address (__FILE__, __LINE__, addr, str_expected)
 
-inline static void
-FAIL(const char *test_name, const char *fmt, ...)
-{
-	va_list args;
-	char buf[500];
-
-	g_snprintf (buf, 500, "FAIL: (%s) %s\n", test_name, fmt);
-
-	va_start (args, fmt);
-	vfprintf (stderr, buf, args);
-	va_end (args);
-	_exit (1);
-}
-
-#define ASSERT(x, test_name, fmt, ...) \
-	if (!(x)) { \
-		FAIL (test_name, fmt, ## __VA_ARGS__); \
-	}
-
-
 #define nmtst_spawn_sync(working_directory, standard_out, standard_err, assert_exit_status, ...) \
 	__nmtst_spawn_sync (working_directory, standard_out, standard_err, assert_exit_status, ##__VA_ARGS__, NULL)
 inline static gint
@@ -1085,7 +1147,7 @@ nmtst_platform_ip6_address (const char *address, const char *peer_address, guint
 inline static NMPlatformIP6Address *
 nmtst_platform_ip6_address_full (const char *address, const char *peer_address, guint plen,
                                  int ifindex, NMIPConfigSource source, guint32 timestamp,
-                                 guint32 lifetime, guint32 preferred, guint flags)
+                                 guint32 lifetime, guint32 preferred, guint32 flags)
 {
 	NMPlatformIP6Address *addr = nmtst_platform_ip6_address (address, peer_address, plen);
 
@@ -1094,7 +1156,7 @@ nmtst_platform_ip6_address_full (const char *address, const char *peer_address,
 	addr->timestamp = timestamp;
 	addr->lifetime = lifetime;
 	addr->preferred = preferred;
-	addr->flags = flags;
+	addr->n_ifa_flags = flags;
 
 	return addr;
 }
@@ -1261,9 +1323,71 @@ nmtst_ip6_config_clone (NMIP6Config *config)
 
 #endif
 
+#ifdef NM_SETTING_IP_CONFIG_H
+inline static void
+nmtst_setting_ip_config_add_address (NMSettingIPConfig *s_ip,
+                                     const char *address,
+                                     guint prefix)
+{
+	NMIPAddress *addr;
+	int family;
+
+	g_assert (s_ip);
+
+	if (nm_utils_ipaddr_valid (AF_INET, address))
+		family = AF_INET;
+	else if (nm_utils_ipaddr_valid (AF_INET6, address))
+		family = AF_INET6;
+	else
+		g_assert_not_reached ();
+
+	addr = nm_ip_address_new (family, address, prefix, NULL);
+	g_assert (addr);
+	g_assert (nm_setting_ip_config_add_address (s_ip, addr));
+	nm_ip_address_unref (addr);
+}
+
+inline static void
+nmtst_setting_ip_config_add_route (NMSettingIPConfig *s_ip,
+                                   const char *dest,
+                                   guint prefix,
+                                   const char *next_hop,
+                                   gint64 metric)
+{
+	NMIPRoute *route;
+	int family;
+
+	g_assert (s_ip);
+
+	if (nm_utils_ipaddr_valid (AF_INET, dest))
+		family = AF_INET;
+	else if (nm_utils_ipaddr_valid (AF_INET6, dest))
+		family = AF_INET6;
+	else
+		g_assert_not_reached ();
+
+	route = nm_ip_route_new (family, dest, prefix, next_hop, metric, NULL);
+	g_assert (route);
+	g_assert (nm_setting_ip_config_add_route (s_ip, route));
+	nm_ip_route_unref (route);
+}
+#endif /* NM_SETTING_IP_CONFIG_H */
+
 #if (defined(__NM_SIMPLE_CONNECTION_H__) && defined(__NM_SETTING_CONNECTION_H__)) || (defined(NM_CONNECTION_H))
 
 inline static NMConnection *
+nmtst_clone_connection (NMConnection *connection)
+{
+	g_assert (NM_IS_CONNECTION (connection));
+
+#if defined(__NM_SIMPLE_CONNECTION_H__)
+	return nm_simple_connection_new_clone (connection);
+#else
+	return nm_connection_duplicate (connection);
+#endif
+}
+
+inline static NMConnection *
 nmtst_create_minimal_connection (const char *id, const char *uuid, const char *type, NMSettingConnection **out_s_con)
 {
 	NMConnection *con;
@@ -1367,13 +1491,7 @@ _nmtst_connection_duplicate_and_normalize (NMConnection *connection, ...)
 	gboolean was_modified;
 	va_list args;
 
-	g_assert (NM_IS_CONNECTION (connection));
-
-#if defined(__NM_SIMPLE_CONNECTION_H__)
-	connection = nm_simple_connection_new_clone (connection);
-#else
-	connection = nm_connection_duplicate (connection);
-#endif
+	connection = nmtst_clone_connection (connection);
 
 	va_start (args, connection);
 	was_modified = _nmtst_connection_normalize_v (connection, args);
@@ -1444,28 +1562,33 @@ nmtst_assert_connection_equals (NMConnection *a, gboolean normalize_a, NMConnect
 }
 
 inline static void
-nmtst_assert_connection_verifies_without_normalization (NMConnection *con)
+nmtst_assert_connection_verifies (NMConnection *con)
 {
-	/* assert that the connection verifies and does not need any normalization */
-
+	/* assert that the connection does verify, it might be normaliziable or not */
 	GError *error = NULL;
 	gboolean success;
-	gboolean was_modified = FALSE;
-	gs_unref_object NMConnection *clone = NULL;
 
 	g_assert (NM_IS_CONNECTION (con));
 
-#if defined(__NM_SIMPLE_CONNECTION_H__)
-	clone = nm_simple_connection_new_clone (con);
-#else
-	clone = nm_connection_duplicate (con);
-#endif
-
 	success = nm_connection_verify (con, &error);
 	g_assert_no_error (error);
 	g_assert (success);
+}
+
+inline static void
+nmtst_assert_connection_verifies_without_normalization (NMConnection *con)
+{
+	/* assert that the connection verifies and does not need any normalization */
+	GError *error = NULL;
+	gboolean success;
+	gboolean was_modified = FALSE;
+	gs_unref_object NMConnection *clone = NULL;
 
-	success = nm_connection_normalize (con, NULL, &was_modified, &error);
+	clone = nmtst_clone_connection (con);
+
+	nmtst_assert_connection_verifies (con);
+
+	success = nm_connection_normalize (clone, NULL, &was_modified, &error);
 	g_assert_no_error (error);
 	g_assert (success);
 	nmtst_assert_connection_equals (con, FALSE, clone, FALSE);
@@ -1479,21 +1602,19 @@ nmtst_assert_connection_verifies_and_normalizable (NMConnection *con)
 	GError *error = NULL;
 	gboolean success;
 	gboolean was_modified = FALSE;
+	gs_unref_object NMConnection *clone = NULL;
 
-	g_assert (NM_IS_CONNECTION (con));
+	clone = nmtst_clone_connection (con);
 
-	success = nm_connection_verify (con, &error);
-	g_assert_no_error (error);
-	g_assert (success);
-	g_clear_error (&error);
+	nmtst_assert_connection_verifies (con);
 
-	success = nm_connection_normalize (con, NULL, &was_modified, &error);
+	success = nm_connection_normalize (clone, NULL, &was_modified, &error);
 	g_assert_no_error (error);
 	g_assert (success);
 	g_assert (was_modified);
 
 	/* again! */
-	nmtst_assert_connection_verifies_without_normalization (con);
+	nmtst_assert_connection_verifies_without_normalization (clone);
 }
 
 inline static void
@@ -1505,21 +1626,22 @@ nmtst_assert_connection_verifies_after_normalization (NMConnection *con,
 	GError *error = NULL;
 	gboolean success;
 	gboolean was_modified = FALSE;
+	gs_unref_object NMConnection *clone = NULL;
 
-	g_assert (NM_IS_CONNECTION (con));
+	clone = nmtst_clone_connection (con);
 
 	success = nm_connection_verify (con, &error);
 	nmtst_assert_error (error, expect_error_domain, expect_error_code, NULL);
 	g_assert (!success);
 	g_clear_error (&error);
 
-	success = nm_connection_normalize (con, NULL, &was_modified, &error);
+	success = nm_connection_normalize (clone, NULL, &was_modified, &error);
 	g_assert_no_error (error);
 	g_assert (success);
 	g_assert (was_modified);
 
 	/* again! */
-	nmtst_assert_connection_verifies_without_normalization (con);
+	nmtst_assert_connection_verifies_without_normalization (clone);
 }
 
 inline static void
@@ -1532,18 +1654,20 @@ nmtst_assert_connection_unnormalizable (NMConnection *con,
 	GError *error = NULL;
 	gboolean success;
 	gboolean was_modified = FALSE;
+	gs_unref_object NMConnection *clone = NULL;
 
-	g_assert (NM_IS_CONNECTION (con));
+	clone = nmtst_clone_connection (con);
 
 	success = nm_connection_verify (con, &error);
 	nmtst_assert_error (error, expect_error_domain, expect_error_code, NULL);
 	g_assert (!success);
 	g_clear_error (&error);
 
-	success = nm_connection_normalize (con, NULL, &was_modified, &error);
+	success = nm_connection_normalize (clone, NULL, &was_modified, &error);
 	nmtst_assert_error (error, expect_error_domain, expect_error_code, NULL);
 	g_assert (!success);
 	g_assert (!was_modified);
+	nmtst_assert_connection_equals (con, FALSE, clone, FALSE);
 	g_clear_error (&error);
 }
 
@@ -1584,7 +1708,7 @@ nmtst_assert_setting_verify_fails (NMSetting *setting,
 
 #ifdef __NM_UTILS_H__
 static inline void
-nmtst_assert_hwaddr_equals (gconstpointer hwaddr1, gssize hwaddr1_len, const char *expected, const char *loc)
+nmtst_assert_hwaddr_equals (gconstpointer hwaddr1, gssize hwaddr1_len, const char *expected, const char *file, int line)
 {
 	guint8 buf2[NM_UTILS_HWADDR_LEN_MAX];
 	gsize hwaddr2_len = 1;
@@ -1609,12 +1733,12 @@ nmtst_assert_hwaddr_equals (gconstpointer hwaddr1, gssize hwaddr1_len, const cha
 	if (success)
 		success = !memcmp (hwaddr1, buf2, hwaddr1_len);
 	if (!success) {
-		g_error ("assert: %s: hwaddr '%s' (%zd) expected, but got %s (%zd)",
-		         loc, expected, hwaddr2_len, nm_utils_hwaddr_ntoa (hwaddr1, hwaddr1_len), hwaddr1_len);
+		g_error ("assert: %s:%d: hwaddr '%s' (%zd) expected, but got %s (%zd)",
+		         file, line, expected, hwaddr2_len, nm_utils_hwaddr_ntoa (hwaddr1, hwaddr1_len), hwaddr1_len);
 	}
 }
 #define nmtst_assert_hwaddr_equals(hwaddr1, hwaddr1_len, expected) \
-    nmtst_assert_hwaddr_equals (hwaddr1, hwaddr1_len, expected, G_STRLOC)
+    nmtst_assert_hwaddr_equals (hwaddr1, hwaddr1_len, expected, __FILE__, __LINE__)
 #endif
 
 #if defined(__NM_SIMPLE_CONNECTION_H__) && defined(__NM_SETTING_CONNECTION_H__) && defined(__NM_KEYFILE_INTERNAL_H__)
diff --git a/shared/nm-version-macros.h b/shared/nm-version-macros.h
index dff5a449..e113b035 100644
--- a/shared/nm-version-macros.h
+++ b/shared/nm-version-macros.h
@@ -45,7 +45,7 @@
  * Evaluates to the micro version number of NetworkManager which this source
  * compiled against.
  */
-#define NM_MICRO_VERSION (90)
+#define NM_MICRO_VERSION (91)
 
 /**
  * NM_CHECK_VERSION: