summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2024-01-04 10:04:19 +0100
committerThomas Haller <thaller@redhat.com>2024-01-04 10:04:19 +0100
commit71b535e932e589c1d33d62d869e7010f1c054a69 (patch)
tree925369299aa696501b7f2fb5a77cd82ed22e1f97
parent0e893593a95aac02b20d1015a009f414f996917c (diff)
parent03b9a255d2a7101c63b4f865614e3f60952292ca (diff)
glib-aux,libnm: merge branch 'th/gvariant-cmp'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1819
-rw-r--r--.gitignore2
-rw-r--r--Makefile.am7
-rw-r--r--docs/libnm/Makefile.am1
-rw-r--r--docs/libnm/meson.build1
-rw-r--r--src/libnm-core-impl/meson.build1
-rw-r--r--src/libnm-core-impl/nm-property-compare.c136
-rw-r--r--src/libnm-core-impl/nm-property-compare.h16
-rw-r--r--src/libnm-core-impl/nm-setting.c3
-rw-r--r--src/libnm-core-impl/tests/meson.build1
-rw-r--r--src/libnm-core-impl/tests/test-compare.c231
-rw-r--r--src/libnm-glib-aux/nm-shared-utils.c143
-rw-r--r--src/libnm-glib-aux/nm-shared-utils.h4
-rw-r--r--src/libnm-glib-aux/tests/test-shared-general.c225
13 files changed, 374 insertions, 397 deletions
diff --git a/.gitignore b/.gitignore
index e2a2f5607a..42e24fe416 100644
--- a/.gitignore
+++ b/.gitignore
@@ -141,7 +141,6 @@ test-*.trs
/src/libnm-core-public/nm-version-macros.h
/src/libnm-core-public/nm-dbus-types.xml
/src/libnm-core-public/nm-vpn-dbus-types.xml
-/src/libnm-core-impl/tests/test-compare
/src/libnm-core-impl/tests/test-crypto
/src/libnm-core-impl/tests/test-settings-defaults
/src/libnm-core-impl/tests/test-general
@@ -439,6 +438,7 @@ test-*.trs
/src/initrd/tests/test-dt-reader
/src/initrd/tests/test-ibft-reader
/src/libnm-client-impl/nm-settings-docs-gir.xml
+/src/libnm-core-impl/tests/test-compare
/src/ndisc/tests/test-ndisc-fake
/src/ndisc/tests/test-ndisc-linux
/src/nm-daemon-helper/nm-daemon-helper
diff --git a/Makefile.am b/Makefile.am
index f83cf25bd7..4a4ea61628 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1320,7 +1320,6 @@ src_libnm_core_public_mkenums_h = \
src_libnm_core_impl_lib_h_priv = \
src/libnm-core-impl/nm-connection-private.h \
src/libnm-core-impl/nm-default-libnm-core.h \
- src/libnm-core-impl/nm-property-compare.h \
src/libnm-core-impl/nm-setting-private.h \
src/libnm-core-impl/nm-team-utils.h \
src/libnm-core-impl/nm-utils-private.h \
@@ -1396,7 +1395,6 @@ src_libnm_core_impl_lib_c_real = \
src/libnm-core-impl/nm-keyfile-utils.c \
src/libnm-core-impl/nm-keyfile.c \
src/libnm-core-impl/nm-meta-setting-base-impl.c \
- src/libnm-core-impl/nm-property-compare.c \
src/libnm-core-impl/nm-setting.c \
src/libnm-core-impl/nm-simple-connection.c \
src/libnm-core-impl/nm-team-utils.c \
@@ -1602,7 +1600,6 @@ EXTRA_DIST += \
###############################################################################
check_programs += \
- src/libnm-core-impl/tests/test-compare \
src/libnm-core-impl/tests/test-crypto \
src/libnm-core-impl/tests/test-general \
src/libnm-core-impl/tests/test-keyfile \
@@ -1631,7 +1628,6 @@ src_libnm_core_impl_tests_cppflags = \
$(SANITIZER_EXEC_CFLAGS) \
$(NULL)
-src_libnm_core_impl_tests_test_compare_CPPFLAGS = $(src_libnm_core_impl_tests_cppflags)
src_libnm_core_impl_tests_test_crypto_CPPFLAGS = $(src_libnm_core_impl_tests_cppflags)
src_libnm_core_impl_tests_test_general_CPPFLAGS = $(src_libnm_core_impl_tests_cppflags)
src_libnm_core_impl_tests_test_keyfile_CPPFLAGS = $(src_libnm_core_impl_tests_cppflags)
@@ -1668,7 +1664,6 @@ src_libnm_core_impl_tests_ldflags = \
$(SANITIZER_EXEC_LDFLAGS) \
$(NULL)
-src_libnm_core_impl_tests_test_compare_LDADD = $(src_libnm_core_impl_tests_ldadd)
src_libnm_core_impl_tests_test_crypto_LDADD = $(src_libnm_core_impl_tests_ldadd)
src_libnm_core_impl_tests_test_general_LDADD = $(src_libnm_core_impl_tests_ldadd)
src_libnm_core_impl_tests_test_keyfile_LDADD = $(src_libnm_core_impl_tests_ldadd)
@@ -1676,7 +1671,6 @@ src_libnm_core_impl_tests_test_secrets_LDADD = $(src_libnm_core_impl_tests_ldadd
src_libnm_core_impl_tests_test_setting_LDADD = $(src_libnm_core_impl_tests_ldadd)
src_libnm_core_impl_tests_test_settings_defaults_LDADD = $(src_libnm_core_impl_tests_ldadd)
-src_libnm_core_impl_tests_test_compare_LDFLAGS = $(src_libnm_core_impl_tests_ldflags)
src_libnm_core_impl_tests_test_crypto_LDFLAGS = $(src_libnm_core_impl_tests_ldflags)
src_libnm_core_impl_tests_test_general_LDFLAGS = $(src_libnm_core_impl_tests_ldflags)
src_libnm_core_impl_tests_test_keyfile_LDFLAGS = $(src_libnm_core_impl_tests_ldflags)
@@ -1684,7 +1678,6 @@ src_libnm_core_impl_tests_test_secrets_LDFLAGS = $(src_libnm_core_impl_tests_ldf
src_libnm_core_impl_tests_test_setting_LDFLAGS = $(src_libnm_core_impl_tests_ldflags)
src_libnm_core_impl_tests_test_settings_defaults_LDFLAGS = $(src_libnm_core_impl_tests_ldflags)
-$(src_libnm_core_impl_tests_test_compare_OBJECTS): $(src_libnm_core_public_mkenums_h)
$(src_libnm_core_impl_tests_test_crypto_OBJECTS): $(src_libnm_core_public_mkenums_h)
$(src_libnm_core_impl_tests_test_general_OBJECTS): $(src_libnm_core_public_mkenums_h)
$(src_libnm_core_impl_tests_test_keyfile_OBJECTS): $(src_libnm_core_public_mkenums_h)
diff --git a/docs/libnm/Makefile.am b/docs/libnm/Makefile.am
index 7a10848f0a..87ab81cc9c 100644
--- a/docs/libnm/Makefile.am
+++ b/docs/libnm/Makefile.am
@@ -52,7 +52,6 @@ IGNORE_HFILES= \
\
nm-connection-private.h \
nm-default-libnm-core.h \
- nm-property-compare.h \
nm-setting-private.h \
nm-team-utils.h \
nm-utils-private.h \
diff --git a/docs/libnm/meson.build b/docs/libnm/meson.build
index fcc4611dcc..faac586d3c 100644
--- a/docs/libnm/meson.build
+++ b/docs/libnm/meson.build
@@ -15,7 +15,6 @@ private_headers = [
'nm-connection-private.h',
'nm-default-libnm-core.h',
- 'nm-property-compare.h',
'nm-setting-private.h',
'nm-team-utils.h',
'nm-utils-private.h',
diff --git a/src/libnm-core-impl/meson.build b/src/libnm-core-impl/meson.build
index d6cf950557..e1f11f323f 100644
--- a/src/libnm-core-impl/meson.build
+++ b/src/libnm-core-impl/meson.build
@@ -68,7 +68,6 @@ libnm_core_impl_sources = files(
'nm-keyfile-utils.c',
'nm-keyfile.c',
'nm-meta-setting-base-impl.c',
- 'nm-property-compare.c',
'nm-setting.c',
'nm-simple-connection.c',
'nm-team-utils.c',
diff --git a/src/libnm-core-impl/nm-property-compare.c b/src/libnm-core-impl/nm-property-compare.c
deleted file mode 100644
index 6273e90bc3..0000000000
--- a/src/libnm-core-impl/nm-property-compare.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2007 - 2014 Red Hat, Inc.
- * Copyright (C) 2007 - 2008 Novell, Inc.
- */
-
-#include "libnm-core-impl/nm-default-libnm-core.h"
-
-#include "nm-property-compare.h"
-
-#include <netinet/in.h>
-
-static int
-_nm_property_compare_collection(GVariant *value1, GVariant *value2)
-{
- GVariant *child1, *child2;
- int i, len1, len2;
- int ret;
-
- len1 = g_variant_n_children(value1);
- len2 = g_variant_n_children(value2);
-
- if (len1 != len2)
- return len1 < len2 ? -1 : len1 > len2;
-
- for (i = 0; i < len1; i++) {
- child1 = g_variant_get_child_value(value1, i);
- child2 = g_variant_get_child_value(value2, i);
-
- ret = nm_property_compare(child1, child2);
- g_variant_unref(child1);
- g_variant_unref(child2);
-
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static int
-_nm_property_compare_vardict(GVariant *value1, GVariant *value2)
-{
- GVariantIter iter;
- int len1, len2;
- const char *key;
- GVariant *val1, *val2;
-
- len1 = g_variant_n_children(value1);
- len2 = g_variant_n_children(value2);
-
- if (len1 != len2)
- return len1 < len2 ? -1 : 1;
-
- g_variant_iter_init(&iter, value1);
- while (g_variant_iter_next(&iter, "{&sv}", &key, &val1)) {
- if (!g_variant_lookup(value2, key, "v", &val2)) {
- g_variant_unref(val1);
- return -1;
- }
- if (!g_variant_equal(val1, val2)) {
- g_variant_unref(val1);
- g_variant_unref(val2);
- return -1;
- }
- g_variant_unref(val1);
- g_variant_unref(val2);
- }
-
- return 0;
-}
-
-static int
-_nm_property_compare_strdict(GVariant *value1, GVariant *value2)
-{
- GVariantIter iter;
- int len1, len2;
- const char *key, *val1, *val2;
- int ret;
-
- len1 = g_variant_n_children(value1);
- len2 = g_variant_n_children(value2);
-
- if (len1 != len2)
- return len1 < len2 ? -1 : len1 > len2;
-
- g_variant_iter_init(&iter, value1);
- while (g_variant_iter_next(&iter, "{&s&s}", &key, &val1)) {
- if (!g_variant_lookup(value2, key, "&s", &val2))
- return -1;
-
- ret = strcmp(val1, val2);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-int
-nm_property_compare(GVariant *value1, GVariant *value2)
-{
- const GVariantType *type1;
- const GVariantType *type2;
- int ret;
-
- if (value1 == value2)
- return 0;
- if (!value1)
- return 1;
- if (!value2)
- return -1;
-
- type1 = g_variant_get_type(value1);
- type2 = g_variant_get_type(value2);
-
- if (!g_variant_type_equal(type1, type2))
- return type1 < type2 ? -1 : type1 > type2;
-
- if (g_variant_type_is_basic(type1))
- ret = g_variant_compare(value1, value2);
- else if (g_variant_is_of_type(value1, G_VARIANT_TYPE("a{ss}")))
- ret = _nm_property_compare_strdict(value1, value2);
- else if (g_variant_is_of_type(value1, G_VARIANT_TYPE("a{sv}")))
- ret = _nm_property_compare_vardict(value1, value2);
- else if (g_variant_type_is_array(type1))
- ret = _nm_property_compare_collection(value1, value2);
- else if (g_variant_type_is_tuple(type1))
- ret = _nm_property_compare_collection(value1, value2);
- else {
- g_warning("Don't know how to compare variant type '%s'", (const char *) type1);
- ret = value1 == value2;
- }
-
- return ret;
-}
diff --git a/src/libnm-core-impl/nm-property-compare.h b/src/libnm-core-impl/nm-property-compare.h
deleted file mode 100644
index 7444400d7c..0000000000
--- a/src/libnm-core-impl/nm-property-compare.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2007 - 2014 Red Hat, Inc.
- * Copyright (C) 2007 - 2008 Novell, Inc.
- */
-
-#ifndef __NM_PROPERTY_COMPARE_H__
-#define __NM_PROPERTY_COMPARE_H__
-
-#if !((NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_PRIVATE)
-#error Cannot use this header.
-#endif
-
-int nm_property_compare(GVariant *value1, GVariant *value2);
-
-#endif /* __NM_PROPERTY_COMPARE_H__ */
diff --git a/src/libnm-core-impl/nm-setting.c b/src/libnm-core-impl/nm-setting.c
index fdb2b1299d..455abcb95d 100644
--- a/src/libnm-core-impl/nm-setting.c
+++ b/src/libnm-core-impl/nm-setting.c
@@ -11,7 +11,6 @@
#include "libnm-core-intern/nm-core-internal.h"
#include "libnm-glib-aux/nm-ref-string.h"
#include "libnm-glib-aux/nm-secret-utils.h"
-#include "nm-property-compare.h"
#include "nm-setting-private.h"
#include "nm-utils-private.h"
#include "nm-utils.h"
@@ -2653,7 +2652,7 @@ _nm_setting_property_compare_fcn_default(_NM_SETT_INFO_PROP_COMPARE_FCN_ARGS _nm
NM_CONNECTION_SERIALIZE_ALL,
NULL,
TRUE);
- return nm_property_compare(value1, value2) == 0;
+ return nm_g_variant_equal(value1, value2);
}
}
diff --git a/src/libnm-core-impl/tests/meson.build b/src/libnm-core-impl/tests/meson.build
index 988c60db86..80b588274e 100644
--- a/src/libnm-core-impl/tests/meson.build
+++ b/src/libnm-core-impl/tests/meson.build
@@ -8,7 +8,6 @@ enum_sources = gnome.mkenums_simple(
)
test_units = [
- 'test-compare',
'test-crypto',
'test-general',
'test-keyfile',
diff --git a/src/libnm-core-impl/tests/test-compare.c b/src/libnm-core-impl/tests/test-compare.c
deleted file mode 100644
index 77d2e17b68..0000000000
--- a/src/libnm-core-impl/tests/test-compare.c
+++ /dev/null
@@ -1,231 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2007 - 2014 Red Hat, Inc.
- * Copyright (C) 2007 - 2008 Novell, Inc.
- */
-
-#include "libnm-core-impl/nm-default-libnm-core.h"
-
-#include <arpa/inet.h>
-#include <netinet/in.h>
-
-#include "nm-property-compare.h"
-
-#include "libnm-glib-aux/nm-test-utils.h"
-
-static void
-compare_ints(void)
-{
- GVariant *value1, *value2;
-
- value1 = g_variant_new_int32(5);
- value2 = g_variant_new_int32(5);
- g_assert(nm_property_compare(value1, value2) == 0);
-
- g_variant_unref(value2);
- value2 = g_variant_new_int32(10);
- g_assert(nm_property_compare(value1, value2) < 0);
-
- g_variant_unref(value2);
- value2 = g_variant_new_int32(-1);
- g_assert(nm_property_compare(value1, value2) > 0);
-
- g_variant_unref(value1);
- g_variant_unref(value2);
-}
-
-static void
-compare_strings(void)
-{
- GVariant *value1, *value2;
- const char *str1 = "hello";
- const char *str2 = "world";
-
- value1 = g_variant_new_string(str1);
- value2 = g_variant_new_string(str1);
- g_assert(nm_property_compare(value1, value2) == 0);
-
- g_variant_unref(value2);
- value2 = g_variant_new_string(str2);
- g_assert(nm_property_compare(value1, value2) < 0);
-
- g_assert(nm_property_compare(value2, value1) > 0);
-
- g_variant_unref(value1);
- g_variant_unref(value2);
-}
-
-static void
-compare_strv(void)
-{
- GVariant *value1, *value2;
- const char *const strv1[] = {"foo", "bar", "baz", NULL};
- const char *const strv2[] = {"foo", "bar", "bar", NULL};
- const char *const strv3[] = {"foo", "bar", NULL};
- const char *const strv4[] = {"foo", "bar", "baz", "bam", NULL};
-
- value1 = g_variant_new_strv(strv1, -1);
- value2 = g_variant_new_strv(strv1, -1);
- g_assert(nm_property_compare(value1, value2) == 0);
-
- g_variant_unref(value2);
- value2 = g_variant_new_strv(strv2, -1);
- g_assert(nm_property_compare(value1, value2) != 0);
-
- g_variant_unref(value2);
- value2 = g_variant_new_strv(strv3, -1);
- g_assert(nm_property_compare(value1, value2) != 0);
-
- g_variant_unref(value2);
- value2 = g_variant_new_strv(strv4, -1);
- g_assert(nm_property_compare(value1, value2) != 0);
-
- g_variant_unref(value1);
- g_variant_unref(value2);
-}
-
-static void
-compare_arrays(void)
-{
- GVariant *value1, *value2;
- guint32 array[] = {0, 1, 2, 3, 4};
-
- value1 = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
- array,
- G_N_ELEMENTS(array),
- sizeof(guint32));
- value2 = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
- array,
- G_N_ELEMENTS(array),
- sizeof(guint32));
-
- g_assert(nm_property_compare(value1, value2) == 0);
-
- g_variant_unref(value2);
- value2 = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
- array + 1,
- G_N_ELEMENTS(array) - 1,
- sizeof(guint32));
- g_assert(nm_property_compare(value1, value2) != 0);
-
- array[0] = 7;
- g_variant_unref(value2);
- value2 = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
- array,
- G_N_ELEMENTS(array),
- sizeof(guint32));
- g_assert(nm_property_compare(value1, value2) != 0);
-
- g_variant_unref(value1);
- g_variant_unref(value2);
-}
-
-static void
-compare_str_hash(void)
-{
- GVariant *value1, *value2;
- GVariantBuilder builder;
-
- g_variant_builder_init(&builder, G_VARIANT_TYPE("a{ss}"));
- g_variant_builder_add(&builder, "{ss}", "key1", "hello");
- g_variant_builder_add(&builder, "{ss}", "key2", "world");
- g_variant_builder_add(&builder, "{ss}", "key3", "!");
- value1 = g_variant_builder_end(&builder);
-
- g_variant_builder_init(&builder, G_VARIANT_TYPE("a{ss}"));
- g_variant_builder_add(&builder, "{ss}", "key3", "!");
- g_variant_builder_add(&builder, "{ss}", "key2", "world");
- g_variant_builder_add(&builder, "{ss}", "key1", "hello");
- value2 = g_variant_builder_end(&builder);
-
- g_assert(nm_property_compare(value1, value2) == 0);
-
- g_variant_unref(value2);
- g_variant_builder_init(&builder, G_VARIANT_TYPE("a{ss}"));
- g_variant_builder_add(&builder, "{ss}", "key1", "hello");
- g_variant_builder_add(&builder, "{ss}", "key3", "!");
- value2 = g_variant_builder_end(&builder);
-
- g_assert(nm_property_compare(value1, value2) != 0);
- g_assert(nm_property_compare(value2, value1) != 0);
-
- g_variant_unref(value2);
- g_variant_builder_init(&builder, G_VARIANT_TYPE("a{ss}"));
- g_variant_builder_add(&builder, "{ss}", "key1", "hello");
- g_variant_builder_add(&builder, "{ss}", "key2", "moon");
- g_variant_builder_add(&builder, "{ss}", "key3", "!");
- value2 = g_variant_builder_end(&builder);
-
- g_assert(nm_property_compare(value1, value2) != 0);
-
- g_variant_unref(value1);
- g_variant_unref(value2);
-}
-
-static void
-compare_ip6_addresses(void)
-{
- GVariant *value1, *value2;
- struct in6_addr addr1;
- struct in6_addr addr2;
- struct in6_addr addr3;
- guint32 prefix1 = 64;
- guint32 prefix2 = 64;
- guint32 prefix3 = 0;
-
- inet_pton(AF_INET6, "1:2:3:4:5:6:7:8", &addr1);
- inet_pton(AF_INET6, "ffff:2:3:4:5:6:7:8", &addr2);
- inet_pton(AF_INET6, "::", &addr3);
-
- value1 = g_variant_new(
- "(@ayu@ay)",
- g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, (guint8 *) addr1.s6_addr, 16, 1),
- prefix1,
- g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, (guint8 *) addr3.s6_addr, 16, 1));
-
- value2 = g_variant_new(
- "(@ayu@ay)",
- g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, (guint8 *) addr1.s6_addr, 16, 1),
- prefix1,
- g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, (guint8 *) addr3.s6_addr, 16, 1));
-
- g_assert(nm_property_compare(value1, value2) == 0);
-
- g_variant_unref(value2);
- value2 = g_variant_new(
- "(@ayu@ay)",
- g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, (guint8 *) addr2.s6_addr, 16, 1),
- prefix2,
- g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, (guint8 *) addr3.s6_addr, 16, 1));
-
- g_assert(nm_property_compare(value1, value2) != 0);
-
- g_variant_unref(value2);
- value2 = g_variant_new(
- "(@ayu@ay)",
- g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, (guint8 *) addr3.s6_addr, 16, 1),
- prefix3,
- g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, (guint8 *) addr3.s6_addr, 16, 1));
-
- g_assert(nm_property_compare(value1, value2) != 0);
-
- g_variant_unref(value1);
- g_variant_unref(value2);
-}
-
-NMTST_DEFINE();
-
-int
-main(int argc, char *argv[])
-{
- nmtst_init(&argc, &argv, TRUE);
-
- g_test_add_func("/libnm/compare/ints", compare_ints);
- g_test_add_func("/libnm/compare/strings", compare_strings);
- g_test_add_func("/libnm/compare/strv", compare_strv);
- g_test_add_func("/libnm/compare/arrays", compare_arrays);
- g_test_add_func("/libnm/compare/str_hash", compare_str_hash);
- g_test_add_func("/libnm/compare/ip6_addresses", compare_ip6_addresses);
-
- return g_test_run();
-}
diff --git a/src/libnm-glib-aux/nm-shared-utils.c b/src/libnm-glib-aux/nm-shared-utils.c
index f8620279b3..7d623bd9d3 100644
--- a/src/libnm-glib-aux/nm-shared-utils.c
+++ b/src/libnm-glib-aux/nm-shared-utils.c
@@ -623,6 +623,149 @@ nm_g_variant_maybe_singleton_i(gint32 value)
/*****************************************************************************/
+static int
+_variant_type_cmp(const GVariantType *type1, const GVariantType *type2)
+{
+ const char *string1;
+ const char *string2;
+ gsize size;
+
+ NM_CMP_SELF(type1, type2);
+
+ size = g_variant_type_get_string_length(type1);
+
+ NM_CMP_DIRECT(size, g_variant_type_get_string_length(type2));
+
+ string1 = g_variant_type_peek_string(type1);
+ string2 = g_variant_type_peek_string(type2);
+
+ NM_CMP_DIRECT_MEMCMP(string1, string2, size);
+ return 0;
+}
+
+int
+nm_g_variant_type_cmp(const GVariantType *type1, const GVariantType *type2)
+{
+ int r;
+
+ r = _variant_type_cmp(type1, type2);
+ nm_assert((!!g_variant_type_equal(type1, type2)) == (r == 0));
+ return r;
+}
+
+/*****************************************************************************/
+
+typedef enum {
+ VARIANT_CMP_TYPE_VARIANT,
+ VARIANT_CMP_TYPE_STRDICT,
+ VARIANT_CMP_TYPE_VARDICT,
+} VariantCmpType;
+
+static int
+_variant_cmp_array(GVariant *value1, GVariant *value2, VariantCmpType type)
+{
+ gsize len;
+ gsize i;
+
+ len = g_variant_n_children(value1);
+
+ NM_CMP_DIRECT(len, g_variant_n_children(value2));
+
+ for (i = 0; i < len; i++) {
+ gs_unref_variant GVariant *child1 = g_variant_get_child_value(value1, i);
+ gs_unref_variant GVariant *child2 = g_variant_get_child_value(value2, i);
+ const char *key1;
+ const char *key2;
+ const char *val1_str;
+ const char *val2_str;
+
+ nm_assert(child1);
+ nm_assert(child2);
+
+ switch (type) {
+ case VARIANT_CMP_TYPE_VARIANT:
+ NM_CMP_RETURN(nm_g_variant_cmp(child1, child2));
+ break;
+ case VARIANT_CMP_TYPE_STRDICT:
+ g_variant_get(child1, "{&s&s}", &key1, &val1_str);
+ g_variant_get(child2, "{&s&s}", &key2, &val2_str);
+ NM_CMP_DIRECT_STRCMP(key1, key2);
+ NM_CMP_DIRECT_STRCMP(val1_str, val2_str);
+ break;
+ case VARIANT_CMP_TYPE_VARDICT:
+ {
+ gs_unref_variant GVariant *val1_var = NULL;
+ gs_unref_variant GVariant *val2_var = NULL;
+
+ g_variant_get(child1, "{&sv}", &key1, &val1_var);
+ g_variant_get(child2, "{&sv}", &key2, &val2_var);
+ NM_CMP_DIRECT_STRCMP(key1, key2);
+ NM_CMP_RETURN(nm_g_variant_cmp(val1_var, val2_var));
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int
+_variant_cmp_generic(GVariant *value1, GVariant *value2)
+{
+ gs_free char *str1 = NULL;
+ gs_free char *str2 = NULL;
+
+ /* This is like g_variant_equal(), which also resorts to pretty-printing
+ * the variants for comparison.
+ *
+ * Note that the variant types are already checked and equal. We thus don't
+ * need to include the type annotation. */
+ str1 = g_variant_print(value1, FALSE);
+ str2 = g_variant_print(value2, FALSE);
+
+ NM_CMP_DIRECT_STRCMP(str1, str2);
+ return 0;
+}
+
+static int
+_variant_cmp(GVariant *value1, GVariant *value2)
+{
+ const GVariantType *type;
+
+ NM_CMP_SELF(value1, value2);
+
+ type = g_variant_get_type(value1);
+
+ NM_CMP_RETURN(nm_g_variant_type_cmp(type, g_variant_get_type(value2)));
+
+ if (g_variant_type_is_basic(type))
+ NM_CMP_RETURN(g_variant_compare(value1, value2));
+ else if (g_variant_type_is_subtype_of(type, G_VARIANT_TYPE("a{ss}")))
+ NM_CMP_RETURN(_variant_cmp_array(value1, value2, VARIANT_CMP_TYPE_STRDICT));
+ else if (g_variant_type_is_subtype_of(type, G_VARIANT_TYPE("a{sv}")))
+ NM_CMP_RETURN(_variant_cmp_array(value1, value2, VARIANT_CMP_TYPE_VARDICT));
+ else if (g_variant_type_is_array(type) || g_variant_type_is_tuple(type))
+ NM_CMP_RETURN(_variant_cmp_array(value1, value2, VARIANT_CMP_TYPE_VARIANT));
+ else
+ NM_CMP_RETURN(_variant_cmp_generic(value1, value2));
+
+ return 0;
+}
+
+int
+nm_g_variant_cmp(GVariant *value1, GVariant *value2)
+{
+ int r;
+
+ r = _variant_cmp(value1, value2);
+
+ nm_assert((!!nm_g_variant_equal(value1, value2)) == (r == 0));
+
+ return r;
+}
+
+/*****************************************************************************/
+
GHashTable *
nm_strdict_clone(GHashTable *src)
{
diff --git a/src/libnm-glib-aux/nm-shared-utils.h b/src/libnm-glib-aux/nm-shared-utils.h
index b0ce25a568..ea38e083cd 100644
--- a/src/libnm-glib-aux/nm-shared-utils.h
+++ b/src/libnm-glib-aux/nm-shared-utils.h
@@ -1418,6 +1418,10 @@ nm_g_variant_builder_add_sv_str(GVariantBuilder *builder, const char *key, const
nm_g_variant_builder_add_sv(builder, key, g_variant_new_string(str));
}
+int nm_g_variant_type_cmp(const GVariantType *type1, const GVariantType *type2);
+
+int nm_g_variant_cmp(GVariant *value1, GVariant *value2);
+
static inline void
nm_g_source_destroy_and_unref(GSource *source)
{
diff --git a/src/libnm-glib-aux/tests/test-shared-general.c b/src/libnm-glib-aux/tests/test-shared-general.c
index e65c0efc1d..b19ac1ce52 100644
--- a/src/libnm-glib-aux/tests/test-shared-general.c
+++ b/src/libnm-glib-aux/tests/test-shared-general.c
@@ -2630,6 +2630,224 @@ test_uid_to_name(void)
/*****************************************************************************/
+static void
+compare_ints(void)
+{
+ GVariant *value1, *value2;
+
+ value1 = g_variant_new_int32(5);
+ value2 = g_variant_new_int32(5);
+ g_assert(nm_g_variant_cmp(value1, value2) == 0);
+
+ g_variant_unref(value2);
+ value2 = g_variant_new_int32(10);
+ g_assert(nm_g_variant_cmp(value1, value2) < 0);
+
+ g_variant_unref(value2);
+ value2 = g_variant_new_int32(-1);
+ g_assert(nm_g_variant_cmp(value1, value2) > 0);
+
+ g_variant_unref(value1);
+ g_variant_unref(value2);
+}
+
+static void
+compare_strings(void)
+{
+ GVariant *value1, *value2;
+ const char *str1 = "hello";
+ const char *str2 = "world";
+
+ value1 = g_variant_new_string(str1);
+ value2 = g_variant_new_string(str1);
+ g_assert(nm_g_variant_cmp(value1, value2) == 0);
+
+ g_variant_unref(value2);
+ value2 = g_variant_new_string(str2);
+ g_assert(nm_g_variant_cmp(value1, value2) < 0);
+
+ g_assert(nm_g_variant_cmp(value2, value1) > 0);
+
+ g_variant_unref(value1);
+ g_variant_unref(value2);
+}
+
+static void
+compare_strv(void)
+{
+ GVariant *value1, *value2;
+ const char *const strv1[] = {"foo", "bar", "baz", NULL};
+ const char *const strv2[] = {"foo", "bar", "bar", NULL};
+ const char *const strv3[] = {"foo", "bar", NULL};
+ const char *const strv4[] = {"foo", "bar", "baz", "bam", NULL};
+
+ value1 = g_variant_new_strv(strv1, -1);
+ value2 = g_variant_new_strv(strv1, -1);
+ g_assert(nm_g_variant_cmp(value1, value2) == 0);
+
+ g_variant_unref(value2);
+ value2 = g_variant_new_strv(strv2, -1);
+ g_assert(nm_g_variant_cmp(value1, value2) != 0);
+
+ g_variant_unref(value2);
+ value2 = g_variant_new_strv(strv3, -1);
+ g_assert(nm_g_variant_cmp(value1, value2) != 0);
+
+ g_variant_unref(value2);
+ value2 = g_variant_new_strv(strv4, -1);
+ g_assert(nm_g_variant_cmp(value1, value2) != 0);
+
+ g_variant_unref(value1);
+ g_variant_unref(value2);
+}
+
+static void
+compare_arrays(void)
+{
+ GVariant *value1, *value2;
+ guint32 array[] = {0, 1, 2, 3, 4};
+
+ value1 = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
+ array,
+ G_N_ELEMENTS(array),
+ sizeof(guint32));
+ value2 = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
+ array,
+ G_N_ELEMENTS(array),
+ sizeof(guint32));
+
+ g_assert(nm_g_variant_cmp(value1, value2) == 0);
+
+ g_variant_unref(value2);
+ value2 = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
+ array + 1,
+ G_N_ELEMENTS(array) - 1,
+ sizeof(guint32));
+ g_assert(nm_g_variant_cmp(value1, value2) != 0);
+
+ array[0] = 7;
+ g_variant_unref(value2);
+ value2 = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
+ array,
+ G_N_ELEMENTS(array),
+ sizeof(guint32));
+ g_assert(nm_g_variant_cmp(value1, value2) != 0);
+
+ g_variant_unref(value1);
+ g_variant_unref(value2);
+}
+
+static void
+compare_str_hash(void)
+{
+ GVariant *value1, *value2;
+ GVariantBuilder builder;
+
+ g_variant_builder_init(&builder, G_VARIANT_TYPE("a{ss}"));
+ g_variant_builder_add(&builder, "{ss}", "key1", "hello");
+ g_variant_builder_add(&builder, "{ss}", "key2", "world");
+ g_variant_builder_add(&builder, "{ss}", "key3", "!");
+ value1 = g_variant_builder_end(&builder);
+
+ g_variant_builder_init(&builder, G_VARIANT_TYPE("a{ss}"));
+ g_variant_builder_add(&builder, "{ss}", "key3", "!");
+ g_variant_builder_add(&builder, "{ss}", "key2", "world");
+ g_variant_builder_add(&builder, "{ss}", "key1", "hello");
+ value2 = g_variant_builder_end(&builder);
+
+ g_assert(nm_g_variant_cmp(value1, value2) != 0);
+
+ g_variant_unref(value1);
+ g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}"));
+ g_variant_builder_add(&builder, "{sv}", "key1", g_variant_new_string("hello"));
+ g_variant_builder_add(&builder, "{sv}", "key2", g_variant_new_string("world"));
+ g_variant_builder_add(&builder, "{sv}", "key3", g_variant_new_string("!"));
+ value1 = g_variant_builder_end(&builder);
+
+ g_variant_unref(value2);
+ g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}"));
+ g_variant_builder_add(&builder, "{sv}", "key1", g_variant_new_string("hello"));
+ g_variant_builder_add(&builder, "{sv}", "key2", g_variant_new_string("world"));
+ g_variant_builder_add(&builder, "{sv}", "key3", g_variant_new_string("!"));
+ value2 = g_variant_builder_end(&builder);
+
+ g_assert(nm_g_variant_cmp(value1, value2) == 0);
+
+ g_variant_unref(value2);
+ g_variant_builder_init(&builder, G_VARIANT_TYPE("a{ss}"));
+ g_variant_builder_add(&builder, "{ss}", "key1", "hello");
+ g_variant_builder_add(&builder, "{ss}", "key3", "!");
+ value2 = g_variant_builder_end(&builder);
+
+ g_assert(nm_g_variant_cmp(value1, value2) != 0);
+ g_assert(nm_g_variant_cmp(value2, value1) != 0);
+
+ g_variant_unref(value2);
+ g_variant_builder_init(&builder, G_VARIANT_TYPE("a{ss}"));
+ g_variant_builder_add(&builder, "{ss}", "key1", "hello");
+ g_variant_builder_add(&builder, "{ss}", "key2", "moon");
+ g_variant_builder_add(&builder, "{ss}", "key3", "!");
+ value2 = g_variant_builder_end(&builder);
+
+ g_assert(nm_g_variant_cmp(value1, value2) != 0);
+
+ g_variant_unref(value1);
+ g_variant_unref(value2);
+}
+
+static void
+compare_ip6_addresses(void)
+{
+ GVariant *value1, *value2;
+ struct in6_addr addr1;
+ struct in6_addr addr2;
+ struct in6_addr addr3;
+ guint32 prefix1 = 64;
+ guint32 prefix2 = 64;
+ guint32 prefix3 = 0;
+
+ inet_pton(AF_INET6, "1:2:3:4:5:6:7:8", &addr1);
+ inet_pton(AF_INET6, "ffff:2:3:4:5:6:7:8", &addr2);
+ inet_pton(AF_INET6, "::", &addr3);
+
+ value1 = g_variant_new(
+ "(@ayu@ay)",
+ g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, (guint8 *) addr1.s6_addr, 16, 1),
+ prefix1,
+ g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, (guint8 *) addr3.s6_addr, 16, 1));
+
+ value2 = g_variant_new(
+ "(@ayu@ay)",
+ g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, (guint8 *) addr1.s6_addr, 16, 1),
+ prefix1,
+ g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, (guint8 *) addr3.s6_addr, 16, 1));
+
+ g_assert(nm_g_variant_cmp(value1, value2) == 0);
+
+ g_variant_unref(value2);
+ value2 = g_variant_new(
+ "(@ayu@ay)",
+ g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, (guint8 *) addr2.s6_addr, 16, 1),
+ prefix2,
+ g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, (guint8 *) addr3.s6_addr, 16, 1));
+
+ g_assert(nm_g_variant_cmp(value1, value2) != 0);
+
+ g_variant_unref(value2);
+ value2 = g_variant_new(
+ "(@ayu@ay)",
+ g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, (guint8 *) addr3.s6_addr, 16, 1),
+ prefix3,
+ g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, (guint8 *) addr3.s6_addr, 16, 1));
+
+ g_assert(nm_g_variant_cmp(value1, value2) != 0);
+
+ g_variant_unref(value1);
+ g_variant_unref(value2);
+}
+
+/*****************************************************************************/
+
NMTST_DEFINE();
int
@@ -2683,5 +2901,12 @@ main(int argc, char **argv)
g_test_add_func("/general/test_nm_random", test_nm_random);
g_test_add_func("/general/test_uid_to_name", test_uid_to_name);
+ g_test_add_func("/libnm/compare/ints", compare_ints);
+ g_test_add_func("/libnm/compare/strings", compare_strings);
+ g_test_add_func("/libnm/compare/strv", compare_strv);
+ g_test_add_func("/libnm/compare/arrays", compare_arrays);
+ g_test_add_func("/libnm/compare/str_hash", compare_str_hash);
+ g_test_add_func("/libnm/compare/ip6_addresses", compare_ip6_addresses);
+
return g_test_run();
}