NetworkManager/shared/nm-glib-aux/tests/test-shared-general.c
Thomas Haller cd31437024 shared: drop _STATIC variant of macros that define functions
Several macros are used to define function. They had a "_STATIC" variant,
to define the function as static.

I think those macros should not try to abstract entirely what they do.
They should not accept the function scope as argument (or have two
variants per scope). This also because it might make sense to add
additional __attribute__(()) to the function. That only works, if
the macro does not pretend to *not* define a plain function.

Instead, embrace what the function does and let the users place the
function scope as they see fit.

This also follows what is already done with

    static NM_CACHED_QUARK_FCN ("autoconnect-root", autoconnect_root_quark)
2020-02-13 17:17:07 +01:00

608 lines
17 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-time-utils.h"
#include "nm-glib-aux/nm-ref-string.h"
#include "nm-utils/nm-test-utils.h"
/*****************************************************************************/
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. */
NMTST_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);
}
}
/*****************************************************************************/
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);
return g_test_run ();
}