From 669a8484c696a600868f4461a74ba50a9c0aa478 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 13 Mar 2015 14:39:16 +0100 Subject: [PATCH 1/4] test: fix __NMTST_LOG() macro to allow format-string-only argument We want to be able to call __NMTST_LOG(g_message, "hallo"); without additional format string arguments. (cherry picked from commit 94cc7ca4f8f9cc97f4ff03a1fc7f6fa414da6038) --- include/nm-test-utils.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/nm-test-utils.h b/include/nm-test-utils.h index 64587f8d65..30d77099d5 100644 --- a/include/nm-test-utils.h +++ b/include/nm-test-utils.h @@ -32,6 +32,7 @@ #include #include "nm-utils.h" +#include "nm-utils-internal.h" #include "nm-glib-compat.h" #include "gsystem-local-alloc.h" @@ -84,13 +85,13 @@ nmtst_initialized (void) return !!__nmtst_internal.rand0; } -#define __NMTST_LOG(cmd, fmt, ...) \ +#define __NMTST_LOG(cmd, ...) \ G_STMT_START { \ g_assert (nmtst_initialized ()); \ if (!__nmtst_internal.assert_logging || __nmtst_internal.no_expect_message) { \ - cmd (fmt, __VA_ARGS__); \ + cmd (__VA_ARGS__); \ } else { \ - printf (fmt "\n", __VA_ARGS__); \ + printf (_NM_UTILS_MACRO_FIRST (__VA_ARGS__) "\n" _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ } \ } G_STMT_END From 6c63fe5028676723cfc788cb2ee4f0ccba89a51f Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 13 Mar 2015 14:32:39 +0100 Subject: [PATCH 2/4] test: fix printing error in nmtst_assert_connection_equals() (cherry picked from commit 3790d8db2e642c76188f740bfccf1f939c95115f) --- include/nm-test-utils.h | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/include/nm-test-utils.h b/include/nm-test-utils.h index 30d77099d5..054600a959 100644 --- a/include/nm-test-utils.h +++ b/include/nm-test-utils.h @@ -837,18 +837,21 @@ nmtst_assert_connection_equals (NMConnection *a, gboolean normalize_a, NMConnect b = b2 = nmtst_connection_duplicate_and_normalize (b); compare = nm_connection_diff (a, b, NM_SETTING_COMPARE_FLAG_EXACT, &out_settings); - if (!compare && out_settings) { + if (!compare || out_settings) { const char *name, *pname; GHashTable *setting; GHashTableIter iter, iter2; - g_hash_table_iter_init (&iter, out_settings); - while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer *) &setting)) { - __NMTST_LOG (g_message, ">>> differences in setting '%s':", name); + __NMTST_LOG (g_message, ">>> ASSERTION nmtst_assert_connection_equals() fails"); + if (out_settings) { + g_hash_table_iter_init (&iter, out_settings); + while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer *) &setting)) { + __NMTST_LOG (g_message, ">>> differences in setting '%s':", name); - g_hash_table_iter_init (&iter2, out_settings); - while (g_hash_table_iter_next (&iter2, (gpointer *) &pname, NULL)) - __NMTST_LOG (g_message, ">>> differences in setting '%s.%s':", name, pname); + g_hash_table_iter_init (&iter2, setting); + while (g_hash_table_iter_next (&iter2, (gpointer *) &pname, NULL)) + __NMTST_LOG (g_message, ">>> differences in setting '%s.%s'", name, pname); + } } } g_assert (compare); From 0a7af4f69b90081e4ff4f76600ab2664717bb9f6 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 13 Mar 2015 13:42:35 +0100 Subject: [PATCH 3/4] libnm: sort settings for nm_connection_for_each_setting_value() nm_connection_for_each_setting_value() is used by keyfile writer to iterate over the settings and write the keyfile entires. The order there is important as g_key_file_to_data() prints the groups in the order they were created. To have a stable order and to have the [connection] entry first, sort the settings. (cherry picked from commit e50fbe466b01823e97540d91a1452d994cfcb11e) --- libnm-core/nm-connection.c | 44 +++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c index 79ff31d89d..acdc8b89c7 100644 --- a/libnm-core/nm-connection.c +++ b/libnm-core/nm-connection.c @@ -30,6 +30,7 @@ #include "nm-utils.h" #include "nm-setting-private.h" #include "nm-core-internal.h" +#include "gsystem-local-alloc.h" /** * SECTION:nm-connection @@ -1306,6 +1307,19 @@ nm_connection_is_type (NMConnection *connection, const char *type) return (g_strcmp0 (type2, type) == 0); } +static int +_for_each_sort (NMSetting **p_a, NMSetting **p_b, void *unused) +{ + NMSetting *a = *p_a; + NMSetting *b = *p_b; + int c; + + c = _nm_setting_compare_priority (a, b); + if (c != 0) + return c; + return strcmp (nm_setting_get_name (a), nm_setting_get_name (b)); +} + /** * nm_connection_for_each_setting_value: * @connection: the #NMConnection @@ -1320,15 +1334,39 @@ nm_connection_for_each_setting_value (NMConnection *connection, NMSettingValueIterFn func, gpointer user_data) { + NMConnectionPrivate *priv; + gs_free NMSetting **arr_free = NULL; + NMSetting *arr_temp[20], **arr; GHashTableIter iter; gpointer value; + guint i, size; g_return_if_fail (NM_IS_CONNECTION (connection)); g_return_if_fail (func != NULL); - g_hash_table_iter_init (&iter, NM_CONNECTION_GET_PRIVATE (connection)->settings); - while (g_hash_table_iter_next (&iter, NULL, &value)) - nm_setting_enumerate_values (NM_SETTING (value), func, user_data); + priv = NM_CONNECTION_GET_PRIVATE (connection); + + size = g_hash_table_size (priv->settings); + if (!size) + return; + + if (size > G_N_ELEMENTS (arr_temp)) + arr = arr_free = g_new (NMSetting *, size); + else + arr = arr_temp; + + g_hash_table_iter_init (&iter, priv->settings); + for (i = 0; g_hash_table_iter_next (&iter, NULL, &value); i++) + arr[i] = NM_SETTING (value); + g_assert (i == size); + + /* sort the settings. This has an effect on the order in which keyfile + * prints them. */ + if (size > 1) + g_qsort_with_data (arr, size, sizeof (NMSetting *), (GCompareDataFunc) _for_each_sort, NULL); + + for (i = 0; i < size; i++) + nm_setting_enumerate_values (arr[i], func, user_data); } /** From dbcb88517a82a0a08d408c6f31c1694539560ce5 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 13 Mar 2015 16:35:23 +0100 Subject: [PATCH 4/4] libnm: sort properties for nm_setting_enumerate_values() The sort order of nm_setting_enumerate_values() affects the order in which keyfile writer serializes the properties. Have a defined, stable sort order by sorting the properties by name (with prefering id,uuid,type for NMSettingConnection). (cherry picked from commit 58f08c8c9ce3602f31d2fdfaa2cc9ecca4713532) --- libnm-core/nm-setting.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/libnm-core/nm-setting.c b/libnm-core/nm-setting.c index 2730742654..b78d9376ff 100644 --- a/libnm-core/nm-setting.c +++ b/libnm-core/nm-setting.c @@ -1314,6 +1314,33 @@ nm_setting_diff (NMSetting *a, return !(*results); } +#define CMP_AND_RETURN(n_a, n_b, name) \ + G_STMT_START { \ + gboolean _is = (strcmp (n_a, ""name) == 0); \ + \ + if (_is || (strcmp (n_b, ""name) == 0)) \ + return _is ? -1 : 1; \ + } G_STMT_END + +static int +_enumerate_values_sort (GParamSpec **p_a, GParamSpec **p_b, GType *p_type) +{ + const char *n_a = (*p_a)->name; + const char *n_b = (*p_b)->name; + int c = strcmp (n_a, n_b); + + if (c) { + if (*p_type == NM_TYPE_SETTING_CONNECTION) { + /* for [connection], report first id, uuid, type in that order. */ + CMP_AND_RETURN (n_a, n_b, NM_SETTING_CONNECTION_ID); + CMP_AND_RETURN (n_a, n_b, NM_SETTING_CONNECTION_UUID); + CMP_AND_RETURN (n_a, n_b, NM_SETTING_CONNECTION_TYPE); + } + } + return c; +} +#undef CMP_AND_RETURN + /** * nm_setting_enumerate_values: * @setting: the #NMSetting @@ -1331,11 +1358,19 @@ nm_setting_enumerate_values (NMSetting *setting, GParamSpec **property_specs; guint n_property_specs; int i; + GType type; g_return_if_fail (NM_IS_SETTING (setting)); g_return_if_fail (func != NULL); property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (setting), &n_property_specs); + + /* sort the properties. This has an effect on the order in which keyfile + * prints them. */ + type = G_OBJECT_TYPE (setting); + g_qsort_with_data (property_specs, n_property_specs, sizeof (gpointer), + (GCompareDataFunc) _enumerate_values_sort, &type); + for (i = 0; i < n_property_specs; i++) { GParamSpec *prop_spec = property_specs[i]; GValue value = G_VALUE_INIT;