mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-07 17:10:21 +01:00
1133 lines
34 KiB
C
1133 lines
34 KiB
C
// SPDX-License-Identifier: LGPL-2.1+
|
|
/*
|
|
* Copyright (C) 2018 Red Hat, Inc.
|
|
*/
|
|
|
|
#define NM_TEST_UTILS_NO_LIBNM 1
|
|
|
|
#include "nm-default.h"
|
|
|
|
#include "nm-std-aux/unaligned.h"
|
|
#include "nm-glib-aux/nm-random-utils.h"
|
|
#include "nm-glib-aux/nm-str-buf.h"
|
|
#include "nm-glib-aux/nm-time-utils.h"
|
|
#include "nm-glib-aux/nm-ref-string.h"
|
|
|
|
#include "nm-utils/nm-test-utils.h"
|
|
|
|
/*****************************************************************************/
|
|
|
|
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)
|
|
{
|
|
const int *int_ptr;
|
|
GPid pid = 42;
|
|
|
|
/* We redefine G_PID_FORMAT, because it's only available since glib 2.53.5.
|
|
*
|
|
* Also, this is the format for GPid, which for glib is always a typedef
|
|
* for "int". Add a check for that here.
|
|
*
|
|
* G_PID_FORMAT is not about pid_t, which might be a smaller int, and which we would
|
|
* check with SIZEOF_PID_T. */
|
|
G_STATIC_ASSERT (sizeof (GPid) == sizeof (int));
|
|
|
|
g_assert_cmpstr (""G_PID_FORMAT, ==, "i");
|
|
|
|
/* check that it's really "int". We will get a compiler warning, if that's not
|
|
* the case. */
|
|
int_ptr = &pid;
|
|
g_assert_cmpint (*int_ptr, ==, 42);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
test_monotonic_timestamp (void)
|
|
{
|
|
g_assert (nm_utils_get_monotonic_timestamp_sec () > 0);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
test_nmhash (void)
|
|
{
|
|
int rnd;
|
|
|
|
nm_utils_random_bytes (&rnd, sizeof (rnd));
|
|
|
|
g_assert (nm_hash_val (555, 4) != 0);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static const char *
|
|
_make_strv_foo (void)
|
|
{
|
|
return "foo";
|
|
}
|
|
|
|
static const char *const*const _tst_make_strv_1 = NM_MAKE_STRV ("1", "2");
|
|
|
|
static void
|
|
test_make_strv (void)
|
|
{
|
|
const char *const*v1a = NM_MAKE_STRV ("a");
|
|
const char *const*v1b = NM_MAKE_STRV ("a", );
|
|
const char *const*v2a = NM_MAKE_STRV ("a", "b");
|
|
const char *const*v2b = NM_MAKE_STRV ("a", "b", );
|
|
const char *const v3[] = { "a", "b", };
|
|
const char *const*v4b = NM_MAKE_STRV ("a", _make_strv_foo (), );
|
|
|
|
g_assert (NM_PTRARRAY_LEN (v1a) == 1);
|
|
g_assert (NM_PTRARRAY_LEN (v1b) == 1);
|
|
g_assert (NM_PTRARRAY_LEN (v2a) == 2);
|
|
g_assert (NM_PTRARRAY_LEN (v2b) == 2);
|
|
|
|
g_assert (NM_PTRARRAY_LEN (_tst_make_strv_1) == 2);
|
|
g_assert_cmpstr (_tst_make_strv_1[0], ==, "1");
|
|
g_assert_cmpstr (_tst_make_strv_1[1], ==, "2");
|
|
/* writing the static read-only variable leads to crash .*/
|
|
//((char **) _tst_make_strv_1)[0] = NULL;
|
|
//((char **) _tst_make_strv_1)[2] = "c";
|
|
|
|
G_STATIC_ASSERT_EXPR (G_N_ELEMENTS (v3) == 2);
|
|
|
|
g_assert (NM_PTRARRAY_LEN (v4b) == 2);
|
|
|
|
G_STATIC_ASSERT_EXPR (G_N_ELEMENTS (NM_MAKE_STRV ("a", "b" )) == 3);
|
|
G_STATIC_ASSERT_EXPR (G_N_ELEMENTS (NM_MAKE_STRV ("a", "b", )) == 3);
|
|
|
|
nm_strquote_a (300, "");
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
typedef enum {
|
|
TEST_NM_STRDUP_ENUM_m1 = -1,
|
|
TEST_NM_STRDUP_ENUM_3 = 3,
|
|
} TestNMStrdupIntEnum;
|
|
|
|
static void
|
|
test_nm_strdup_int (void)
|
|
{
|
|
#define _NM_STRDUP_INT_TEST(num, str) \
|
|
G_STMT_START { \
|
|
gs_free char *_s1 = NULL; \
|
|
\
|
|
_s1 = nm_strdup_int ((num)); \
|
|
\
|
|
g_assert (_s1); \
|
|
g_assert_cmpstr (_s1, ==, str); \
|
|
} G_STMT_END
|
|
|
|
#define _NM_STRDUP_INT_TEST_TYPED(type, num) \
|
|
G_STMT_START { \
|
|
type _num = ((type) num); \
|
|
\
|
|
_NM_STRDUP_INT_TEST (_num, G_STRINGIFY (num)); \
|
|
} G_STMT_END
|
|
|
|
_NM_STRDUP_INT_TEST_TYPED (char, 0);
|
|
_NM_STRDUP_INT_TEST_TYPED (char, 1);
|
|
_NM_STRDUP_INT_TEST_TYPED (guint8, 0);
|
|
_NM_STRDUP_INT_TEST_TYPED (gint8, 25);
|
|
_NM_STRDUP_INT_TEST_TYPED (char, 47);
|
|
_NM_STRDUP_INT_TEST_TYPED (short, 47);
|
|
_NM_STRDUP_INT_TEST_TYPED (int, 47);
|
|
_NM_STRDUP_INT_TEST_TYPED (long, 47);
|
|
_NM_STRDUP_INT_TEST_TYPED (unsigned char, 47);
|
|
_NM_STRDUP_INT_TEST_TYPED (unsigned short, 47);
|
|
_NM_STRDUP_INT_TEST_TYPED (unsigned, 47);
|
|
_NM_STRDUP_INT_TEST_TYPED (unsigned long, 47);
|
|
_NM_STRDUP_INT_TEST_TYPED (gint64, 9223372036854775807);
|
|
_NM_STRDUP_INT_TEST_TYPED (gint64, -9223372036854775807);
|
|
_NM_STRDUP_INT_TEST_TYPED (guint64, 0);
|
|
_NM_STRDUP_INT_TEST_TYPED (guint64, 9223372036854775807);
|
|
|
|
_NM_STRDUP_INT_TEST (TEST_NM_STRDUP_ENUM_m1, "-1");
|
|
_NM_STRDUP_INT_TEST (TEST_NM_STRDUP_ENUM_3, "3");
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
test_nm_strndup_a (void)
|
|
{
|
|
int run;
|
|
|
|
for (run = 0; run < 20; run++) {
|
|
gs_free char *input = NULL;
|
|
char ch;
|
|
gsize i, l;
|
|
|
|
input = g_strnfill (nmtst_get_rand_uint32 () % 20, 'x');
|
|
|
|
for (i = 0; input[i]; i++) {
|
|
while ((ch = ((char) nmtst_get_rand_uint32 ())) == '\0') {
|
|
/* repeat. */
|
|
}
|
|
input[i] = ch;
|
|
}
|
|
|
|
{
|
|
gs_free char *dup_free = NULL;
|
|
const char *dup;
|
|
|
|
l = strlen (input) + 1;
|
|
dup = nm_strndup_a (10, input, l - 1, &dup_free);
|
|
g_assert_cmpstr (dup, ==, input);
|
|
if (strlen (dup) < 10)
|
|
g_assert (!dup_free);
|
|
else
|
|
g_assert (dup == dup_free);
|
|
}
|
|
|
|
{
|
|
gs_free char *dup_free = NULL;
|
|
const char *dup;
|
|
|
|
l = nmtst_get_rand_uint32 () % 23;
|
|
dup = nm_strndup_a (10, input, l, &dup_free);
|
|
g_assert (strncmp (dup, input, l) == 0);
|
|
g_assert (strlen (dup) <= l);
|
|
if (l < 10)
|
|
g_assert (!dup_free);
|
|
else
|
|
g_assert (dup == dup_free);
|
|
if (strlen (input) < l)
|
|
g_assert (nm_utils_memeqzero (&dup[strlen (input)], l - strlen (input)));
|
|
}
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
test_nm_ip4_addr_is_localhost (void)
|
|
{
|
|
g_assert ( nm_ip4_addr_is_localhost (nmtst_inet4_from_string ("127.0.0.0")));
|
|
g_assert ( nm_ip4_addr_is_localhost (nmtst_inet4_from_string ("127.0.0.1")));
|
|
g_assert ( nm_ip4_addr_is_localhost (nmtst_inet4_from_string ("127.5.0.1")));
|
|
g_assert (!nm_ip4_addr_is_localhost (nmtst_inet4_from_string ("126.5.0.1")));
|
|
g_assert (!nm_ip4_addr_is_localhost (nmtst_inet4_from_string ("128.5.0.1")));
|
|
g_assert (!nm_ip4_addr_is_localhost (nmtst_inet4_from_string ("129.5.0.1")));
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
test_unaligned (void)
|
|
{
|
|
int shift;
|
|
|
|
for (shift = 0; shift <= 32; shift++) {
|
|
guint8 buf[100] = { };
|
|
guint8 val = 0;
|
|
|
|
while (val == 0)
|
|
val = nmtst_get_rand_uint32 () % 256;
|
|
|
|
buf[shift] = val;
|
|
|
|
g_assert_cmpint (unaligned_read_le64 (&buf[shift]), ==, (guint64) val);
|
|
g_assert_cmpint (unaligned_read_be64 (&buf[shift]), ==, ((guint64) val) << 56);
|
|
g_assert_cmpint (unaligned_read_ne64 (&buf[shift]), !=, 0);
|
|
|
|
g_assert_cmpint (unaligned_read_le32 (&buf[shift]), ==, (guint32) val);
|
|
g_assert_cmpint (unaligned_read_be32 (&buf[shift]), ==, ((guint32) val) << 24);
|
|
g_assert_cmpint (unaligned_read_ne32 (&buf[shift]), !=, 0);
|
|
|
|
g_assert_cmpint (unaligned_read_le16 (&buf[shift]), ==, (guint16) val);
|
|
g_assert_cmpint (unaligned_read_be16 (&buf[shift]), ==, ((guint16) val) << 8);
|
|
g_assert_cmpint (unaligned_read_ne16 (&buf[shift]), !=, 0);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
_strv_cmp_fuzz_input (const char *const*in,
|
|
gssize l,
|
|
const char ***out_strv_free_shallow,
|
|
char ***out_strv_free_deep,
|
|
const char *const* *out_s1,
|
|
const char *const* *out_s2)
|
|
{
|
|
const char **strv;
|
|
gsize i;
|
|
|
|
/* Fuzz the input argument. It will return two output arrays that are semantically
|
|
* equal the input. */
|
|
|
|
if (nmtst_get_rand_bool ()) {
|
|
char **ss;
|
|
|
|
if (l < 0)
|
|
ss = g_strdupv ((char **) in);
|
|
else if (l == 0) {
|
|
ss = nmtst_get_rand_bool ()
|
|
? NULL
|
|
: g_new0 (char *, 1);
|
|
} else {
|
|
ss = nm_memdup (in, sizeof (const char *) * l);
|
|
for (i = 0; i < (gsize) l; i++)
|
|
ss[i] = g_strdup (ss[i]);
|
|
}
|
|
strv = (const char **) ss;
|
|
*out_strv_free_deep = ss;
|
|
} else {
|
|
if (l < 0) {
|
|
strv = in
|
|
? nm_memdup (in, sizeof (const char *) * (NM_PTRARRAY_LEN (in) + 1))
|
|
: NULL;
|
|
} else if (l == 0) {
|
|
strv = nmtst_get_rand_bool ()
|
|
? NULL
|
|
: g_new0 (const char *, 1);
|
|
} else
|
|
strv = nm_memdup (in, sizeof (const char *) * l);
|
|
*out_strv_free_shallow = strv;
|
|
}
|
|
|
|
*out_s1 = in;
|
|
*out_s2 = strv;
|
|
|
|
if (nmtst_get_rand_bool ()) {
|
|
/* randomly swap the original and the clone. That means, out_s1 is either
|
|
* the input argument (as-is) or the sementically equal clone. */
|
|
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)
|
|
{
|
|
gssize i;
|
|
|
|
if (strv) {
|
|
if (len < 0)
|
|
g_strfreev (strv);
|
|
else {
|
|
for (i = 0; i < len; i++)
|
|
g_free (strv[i]);
|
|
g_free (strv);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
test_strv_cmp (void)
|
|
{
|
|
const char *const strv0[1] = { };
|
|
const char *const strv1[2] = { "", };
|
|
|
|
#define _STRV_CMP(a1, l1, a2, l2, equal) \
|
|
G_STMT_START { \
|
|
gssize _l1 = (l1); \
|
|
gssize _l2 = (l2); \
|
|
const char *const*_a1; \
|
|
const char *const*_a2; \
|
|
const char *const*_a1x; \
|
|
const char *const*_a2x; \
|
|
char **_a1_free_deep = NULL; \
|
|
char **_a2_free_deep = NULL; \
|
|
gs_free const char **_a1_free_shallow = NULL; \
|
|
gs_free const char **_a2_free_shallow = NULL; \
|
|
int _c1, _c2; \
|
|
\
|
|
_strv_cmp_fuzz_input ((a1), _l1, &_a1_free_shallow, &_a1_free_deep, &_a1, &_a1x); \
|
|
_strv_cmp_fuzz_input ((a2), _l2, &_a2_free_shallow, &_a2_free_deep, &_a2, &_a2x); \
|
|
\
|
|
_c1 = _nm_utils_strv_cmp_n (_a1, _l1, _a2, _l2); \
|
|
_c2 = _nm_utils_strv_cmp_n (_a2, _l2, _a1, _l1); \
|
|
if (equal) { \
|
|
g_assert_cmpint (_c1, ==, 0); \
|
|
g_assert_cmpint (_c2, ==, 0); \
|
|
} else { \
|
|
g_assert_cmpint (_c1, ==, -1); \
|
|
g_assert_cmpint (_c2, ==, 1); \
|
|
} \
|
|
\
|
|
/* Compare with self. _strv_cmp_fuzz_input() randomly swapped the arguments (_a1 and _a1x).
|
|
* Either way, the arrays must compare equal to their semantically equal alternative. */ \
|
|
g_assert_cmpint (_nm_utils_strv_cmp_n (_a1, _l1, _a1x, _l1), ==, 0); \
|
|
g_assert_cmpint (_nm_utils_strv_cmp_n (_a2, _l2, _a2x, _l2), ==, 0); \
|
|
\
|
|
_strv_cmp_free_deep (_a1_free_deep, _l1); \
|
|
_strv_cmp_free_deep (_a2_free_deep, _l2); \
|
|
} G_STMT_END
|
|
|
|
_STRV_CMP (NULL, -1, NULL, -1, TRUE);
|
|
|
|
_STRV_CMP (NULL, -1, NULL, 0, FALSE);
|
|
_STRV_CMP (NULL, -1, strv0, 0, FALSE);
|
|
_STRV_CMP (NULL, -1, strv0, -1, FALSE);
|
|
|
|
_STRV_CMP (NULL, 0, NULL, 0, TRUE);
|
|
_STRV_CMP (NULL, 0, strv0, 0, TRUE);
|
|
_STRV_CMP (NULL, 0, strv0, -1, TRUE);
|
|
_STRV_CMP (strv0, 0, strv0, 0, TRUE);
|
|
_STRV_CMP (strv0, 0, strv0, -1, TRUE);
|
|
_STRV_CMP (strv0, -1, strv0, -1, TRUE);
|
|
|
|
_STRV_CMP (NULL, 0, strv1, -1, FALSE);
|
|
_STRV_CMP (NULL, 0, strv1, 1, FALSE);
|
|
_STRV_CMP (strv0, 0, strv1, -1, FALSE);
|
|
_STRV_CMP (strv0, 0, strv1, 1, FALSE);
|
|
_STRV_CMP (strv0, -1, strv1, -1, FALSE);
|
|
_STRV_CMP (strv0, -1, strv1, 1, FALSE);
|
|
|
|
_STRV_CMP (strv1, -1, strv1, 1, TRUE);
|
|
_STRV_CMP (strv1, 1, strv1, 1, TRUE);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
_do_strstrip_avoid_copy (const char *str)
|
|
{
|
|
gs_free char *str1 = g_strdup (str);
|
|
gs_free char *str2 = g_strdup (str);
|
|
gs_free char *str3 = NULL;
|
|
gs_free char *str4 = NULL;
|
|
const char *s3;
|
|
const char *s4;
|
|
|
|
if (str1)
|
|
g_strstrip (str1);
|
|
|
|
nm_strstrip (str2);
|
|
|
|
g_assert_cmpstr (str1, ==, str2);
|
|
|
|
s3 = nm_strstrip_avoid_copy (str, &str3);
|
|
g_assert_cmpstr (str1, ==, s3);
|
|
|
|
s4 = nm_strstrip_avoid_copy_a (10, str, &str4);
|
|
g_assert_cmpstr (str1, ==, s4);
|
|
g_assert (!str == !s4);
|
|
g_assert (!s4 || strlen (s4) <= strlen (str));
|
|
if (s4 && s4 == &str[strlen (str) - strlen (s4)]) {
|
|
g_assert (!str4);
|
|
g_assert (s3 == s4);
|
|
} else if (s4 && strlen (s4) >= 10) {
|
|
g_assert (str4);
|
|
g_assert (s4 == str4);
|
|
} else
|
|
g_assert (!str4);
|
|
|
|
if (!nm_streq0 (str1, str))
|
|
_do_strstrip_avoid_copy (str1);
|
|
}
|
|
|
|
static void
|
|
test_strstrip_avoid_copy (void)
|
|
{
|
|
_do_strstrip_avoid_copy (NULL);
|
|
_do_strstrip_avoid_copy ("");
|
|
_do_strstrip_avoid_copy (" ");
|
|
_do_strstrip_avoid_copy (" a ");
|
|
_do_strstrip_avoid_copy (" 012345678 ");
|
|
_do_strstrip_avoid_copy (" 0123456789 ");
|
|
_do_strstrip_avoid_copy (" 01234567890 ");
|
|
_do_strstrip_avoid_copy (" 012345678901 ");
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
test_nm_utils_bin2hexstr (void)
|
|
{
|
|
int n_run;
|
|
|
|
for (n_run = 0; n_run < 100; n_run++) {
|
|
guint8 buf[100];
|
|
guint8 buf2[G_N_ELEMENTS (buf) + 1];
|
|
gsize len = nmtst_get_rand_uint32 () % (G_N_ELEMENTS (buf) + 1);
|
|
char strbuf1[G_N_ELEMENTS (buf) * 3];
|
|
gboolean allocate = nmtst_get_rand_bool ();
|
|
char delimiter = nmtst_get_rand_bool () ? ':' : '\0';
|
|
gboolean upper_case = nmtst_get_rand_bool ();
|
|
gsize expected_strlen;
|
|
char *str_hex;
|
|
gsize required_len;
|
|
gboolean outlen_set;
|
|
gsize outlen;
|
|
guint8 *bin2;
|
|
|
|
nmtst_rand_buf (NULL, buf, len);
|
|
|
|
if (len == 0)
|
|
expected_strlen = 0;
|
|
else if (delimiter != '\0')
|
|
expected_strlen = (len * 3u) - 1;
|
|
else
|
|
expected_strlen = len * 2u;
|
|
|
|
g_assert_cmpint (expected_strlen, <, G_N_ELEMENTS (strbuf1));
|
|
|
|
str_hex = nm_utils_bin2hexstr_full (buf, len, delimiter, upper_case, !allocate ? strbuf1 : NULL);
|
|
|
|
g_assert (str_hex);
|
|
if (!allocate)
|
|
g_assert (str_hex == strbuf1);
|
|
g_assert_cmpint (strlen (str_hex), ==, expected_strlen);
|
|
|
|
g_assert (NM_STRCHAR_ALL (str_hex, ch, (ch >= '0' && ch <= '9')
|
|
|| ch == delimiter
|
|
|| ( upper_case
|
|
? (ch >= 'A' && ch <= 'F')
|
|
: (ch >= 'a' && ch <= 'f'))));
|
|
|
|
required_len = nmtst_get_rand_bool () ? len : 0u;
|
|
|
|
outlen_set = required_len == 0 || nmtst_get_rand_bool ();
|
|
|
|
memset (buf2, 0, sizeof (buf2));
|
|
|
|
bin2 = nm_utils_hexstr2bin_full (str_hex,
|
|
nmtst_get_rand_bool (),
|
|
delimiter != '\0' && nmtst_get_rand_bool (),
|
|
delimiter != '\0'
|
|
? nmtst_rand_select ((const char *) ":", ":-")
|
|
: nmtst_rand_select ((const char *) ":", ":-", "", NULL),
|
|
required_len,
|
|
buf2,
|
|
len,
|
|
outlen_set ? &outlen : NULL);
|
|
if (len > 0) {
|
|
g_assert (bin2);
|
|
g_assert (bin2 == buf2);
|
|
} else
|
|
g_assert (!bin2);
|
|
|
|
if (outlen_set)
|
|
g_assert_cmpint (outlen, ==, len);
|
|
|
|
g_assert_cmpmem (buf, len, buf2, len);
|
|
|
|
g_assert (buf2[len] == '\0');
|
|
|
|
if (allocate)
|
|
g_free (str_hex);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
test_nm_ref_string (void)
|
|
{
|
|
nm_auto_ref_string NMRefString *s1 = NULL;
|
|
NMRefString *s2;
|
|
|
|
s1 = nm_ref_string_new ("hallo");
|
|
g_assert (s1);
|
|
g_assert_cmpstr (s1->str, ==, "hallo");
|
|
g_assert_cmpint (s1->len, ==, strlen ("hallo"));
|
|
|
|
s2 = nm_ref_string_new ("hallo");
|
|
g_assert (s2 == s1);
|
|
nm_ref_string_unref (s2);
|
|
|
|
s2 = nm_ref_string_new (NULL);
|
|
g_assert (!s2);
|
|
nm_ref_string_unref (s2);
|
|
|
|
#define STR_WITH_NUL "hallo\0test\0"
|
|
s2 = nm_ref_string_new_len (STR_WITH_NUL, NM_STRLEN (STR_WITH_NUL));
|
|
g_assert (s2);
|
|
g_assert_cmpstr (s2->str, ==, "hallo");
|
|
g_assert_cmpint (s2->len, ==, NM_STRLEN (STR_WITH_NUL));
|
|
g_assert_cmpint (s2->len, >, strlen (s2->str));
|
|
g_assert_cmpmem (s2->str, s2->len, STR_WITH_NUL, NM_STRLEN (STR_WITH_NUL));
|
|
g_assert (s2->str[s2->len] == '\0');
|
|
nm_ref_string_unref (s2);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
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 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_nm_utils_parse_next_line (void)
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
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_is_specific_hostname (void)
|
|
{
|
|
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_strv_dup_packed (void)
|
|
{
|
|
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 ();
|
|
|
|
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);
|
|
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 ();
|
|
}
|