/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2018 Red Hat, Inc. */ #include "libnm-glib-aux/nm-default-glib-i18n-prog.h" #include #include "libnm-std-aux/unaligned.h" #include "libnm-glib-aux/nm-random-utils.h" #include "libnm-glib-aux/nm-str-buf.h" #include "libnm-glib-aux/nm-time-utils.h" #include "libnm-glib-aux/nm-ref-string.h" #include "libnm-glib-aux/nm-io-utils.h" #include "libnm-glib-aux/nm-prioq.h" #include "libnm-glib-aux/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(_nm_alignof(in_addr_t) <= _nm_alignof(NMIPAddr)); G_STATIC_ASSERT(_nm_alignof(struct in_addr) <= _nm_alignof(NMIPAddr)); G_STATIC_ASSERT(_nm_alignof(struct in6_addr) <= _nm_alignof(NMIPAddr)); G_STATIC_ASSERT(_nm_alignof(NMEtherAddr) <= _nm_alignof(NMIPAddr)); /*****************************************************************************/ G_STATIC_ASSERT(_NM_INT_IS_SIGNED(1)); G_STATIC_ASSERT(!_NM_INT_IS_SIGNED(1u)); G_STATIC_ASSERT(_NM_INT_SAME_SIGNEDNESS((short) 1, 1l)); G_STATIC_ASSERT(!_NM_INT_SAME_SIGNEDNESS((unsigned short) 1, 1l)); /*****************************************************************************/ static void test_nm_static_assert(void) { int v1[NM_STATIC_ASSERT_EXPR_1(1)]; typeof(NM_STATIC_ASSERT_EXPR_1(1)) v_int; int *p_int; G_STATIC_ASSERT(sizeof(v1) == sizeof(int)); G_STATIC_ASSERT(NM_STATIC_ASSERT_EXPR_1(1) == 1); G_STATIC_ASSERT(NM_STATIC_ASSERT_EXPR_1(NM_STATIC_ASSERT_EXPR_1(1)) == 1); G_STATIC_ASSERT(NM_STATIC_ASSERT_EXPR_1(NM_STATIC_ASSERT_EXPR_1(NM_STATIC_ASSERT_EXPR_1(1))) == 1); g_assert(NM_STATIC_ASSERT_EXPR_1(2) == 1); p_int = &v_int; g_assert(&v_int == p_int); (void) NM_STATIC_ASSERT_EXPR_1(2 > 1); NM_STATIC_ASSERT_EXPR_VOID(2 > 1); } /*****************************************************************************/ static void test_max(void) { /* Check that NM_MAX() of constant expressions is itself a constant. We * build with -Wvla, so this is a constant! */ char buf1[NM_MAX(55, 40)]; char buf2[NM_MAX(1, NM_MAX(40, 55))]; G_STATIC_ASSERT(sizeof(buf1) == 55); G_STATIC_ASSERT(sizeof(buf2) == 55); } /*****************************************************************************/ 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); /* also check how assert() works. */ assert(*int_ptr == 42); } /*****************************************************************************/ static void test_monotonic_timestamp(void) { g_assert(nm_utils_get_monotonic_timestamp_sec() > 0); } /*****************************************************************************/ static void test_timespect_to(void) { struct timespec ts; int i; for (i = 0; i < 1000; i++) { gint64 t_msec; gint64 t_usec; gint64 t_nsec; nmtst_rand_buf(NULL, &ts, sizeof(ts)); ts.tv_sec = llabs(ts.tv_sec % 100000); ts.tv_nsec = llabs(ts.tv_nsec % NM_UTILS_NSEC_PER_SEC); t_msec = nm_utils_timespec_to_msec(&ts); t_usec = nm_utils_timespec_to_usec(&ts); t_nsec = nm_utils_timespec_to_nsec(&ts); g_assert_cmpint(t_msec, <=, t_usec / 1000); g_assert_cmpint(t_msec + 1, >=, t_usec / 1000); g_assert_cmpint(t_msec, <=, t_nsec / 1000000); g_assert_cmpint(t_msec + 1, >=, t_nsec / 1000000); g_assert_cmpint(t_usec, <=, t_nsec / 1000); g_assert_cmpint(t_usec + 1, >=, t_nsec / 1000); } } /*****************************************************************************/ static void test_nmhash(void) { int rnd; nm_random_get_bytes(&rnd, sizeof(rnd)); g_assert(nm_hash_val(555, 4) != 0); } /*****************************************************************************/ static void test_nm_random(void) { int i_run; for (i_run = 0; i_run < 1000; i_run++) { guint64 begin; guint64 end; guint64 m; guint64 x; m = nmtst_get_rand_uint64(); m = m >> (nmtst_get_rand_uint32() % 64); if (m == 0) continue; switch (nmtst_get_rand_uint32() % 4) { case 0: begin = 0; break; case 1: begin = nmtst_get_rand_uint64() % 1000; break; case 2: begin = ((G_MAXUINT64 - m) - 500) + (nmtst_get_rand_uint64() % 1000); break; default: begin = nmtst_get_rand_uint64() % (G_MAXUINT64 - m); break; } end = (begin + m) - 10 + (nmtst_get_rand_uint64() % 5); if (begin >= end) continue; x = nm_random_u64_range(begin, end); g_assert_cmpuint(x, >=, begin); g_assert_cmpuint(x, <, end); } } /*****************************************************************************/ 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_loopback(void) { g_assert(nm_ip4_addr_is_loopback(nmtst_inet4_from_string("127.0.0.0"))); g_assert(nm_ip4_addr_is_loopback(nmtst_inet4_from_string("127.0.0.1"))); g_assert(nm_ip4_addr_is_loopback(nmtst_inet4_from_string("127.5.0.1"))); g_assert(!nm_ip4_addr_is_loopback(nmtst_inet4_from_string("126.5.0.1"))); g_assert(!nm_ip4_addr_is_loopback(nmtst_inet4_from_string("128.5.0.1"))); g_assert(!nm_ip4_addr_is_loopback(nmtst_inet4_from_string("129.5.0.1"))); g_assert_cmpint(nmtst_inet4_from_string("127.0.0.0"), ==, NM_IPV4LO_NETWORK); g_assert_cmpint(nmtst_inet4_from_string("127.0.0.1"), ==, NM_IPV4LO_ADDR1); g_assert_cmpint(nmtst_inet4_from_string("255.0.0.0"), ==, NM_IPV4LO_NETMASK); g_assert_cmpint(nm_ip4_addr_netmask_to_prefix(NM_IPV4LO_NETMASK), ==, NM_IPV4LO_PREFIXLEN); } /*****************************************************************************/ static void test_nm_ip4_addr_netmask_from_prefix(void) { g_assert_cmpint(nm_ip4_addr_netmask_from_prefix(0), ==, nmtst_inet4_from_string("0.0.0.0")); g_assert_cmpint(nm_ip4_addr_netmask_from_prefix(1), ==, nmtst_inet4_from_string("128.0.0.0")); g_assert_cmpint(nm_ip4_addr_netmask_from_prefix(2), ==, nmtst_inet4_from_string("192.0.0.0")); g_assert_cmpint(nm_ip4_addr_netmask_from_prefix(16), ==, nmtst_inet4_from_string("255.255.0.0")); g_assert_cmpint(nm_ip4_addr_netmask_from_prefix(24), ==, nmtst_inet4_from_string("255.255.255.0")); g_assert_cmpint(nm_ip4_addr_netmask_from_prefix(30), ==, nmtst_inet4_from_string("255.255.255.252")); g_assert_cmpint(nm_ip4_addr_netmask_from_prefix(31), ==, nmtst_inet4_from_string("255.255.255.254")); g_assert_cmpint(nm_ip4_addr_netmask_from_prefix(32), ==, nmtst_inet4_from_string("255.255.255.255")); } /*****************************************************************************/ static void test_nm_ip6_addr_get_subnet_id(void) { #define check_subnet_id(_addrstr, _plen, _subnet_id) \ { \ struct in6_addr addr; \ \ addr = nmtst_inet6_from_string(_addrstr); \ g_assert_cmpint(nm_ip6_addr_get_subnet_id(&addr, _plen), ==, _subnet_id); \ } check_subnet_id("aaaa:bbbb:cccc:ffff::", 64, 0); check_subnet_id("aaaa:bbbb:cccc:fffe::", 63, 0); check_subnet_id("aaaa:bbbb:cccc:ffff::", 63, 1); check_subnet_id("aaaa:bbbb:cccc:fffc::", 62, 0); check_subnet_id("aaaa:bbbb:cccc:fffd::", 62, 1); check_subnet_id("aaaa:bbbb:cccc:fffe::", 62, 2); check_subnet_id("aaaa:bbbb:cccc:ffff::", 62, 3); check_subnet_id("aaaa:bbbb:cccc:fff8::", 61, 0); check_subnet_id("aaaa:bbbb:cccc:ffff::", 61, 7); check_subnet_id("aaaa:bbbb:cccc:fff0::", 60, 0); check_subnet_id("aaaa:bbbb:cccc:fff2::", 60, 2); check_subnet_id("aaaa:bbbb:cccc:ffff::", 60, 15); check_subnet_id("aaaa:bbbb:cccc:0000::", 48, 0); check_subnet_id("aaaa:bbbb:cccc:f000::", 48, 61440); check_subnet_id("aaaa:bbbb:cccc:ffff::", 48, 65535); check_subnet_id("aaaa:bbbb:cccc:0000::", 46, 0); check_subnet_id("aaaa:bbbb:cccc:0001::", 46, 1); check_subnet_id("aaaa:bbbb:ccce:5555::", 46, 152917); check_subnet_id("aaaa:bbbb:0000:0000::", 32, 0); check_subnet_id("aaaa:bbbb:0000:0001::", 32, 1); check_subnet_id("aaaa:bbbb:0001:0001::", 32, 65537); check_subnet_id("aaaa:bbbb:ffff:ffff::", 32, 0xffffffff); check_subnet_id("aaaa:bbb8:0000:0000::", 30, 0); check_subnet_id("aaaa:bbb8:0000:0001::", 30, 1); check_subnet_id("aaaa:bbb8:0001:0001::", 30, 65537); check_subnet_id("aaaa:bbbb:0000:0000::", 30, 0x300000000ULL); check_subnet_id("aaaa:bbbb:0001:0001::", 30, 0x300010001ULL); check_subnet_id("aaaa:bbbb:0001:0001::", 8, 0xAABBBB00010001ULL); check_subnet_id("abaa:bbbb:0001:0001::", 7, 0x1AABBBB00010001ULL); check_subnet_id("abaa:bbbb:0001:0001::", 0, 0xABAABBBB00010001ULL); check_subnet_id("abaa:bbbb:0001:0001:5555:5555:5555:5555", 0, 0xABAABBBB00010001ULL); check_subnet_id("::", 0, 0); } /*****************************************************************************/ 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 : nm_strv_empty_new(); } 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_strv_cmp_n(_a1, _l1, _a2, _l2); \ _c2 = nm_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_strv_cmp_n(_a1, _l1, _a1x, _l1), ==, 0); \ g_assert_cmpint(nm_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 < 500; 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(); gboolean hexdigit_pairs_mangled; gsize expected_strlen; char *str_hex; gsize required_len; gboolean outlen_set; gsize outlen; guint8 *bin2; guint i, j; 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')))); hexdigit_pairs_mangled = FALSE; if (delimiter && len > 1 && nmtst_get_rand_bool()) { /* randomly convert "0?" sequences to single digits, so we can get hexdigit_pairs_required * parameter. */ g_assert(strlen(str_hex) >= 5); g_assert(str_hex[2] == delimiter); i = 0; j = 0; for (;;) { g_assert(g_ascii_isxdigit(str_hex[i])); g_assert(g_ascii_isxdigit(str_hex[i + 1])); g_assert(NM_IN_SET(str_hex[i + 2], delimiter, '\0')); if (str_hex[i] == '0' && nmtst_get_rand_bool()) { i++; str_hex[j++] = str_hex[i++]; hexdigit_pairs_mangled = TRUE; } else { str_hex[j++] = str_hex[i++]; str_hex[j++] = str_hex[i++]; } if (str_hex[i] == '\0') { str_hex[j] = '\0'; break; } g_assert(str_hex[i] == delimiter); str_hex[j++] = str_hex[i++]; } } 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(), !hexdigit_pairs_mangled && 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 (hexdigit_pairs_mangled) { /* we mangled the hexstr to contain single digits. Trying to parse with * hexdigit_pairs_required must now fail. */ bin2 = nm_utils_hexstr2bin_full( str_hex, nmtst_get_rand_bool(), delimiter != '\0' && nmtst_get_rand_bool(), TRUE, delimiter != '\0' ? nmtst_rand_select((const char *) ":", ":-") : nmtst_rand_select((const char *) ":", ":-", "", NULL), required_len, buf2, len, outlen_set ? &outlen : NULL); g_assert(!bin2); } if (allocate) g_free(str_hex); } } /*****************************************************************************/ static void test_nm_ref_string(void) { nm_auto_ref_string NMRefString *s1 = NULL; NMRefString *s2; g_assert(NULL == NM_REF_STRING_UPCAST(NULL)); g_assert(nm_ref_string_equal_str(NULL, NULL)); g_assert(!nm_ref_string_equal_str(NULL, "")); g_assert(!nm_ref_string_equal_str(NULL, "a")); s1 = nm_ref_string_new("hallo"); g_assert(s1); g_assert_cmpstr(s1->str, ==, "hallo"); g_assert_cmpint(s1->len, ==, strlen("hallo")); g_assert(s1 == NM_REF_STRING_UPCAST(s1->str)); g_assert(nm_ref_string_equal_str(s1, "hallo")); g_assert(!nm_ref_string_equal_str(s1, "hallox")); g_assert(!nm_ref_string_equal_str(s1, "hall")); g_assert(!nm_ref_string_equal_str(s1, NULL)); 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(!nm_ref_string_equal_str(s2, "hallo")); 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_232, NM_UTILS_GET_NEXT_REALLOC_SIZE_232, NM_UTILS_GET_NEXT_REALLOC_SIZE_232}, {NM_UTILS_GET_NEXT_REALLOC_SIZE_488, NM_UTILS_GET_NEXT_REALLOC_SIZE_488, NM_UTILS_GET_NEXT_REALLOC_SIZE_488}, {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_32 == 32u); G_STATIC_ASSERT_EXPR(NM_UTILS_GET_NEXT_REALLOC_SIZE_40 == 40u); G_STATIC_ASSERT_EXPR(NM_UTILS_GET_NEXT_REALLOC_SIZE_104 == 104u); G_STATIC_ASSERT_EXPR(NM_UTILS_GET_NEXT_REALLOC_SIZE_232 == 232u); 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; gsize reserved_true; gsize reserved_false; bool truncated_true = FALSE; bool truncated_false = FALSE; if (sizeof(gsize) > 4 && requested > SIZE_MAX / 2u - 24u) { reserved_false = G_MAXSSIZE; truncated_false = TRUE; } else reserved_false = nm_utils_get_next_realloc_size(FALSE, requested); if (sizeof(gsize) > 4 && requested > SIZE_MAX - 0x1000u - 24u) { reserved_true = G_MAXSSIZE; truncated_true = TRUE; } else reserved_true = nm_utils_get_next_realloc_size(TRUE, requested); g_assert_cmpuint(reserved_true, >, 0); g_assert_cmpuint(reserved_false, >, 0); if (!truncated_true) g_assert_cmpuint(reserved_true, >=, requested); if (!truncated_false) g_assert_cmpuint(reserved_false, >=, requested); if (!truncated_true && !truncated_false) g_assert_cmpuint(reserved_false, >=, reserved_true); if (i < G_N_ELEMENTS(test_data)) { if (!truncated_true) g_assert_cmpuint(reserved_true, ==, test_data[i].reserved_true); if (!truncated_false) 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 if (!reserved_false) { 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 if (!truncated_true) { 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; i_run < 1000; i_run++) { char stack_buf[1024]; nm_auto_str_buf NMStrBuf strbuf; nm_auto_free_gstring GString *gstr = NULL; int i, j, k; int c; switch (nmtst_get_rand_uint32() % 10) { case 0: memset(&strbuf, 0, sizeof(strbuf)); break; case 1 ... 4: strbuf = NM_STR_BUF_INIT_FULL(stack_buf, 0, nmtst_get_rand_uint32() % sizeof(stack_buf), FALSE, nmtst_get_rand_bool()); break; default: strbuf = NM_STR_BUF_INIT(nmtst_get_rand_uint32() % 200u + 1u, nmtst_get_rand_bool()); break; } 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); if (gstr->str[0]) g_assert_cmpstr(gstr->str, ==, nm_str_buf_get_str(&strbuf)); else g_assert(NM_IN_STRSET(nm_str_buf_get_str(&strbuf), NULL, "")); } for (i_run = 0; i_run < 50; i_run++) { char stack_buf[20]; nm_auto_str_buf NMStrBuf strbuf = NM_STR_BUF_INIT_ARR(stack_buf, nmtst_get_rand_bool()); nm_str_buf_append_c_len(&strbuf, 'a', nmtst_get_rand_uint32() % (sizeof(stack_buf) * 2)); if (strbuf.len <= sizeof(stack_buf)) { g_assert(stack_buf == nm_str_buf_get_str_unsafe(&strbuf)); } else g_assert(stack_buf != nm_str_buf_get_str_unsafe(&strbuf)); if (strbuf.len < sizeof(stack_buf)) { g_assert(stack_buf == nm_str_buf_get_str(&strbuf)); } else g_assert(stack_buf != nm_str_buf_get_str(&strbuf)); } { nm_auto_str_buf NMStrBuf s1 = NM_STR_BUF_INIT_A(10, nmtst_get_rand_bool()); gs_free char *str = NULL; gsize l; nm_str_buf_append_len(&s1, "a\0b", 3); str = nm_str_buf_finalize(&s1, &l); g_assert_cmpmem(str, l + 1, "a\0b", 4); } } /*****************************************************************************/ 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_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_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_strv_equal(strv_cpy, 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 ? NULL : 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_cmp_equal(h1, h2, NULL, NULL)); g_assert(nm_utils_hashtable_cmp_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_cmp_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_cmp_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_cmp_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); } } } /*****************************************************************************/ static void test_nm_g_source_sentinel(void) { GSource *s1; GSource *s2; int n; int i; int refs; s1 = nm_g_source_sentinel_get(0); g_assert_nonnull(s1); g_assert_cmpint(g_atomic_int_get(&s1->ref_count), ==, 1); s2 = nm_g_source_sentinel_get(0); g_assert_nonnull(s2); g_assert(s2 == s1); g_assert_cmpint(g_atomic_int_get(&s1->ref_count), ==, 1); n = nmtst_get_rand_uint32() % 7; for (refs = 0, i = 0; i < n; i++) { if (nmtst_get_rand_bool()) { refs++; g_source_ref(s1); } if (nmtst_get_rand_bool()) g_source_destroy(s1); if (refs > 0 && nmtst_get_rand_bool()) { refs--; g_source_unref(s1); } if (nmtst_get_rand_bool()) { s2 = nm_g_source_sentinel_get(0); g_assert_cmpint(g_atomic_int_get(&s2->ref_count), >=, 1); g_assert(s2 == s1); } } for (; refs > 0;) { if (nmtst_get_rand_bool()) g_source_destroy(s1); if (nmtst_get_rand_bool()) { refs--; g_source_unref(s1); } } g_assert_cmpint(g_atomic_int_get(&s1->ref_count), ==, 1); } /*****************************************************************************/ static void test_nm_ascii(void) { int i; for (i = 0; i < 256; i++) { const char ch = i; gboolean is_space; if (ch == 127) { g_assert(nm_ascii_is_ctrl_or_del(ch)); g_assert(!nm_ascii_is_ctrl(ch)); } else g_assert(nm_ascii_is_ctrl_or_del(ch) == nm_ascii_is_ctrl(ch)); g_assert(nm_ascii_is_ctrl_or_del(ch) == g_ascii_iscntrl(ch)); g_assert(nm_ascii_is_non_ascii(ch) == (i >= 128)); g_assert(!nm_ascii_is_ctrl_or_del(ch) || !nm_ascii_is_non_ascii(ch)); g_assert((nm_ascii_is_ctrl_or_del(ch) || nm_ascii_is_regular(ch)) != nm_ascii_is_non_ascii(ch)); g_assert(nm_ascii_is_regular(ch) == (!nm_ascii_is_ctrl_or_del(ch) && !nm_ascii_is_non_ascii(ch))); is_space = g_ascii_isspace(ch); if (NM_IN_SET(ch, '\t', '\n', '\f', '\r')) { /* hack is-space, so that the check below works to check for regular ASCII characters. */ g_assert(!nm_ascii_is_regular(ch)); g_assert(is_space); is_space = FALSE; } g_assert(nm_ascii_is_regular(ch) == (g_ascii_isalnum(ch) || g_ascii_isalpha(ch) || g_ascii_isdigit(ch) || g_ascii_isgraph(ch) || g_ascii_islower(ch) || g_ascii_isprint(ch) || g_ascii_ispunct(ch) || is_space || g_ascii_isupper(ch) || g_ascii_isxdigit(ch))); } } /*****************************************************************************/ static int _env_file_push_cb(unsigned line, const char *key, const char *value, void *user_data) { char ***strv = user_data; char *s_line; gsize key_l; gsize strv_l; gsize i; g_assert(strv); g_assert(key); g_assert(key[0]); g_assert(!strchr(key, '=')); g_assert(value); key_l = strlen(key); s_line = g_strconcat(key, "=", value, NULL); strv_l = 0; if (*strv) { const char *s; for (i = 0; (s = (*strv)[i]); i++) { if (g_str_has_prefix(s, key) && s[key_l] == '=') { g_free((*strv)[i]); (*strv)[i] = s_line; return 0; } } strv_l = i; } *strv = g_realloc(*strv, sizeof(char *) * (strv_l + 2)); (*strv)[strv_l] = s_line; (*strv)[strv_l + 1] = NULL; return 0; } static void test_parse_env_file(void) { gs_strfreev char **data = NULL; gs_free char *arg1 = NULL; gs_free char *arg2 = NULL; int r; #define env_file_1 \ "a=a\n" \ "a=b\n" \ "a=b\n" \ "a=a\n" \ "b=b\\\n" \ "c\n" \ "d= d\\\n" \ "e \\\n" \ "f \n" \ "g=g\\ \n" \ "h= ąęół\\ śćńźżµ \n" \ "i=i\\" r = nm_parse_env_file_full(env_file_1, _env_file_push_cb, &data); g_assert_cmpint(r, ==, 0); nmtst_assert_strv(data, "a=a", "b=bc", "d=de f", "g=g ", "h=ąęół śćńźżµ", "i=i"); nm_clear_pointer(&data, g_strfreev); r = nm_parse_env_file(env_file_1, "a", &arg1); g_assert_cmpint(r, ==, 0); g_assert_cmpstr(arg1, ==, "a"); nm_clear_g_free(&arg1); r = nm_parse_env_file(env_file_1, "a", &arg1, "d", &arg2); g_assert_cmpint(r, ==, 0); g_assert_cmpstr(arg1, ==, "a"); g_assert_cmpstr(arg2, ==, "de f"); nm_clear_g_free(&arg1); nm_clear_g_free(&arg2); #define env_file_2 "a=a\\\n" r = nm_parse_env_file_full(env_file_2, _env_file_push_cb, &data); g_assert_cmpint(r, ==, 0); nmtst_assert_strv(data, "a=a"); nm_clear_pointer(&data, g_strfreev); #define env_file_3 \ "#SPAMD_ARGS=\"-d --socketpath=/var/lib/bulwark/spamd \\\n" \ "#--nouser-config \\\n" \ "normal=line \\\n" \ ";normal=ignored \\\n" \ "normal_ignored \\\n" \ "normal ignored \\\n" r = nm_parse_env_file_full(env_file_3, _env_file_push_cb, &data); g_assert_cmpint(r, ==, 0); g_assert(!data); #define env_file_4 \ "# Generated\n" \ "\n" \ "HWMON_MODULES=\"coretemp f71882fg\"\n" \ "\n" \ "# For compatibility reasons\n" \ "\n" \ "MODULE_0=coretemp\n" \ "MODULE_1=f71882fg" r = nm_parse_env_file_full(env_file_4, _env_file_push_cb, &data); g_assert_cmpint(r, ==, 0); nmtst_assert_strv(data, "HWMON_MODULES=coretemp f71882fg", "MODULE_0=coretemp", "MODULE_1=f71882fg"); nm_clear_pointer(&data, g_strfreev); #define env_file_5 \ "a=\n" \ "b=" r = nm_parse_env_file_full(env_file_5, _env_file_push_cb, &data); g_assert_cmpint(r, ==, 0); nmtst_assert_strv(data, "a=", "b="); nm_clear_pointer(&data, g_strfreev); #define env_file_6 \ "a=\\ \\n \\t \\x \\y \\' \n" \ "b= \\$' \n" \ "c= ' \\n\\t\\$\\`\\\\\n" \ "' \n" \ "d= \" \\n\\t\\$\\`\\\\\n" \ "\" \n" r = nm_parse_env_file_full(env_file_6, _env_file_push_cb, &data); g_assert_cmpint(r, ==, 0); nmtst_assert_strv(data, "a= n t x y '", "b=$'", "c= \\n\\t\\$\\`\\\\\n", "d= \\n\\t$`\\\n"); nm_clear_pointer(&data, g_strfreev); } /*****************************************************************************/ static void test_unbase64char(void) { static const int expected[128] = { [0] = -1, [1] = -1, [2] = -1, [3] = -1, [4] = -1, [5] = -1, [6] = -1, [7] = -1, [8] = -1, [9] = -1, [10] = -1, [11] = -1, [12] = -1, [13] = -1, [14] = -1, [15] = -1, [16] = -1, [17] = -1, [18] = -1, [19] = -1, [20] = -1, [21] = -1, [22] = -1, [23] = -1, [24] = -1, [25] = -1, [26] = -1, [27] = -1, [28] = -1, [29] = -1, [30] = -1, [31] = -1, [32] = -1, [33] = -1, [34] = -1, [35] = -1, [36] = -1, [37] = -1, [38] = -1, [39] = -1, [40] = -1, [41] = -1, [42] = -1, ['+'] = 62, [44] = -1, [45] = -1, [46] = -1, ['/'] = 63, ['0'] = 52, ['1'] = 53, ['2'] = 54, ['3'] = 55, ['4'] = 56, ['5'] = 57, ['6'] = 58, ['7'] = 59, ['8'] = 60, ['9'] = 61, [58] = -1, [59] = -1, [60] = -1, [61] = -1, [62] = -1, [63] = -1, [64] = -1, ['A'] = 0, ['B'] = 1, ['C'] = 2, ['D'] = 3, ['E'] = 4, ['F'] = 5, ['G'] = 6, ['H'] = 7, ['I'] = 8, ['J'] = 9, ['K'] = 10, ['L'] = 11, ['M'] = 12, ['N'] = 13, ['O'] = 14, ['P'] = 15, ['Q'] = 16, ['R'] = 17, ['S'] = 18, ['T'] = 19, ['U'] = 20, ['V'] = 21, ['W'] = 22, ['X'] = 23, ['Y'] = 24, ['Z'] = 25, [91] = -1, [92] = -1, [93] = -1, [94] = -1, [95] = -1, [96] = -1, ['a'] = 26, ['b'] = 27, ['c'] = 28, ['d'] = 29, ['e'] = 30, ['f'] = 31, ['g'] = 32, ['h'] = 33, ['i'] = 34, ['j'] = 35, ['k'] = 36, ['l'] = 37, ['m'] = 38, ['n'] = 39, ['o'] = 40, ['p'] = 41, ['q'] = 42, ['r'] = 43, ['s'] = 44, ['t'] = 45, ['u'] = 46, ['v'] = 47, ['w'] = 48, ['x'] = 49, ['y'] = 50, ['z'] = 51, [123] = -1, [124] = -1, [125] = -1, [126] = -1, [127] = -1, }; int i; /* Copied from systemd's TEST(unbase64char) * https://github.com/systemd/systemd/blob/688efe7703328c5a0251fafac55757b8864a9f9a/src/test/test-hexdecoct.c#L44 */ g_assert_cmpint(nm_unbase64char('A'), ==, 0); g_assert_cmpint(nm_unbase64char('Z'), ==, 25); g_assert_cmpint(nm_unbase64char('a'), ==, 26); g_assert_cmpint(nm_unbase64char('z'), ==, 51); g_assert_cmpint(nm_unbase64char('0'), ==, 52); g_assert_cmpint(nm_unbase64char('9'), ==, 61); g_assert_cmpint(nm_unbase64char('+'), ==, 62); g_assert_cmpint(nm_unbase64char('/'), ==, 63); g_assert_cmpint(nm_unbase64char('='), ==, -ERANGE); g_assert_cmpint(nm_unbase64char('\0'), ==, -EINVAL); g_assert_cmpint(nm_unbase64char('\1'), ==, -EINVAL); g_assert_cmpint(nm_unbase64char('\x7F'), ==, -EINVAL); g_assert_cmpint(nm_unbase64char('\x80'), ==, -EINVAL); g_assert_cmpint(nm_unbase64char('\xFF'), ==, -EINVAL); for (i = 0; i < 256; i++) { int base64; base64 = nm_unbase64char((char) i); if (base64 < 0) { if (((char) i) == '=') g_assert_cmpint(base64, ==, -ERANGE); else g_assert_cmpint(base64, ==, -EINVAL); base64 = -1; } if (i >= G_N_ELEMENTS(expected)) { g_assert_cmpint(base64, ==, -1); continue; } g_assert_cmpint(base64, ==, expected[i]); } } /*****************************************************************************/ static void test_unbase64mem1(void) { nm_auto_str_buf NMStrBuf encoded_wrapped = NM_STR_BUF_INIT(400, FALSE); uint8_t data[4096]; int i_run; /* Copied from systemd's TEST(base64mem_linebreak) * https://github.com/systemd/systemd/blob/688efe7703328c5a0251fafac55757b8864a9f9a/src/test/test-hexdecoct.c#L280 */ for (i_run = 0; i_run < 20; i_run++) { gs_free char *encoded = NULL; gs_free guint8 *decoded = NULL; gsize decoded_size; guint64 n; guint64 m; guint64 i; guint64 j; gssize l; int r; /* Try a bunch of differently sized blobs */ n = nmtst_get_rand_uint64() % sizeof(data); nmtst_rand_buf(NULL, data, n); /* Break at various different columns */ m = 1 + (nmtst_get_rand_uint64() % (n + 5)); encoded = g_base64_encode(data, n); g_assert(encoded); l = strlen(encoded); nm_str_buf_reset(&encoded_wrapped); for (i = 0, j = 0; i < l; i++, j++) { if (j == m) { nm_str_buf_append_c(&encoded_wrapped, '\n'); j = 0; } nm_str_buf_append_c(&encoded_wrapped, encoded[i]); } g_assert_cmpint(strlen(nm_str_buf_get_str(&encoded_wrapped)), ==, encoded_wrapped.len); r = nm_unbase64mem_full(nm_str_buf_get_str(&encoded_wrapped), nmtst_get_rand_bool() ? SIZE_MAX : encoded_wrapped.len, nmtst_get_rand_bool(), &decoded, &decoded_size); g_assert_cmpint(r, >=, 0); g_assert_cmpmem(data, n, decoded, decoded_size); for (j = 0; j < encoded_wrapped.len; j++) g_assert((nm_str_buf_get_str(&encoded_wrapped)[j] == '\n') == (j % (m + 1) == m)); } } /*****************************************************************************/ static void _assert_unbase64mem(const char *input, const char *output, int ret) { gs_free guint8 *buffer = NULL; gsize size = 0; int r; r = nm_unbase64mem_full(input, SIZE_MAX, nmtst_get_rand_bool(), &buffer, &size); g_assert_cmpint(r, ==, ret); if (ret >= 0) { g_assert_cmpmem(buffer, size, output, strlen(output)); g_assert_cmpint(((const char *) buffer)[size], ==, '\0'); } else { g_assert(!buffer); g_assert_cmpint(size, ==, 0); } } static void test_unbase64mem2(void) { /* Copied from systemd's TEST(unbase64mem) * https://github.com/systemd/systemd/blob/688efe7703328c5a0251fafac55757b8864a9f9a/src/test/test-hexdecoct.c#L324 */ _assert_unbase64mem("", "", 0); _assert_unbase64mem("Zg==", "f", 0); _assert_unbase64mem("Zm8=", "fo", 0); _assert_unbase64mem("Zm9v", "foo", 0); _assert_unbase64mem("Zm9vYg==", "foob", 0); _assert_unbase64mem("Zm9vYmE=", "fooba", 0); _assert_unbase64mem("Zm9vYmFy", "foobar", 0); _assert_unbase64mem(" ", "", 0); _assert_unbase64mem(" \n\r ", "", 0); _assert_unbase64mem(" Zg\n== ", "f", 0); _assert_unbase64mem(" Zm 8=\r", "fo", 0); _assert_unbase64mem(" Zm9\n\r\r\nv ", "foo", 0); _assert_unbase64mem(" Z m9vYg==\n\r", "foob", 0); _assert_unbase64mem(" Zm 9vYmE= ", "fooba", 0); _assert_unbase64mem(" Z m9v YmFy ", "foobar", 0); _assert_unbase64mem("A", NULL, -EPIPE); _assert_unbase64mem("A====", NULL, -EINVAL); _assert_unbase64mem("AAB==", NULL, -EINVAL); _assert_unbase64mem(" A A A B = ", NULL, -EINVAL); _assert_unbase64mem(" Z m 8 = q u u x ", NULL, -ENAMETOOLONG); } /*****************************************************************************/ static void _test_unbase64mem_mem(const char *base64, const guint8 *expected_arr, gsize expected_len) { gs_free char *expected_base64 = NULL; int r; nm_auto_free guint8 *exp2_arr = NULL; nm_auto_free guint8 *exp3_arr = NULL; gsize exp2_len; gsize exp3_len; expected_base64 = g_base64_encode(expected_arr, expected_len); r = nm_unbase64mem_full(expected_base64, strlen(expected_base64), TRUE, &exp2_arr, &exp2_len); g_assert_cmpint(r, ==, 0); g_assert_cmpmem(expected_arr, expected_len, exp2_arr, exp2_len); if (!nm_streq(base64, expected_base64)) { r = nm_unbase64mem_full(base64, strlen(base64), TRUE, &exp3_arr, &exp3_len); g_assert_cmpint(r, ==, 0); g_assert_cmpmem(expected_arr, expected_len, exp3_arr, exp3_len); } } #define _test_unbase64mem(base64, expected_str) \ _test_unbase64mem_mem(base64, (const guint8 *) "" expected_str "", NM_STRLEN(expected_str)) static void _test_unbase64mem_inval(const char *base64) { gs_free guint8 *exp_arr = NULL; gsize exp_len = 0; int r; r = nm_unbase64mem_full(base64, strlen(base64), TRUE, &exp_arr, &exp_len); g_assert_cmpint(r, <, 0); g_assert(!exp_arr); g_assert(exp_len == 0); } static void test_unbase64mem3(void) { gs_free char *rnd_base64 = NULL; guint8 rnd_buf[30]; guint i, rnd_len; _test_unbase64mem("", ""); _test_unbase64mem(" ", ""); _test_unbase64mem(" Y Q == ", "a"); _test_unbase64mem(" Y WJjZGV mZ 2g = ", "abcdefgh"); _test_unbase64mem_inval(" Y %WJjZGV mZ 2g = "); _test_unbase64mem_inval(" Y %WJjZGV mZ 2g = a"); _test_unbase64mem("YQ==", "a"); _test_unbase64mem_inval("YQ==a"); rnd_len = nmtst_get_rand_uint32() % sizeof(rnd_buf); for (i = 0; i < rnd_len; i++) rnd_buf[i] = nmtst_get_rand_uint32() % 256; rnd_base64 = g_base64_encode(rnd_buf, rnd_len); _test_unbase64mem_mem(rnd_base64, rnd_buf, rnd_len); } /*****************************************************************************/ static void assert_path_compare(const char *a, const char *b, int expected) { int r; g_assert(NM_IN_SET(expected, -1, 0, 1)); g_assert_cmpint(nm_path_compare(a, a), ==, 0); g_assert_cmpint(nm_path_compare(b, b), ==, 0); r = nm_path_compare(a, b); g_assert_cmpint(r, ==, expected); r = nm_path_compare(b, a); g_assert_cmpint(r, ==, -expected); g_assert(nm_path_equal(a, a) == 1); g_assert(nm_path_equal(b, b) == 1); g_assert(nm_path_equal(a, b) == (expected == 0)); g_assert(nm_path_equal(b, a) == (expected == 0)); } static void test_path_compare(void) { /* Copied from systemd. * https://github.com/systemd/systemd/blob/bc85f8b51d962597360e982811e674c126850f56/src/test/test-path-util.c#L126 */ assert_path_compare("/goo", "/goo", 0); assert_path_compare("/goo", "/goo", 0); assert_path_compare("//goo", "/goo", 0); assert_path_compare("//goo/////", "/goo", 0); assert_path_compare("goo/////", "goo", 0); assert_path_compare("/goo/boo", "/goo//boo", 0); assert_path_compare("//goo/boo", "/goo/boo//", 0); assert_path_compare("//goo/././//./boo//././//", "/goo/boo//.", 0); assert_path_compare("/.", "//.///", 0); assert_path_compare("/x", "x/", 1); assert_path_compare("x/", "/", -1); assert_path_compare("/x/./y", "x/y", 1); assert_path_compare("/x/./y", "/x/y", 0); assert_path_compare("/x/./././y", "/x/y/././.", 0); assert_path_compare("./x/./././y", "./x/y/././.", 0); assert_path_compare(".", "./.", 0); assert_path_compare(".", "././.", 0); assert_path_compare("./..", ".", 1); assert_path_compare("x/.y", "x/y", -1); assert_path_compare("foo", "/foo", -1); assert_path_compare("/foo", "/foo/bar", -1); assert_path_compare("/foo/aaa", "/foo/b", -1); assert_path_compare("/foo/aaa", "/foo/b/a", -1); assert_path_compare("/foo/a", "/foo/aaa", -1); assert_path_compare("/foo/a/b", "/foo/aaa", -1); } /*****************************************************************************/ static void test_path_equal(void) { #define _path_equal_check(path, expected) \ G_STMT_START \ { \ const char *_path0 = (path); \ const char *_expected = (expected); \ gs_free char *_path = g_strdup(_path0); \ const char *_path_result; \ \ _path_result = nm_path_simplify(_path); \ g_assert(_path_result == _path); \ g_assert_cmpstr(_path, ==, _expected); \ } \ G_STMT_END _path_equal_check("", ""); _path_equal_check(".", "."); _path_equal_check("..", ".."); _path_equal_check("/..", "/.."); _path_equal_check("//..", "/.."); _path_equal_check("/.", "/"); _path_equal_check("./", "."); _path_equal_check("./.", "."); _path_equal_check(".///.", "."); _path_equal_check(".///./", "."); _path_equal_check(".////", "."); _path_equal_check("//..//foo/", "/../foo"); _path_equal_check("///foo//./bar/.", "/foo/bar"); _path_equal_check(".//./foo//./bar/.", "foo/bar"); } /*****************************************************************************/ static void assert_path_find_first_component(const char *path, gboolean accept_dot_dot, const char *const *expected, int ret) { const char *p; for (p = path;;) { const char *e; int r; r = nm_path_find_first_component(&p, accept_dot_dot, &e); if (r <= 0) { if (r == 0) { if (path) g_assert(p == path + strlen(path)); else g_assert(!p); g_assert(!e); } g_assert(r == ret); g_assert(!expected || !*expected); return; } g_assert(e); g_assert(strcspn(e, "/") == (size_t) r); g_assert(strlen(*expected) == (size_t) r); g_assert(strncmp(e, *expected++, r) == 0); } } static void test_path_find_first_component(void) { gs_free char *hoge = NULL; char foo[NAME_MAX * 2]; /* Copied from systemd. * https://github.com/systemd/systemd/blob/bc85f8b51d962597360e982811e674c126850f56/src/test/test-path-util.c#L631 */ assert_path_find_first_component(NULL, false, NULL, 0); assert_path_find_first_component("", false, NULL, 0); assert_path_find_first_component("/", false, NULL, 0); assert_path_find_first_component(".", false, NULL, 0); assert_path_find_first_component("./", false, NULL, 0); assert_path_find_first_component("./.", false, NULL, 0); assert_path_find_first_component("..", false, NULL, -EINVAL); assert_path_find_first_component("/..", false, NULL, -EINVAL); assert_path_find_first_component("./..", false, NULL, -EINVAL); assert_path_find_first_component("////./././//.", false, NULL, 0); assert_path_find_first_component("a/b/c", false, NM_MAKE_STRV("a", "b", "c"), 0); assert_path_find_first_component("././//.///aa/bbb//./ccc", false, NM_MAKE_STRV("aa", "bbb", "ccc"), 0); assert_path_find_first_component("././//.///aa/.../../bbb//./ccc/.", false, NM_MAKE_STRV("aa", "..."), -EINVAL); assert_path_find_first_component("//./aaa///.//./.bbb/..///c.//d.dd///..eeee/.", false, NM_MAKE_STRV("aaa", ".bbb"), -EINVAL); assert_path_find_first_component("a/foo./b", false, NM_MAKE_STRV("a", "foo.", "b"), 0); assert_path_find_first_component(NULL, true, NULL, 0); assert_path_find_first_component("", true, NULL, 0); assert_path_find_first_component("/", true, NULL, 0); assert_path_find_first_component(".", true, NULL, 0); assert_path_find_first_component("./", true, NULL, 0); assert_path_find_first_component("./.", true, NULL, 0); assert_path_find_first_component("..", true, NM_MAKE_STRV(".."), 0); assert_path_find_first_component("/..", true, NM_MAKE_STRV(".."), 0); assert_path_find_first_component("./..", true, NM_MAKE_STRV(".."), 0); assert_path_find_first_component("////./././//.", true, NULL, 0); assert_path_find_first_component("a/b/c", true, NM_MAKE_STRV("a", "b", "c"), 0); assert_path_find_first_component("././//.///aa/bbb//./ccc", true, NM_MAKE_STRV("aa", "bbb", "ccc"), 0); assert_path_find_first_component("././//.///aa/.../../bbb//./ccc/.", true, NM_MAKE_STRV("aa", "...", "..", "bbb", "ccc"), 0); assert_path_find_first_component("//./aaa///.//./.bbb/..///c.//d.dd///..eeee/.", true, NM_MAKE_STRV("aaa", ".bbb", "..", "c.", "d.dd", "..eeee"), 0); assert_path_find_first_component("a/foo./b", true, NM_MAKE_STRV("a", "foo.", "b"), 0); memset(foo, 'a', sizeof(foo) - 1); foo[sizeof(foo) - 1] = '\0'; assert_path_find_first_component(foo, false, NULL, -EINVAL); assert_path_find_first_component(foo, true, NULL, -EINVAL); hoge = g_strjoin("", "a/b/c/", foo, "//d/e/.//f/", NULL); g_assert(hoge); assert_path_find_first_component(hoge, false, NM_MAKE_STRV("a", "b", "c"), -EINVAL); assert_path_find_first_component(hoge, true, NM_MAKE_STRV("a", "b", "c"), -EINVAL); } /*****************************************************************************/ static void assert_path_startswith(const char *path, const char *prefix, const char *skipped, const char *expected) { const char *p; p = nm_path_startswith(path, prefix); g_assert_cmpstr(p, ==, expected); if (p) { gs_free char *q = NULL; g_assert(skipped); q = g_strjoin("", skipped, p, NULL); g_assert_cmpstr(q, ==, path); g_assert(p == path + strlen(skipped)); } else g_assert(!skipped); } static void test_path_startswith(void) { assert_path_startswith("/foo/bar/barfoo/", "/foo", "/foo/", "bar/barfoo/"); assert_path_startswith("/foo/bar/barfoo/", "/foo/", "/foo/", "bar/barfoo/"); assert_path_startswith("/foo/bar/barfoo/", "/", "/", "foo/bar/barfoo/"); assert_path_startswith("/foo/bar/barfoo/", "////", "/", "foo/bar/barfoo/"); assert_path_startswith("/foo/bar/barfoo/", "/foo//bar/////barfoo///", "/foo/bar/barfoo/", ""); assert_path_startswith("/foo/bar/barfoo/", "/foo/bar/barfoo////", "/foo/bar/barfoo/", ""); assert_path_startswith("/foo/bar/barfoo/", "/foo/bar///barfoo/", "/foo/bar/barfoo/", ""); assert_path_startswith("/foo/bar/barfoo/", "/foo////bar/barfoo/", "/foo/bar/barfoo/", ""); assert_path_startswith("/foo/bar/barfoo/", "////foo/bar/barfoo/", "/foo/bar/barfoo/", ""); assert_path_startswith("/foo/bar/barfoo/", "/foo/bar/barfoo", "/foo/bar/barfoo/", ""); assert_path_startswith("/foo/bar/barfoo/", "/foo/bar/barfooa/", NULL, NULL); assert_path_startswith("/foo/bar/barfoo/", "/foo/bar/barfooa", NULL, NULL); assert_path_startswith("/foo/bar/barfoo/", "", NULL, NULL); assert_path_startswith("/foo/bar/barfoo/", "/bar/foo", NULL, NULL); assert_path_startswith("/foo/bar/barfoo/", "/f/b/b/", NULL, NULL); assert_path_startswith("/foo/bar/barfoo/", "/foo/bar/barfo", NULL, NULL); assert_path_startswith("/foo/bar/barfoo/", "/foo/bar/bar", NULL, NULL); assert_path_startswith("/foo/bar/barfoo/", "/fo", NULL, NULL); } /*****************************************************************************/ static void assert_path_simplify(const char *in, const char *out) { gs_free char *p = NULL; g_assert(in); p = g_strdup(in); nm_path_simplify(p); g_assert_cmpstr(p, ==, out); } static void test_path_simplify(void) { gs_free char *hoge = NULL; gs_free char *hoge_out = NULL; char foo[NAME_MAX * 2]; assert_path_simplify("", ""); assert_path_simplify("aaa/bbb////ccc", "aaa/bbb/ccc"); assert_path_simplify("//aaa/.////ccc", "/aaa/ccc"); assert_path_simplify("///", "/"); assert_path_simplify("///.//", "/"); assert_path_simplify("///.//.///", "/"); assert_path_simplify("////.././///../.", "/../.."); assert_path_simplify(".", "."); assert_path_simplify("./", "."); assert_path_simplify(".///.//./.", "."); assert_path_simplify(".///.//././/", "."); assert_path_simplify("//./aaa///.//./.bbb/..///c.//d.dd///..eeee/.", "/aaa/.bbb/../c./d.dd/..eeee"); assert_path_simplify("//./aaa///.//./.bbb/..///c.//d.dd///..eeee/..", "/aaa/.bbb/../c./d.dd/..eeee/.."); assert_path_simplify(".//./aaa///.//./.bbb/..///c.//d.dd///..eeee/..", "aaa/.bbb/../c./d.dd/..eeee/.."); assert_path_simplify("..//./aaa///.//./.bbb/..///c.//d.dd///..eeee/..", "../aaa/.bbb/../c./d.dd/..eeee/.."); memset(foo, 'a', sizeof(foo) - 1); foo[sizeof(foo) - 1] = '\0'; assert_path_simplify(foo, foo); hoge = g_strjoin("", "/", foo, NULL); g_assert(hoge); assert_path_simplify(hoge, hoge); nm_clear_g_free(&hoge); hoge = g_strjoin("", "a////.//././//./b///././/./c/////././//./", foo, "//.//////d/e/.//f/", NULL); g_assert(hoge); hoge_out = g_strjoin("", "a/b/c/", foo, "//.//////d/e/.//f/", NULL); g_assert(hoge_out); assert_path_simplify(hoge, hoge_out); } /*****************************************************************************/ static void test_hostname_is_valid(void) { g_assert(nm_hostname_is_valid("foobar", FALSE)); g_assert(nm_hostname_is_valid("foobar.com", FALSE)); g_assert(!nm_hostname_is_valid("foobar.com.", FALSE)); g_assert(nm_hostname_is_valid("fooBAR", FALSE)); g_assert(nm_hostname_is_valid("fooBAR.com", FALSE)); g_assert(!nm_hostname_is_valid("fooBAR.", FALSE)); g_assert(!nm_hostname_is_valid("fooBAR.com.", FALSE)); g_assert(!nm_hostname_is_valid("fööbar", FALSE)); g_assert(!nm_hostname_is_valid("", FALSE)); g_assert(!nm_hostname_is_valid(".", FALSE)); g_assert(!nm_hostname_is_valid("..", FALSE)); g_assert(!nm_hostname_is_valid("foobar.", FALSE)); g_assert(!nm_hostname_is_valid(".foobar", FALSE)); g_assert(!nm_hostname_is_valid("foo..bar", FALSE)); g_assert(!nm_hostname_is_valid("foo.bar..", FALSE)); G_STATIC_ASSERT_EXPR(NM_HOST_NAME_MAX <= HOST_NAME_MAX); #define _assert_hostname_length(n, valid) \ G_STMT_START \ { \ const gsize _n = (n); \ gs_free char *_h = g_strnfill(_n, 'x'); \ gboolean _valid; \ \ _valid = nm_hostname_is_valid(_h, FALSE); \ g_assert_cmpint(_valid, ==, (valid)); \ } \ G_STMT_END _assert_hostname_length(NM_HOST_NAME_MAX - 10, TRUE); _assert_hostname_length(NM_HOST_NAME_MAX - 1, TRUE); _assert_hostname_length(NM_HOST_NAME_MAX, TRUE); _assert_hostname_length(NM_HOST_NAME_MAX + 1, FALSE); _assert_hostname_length(NM_HOST_NAME_MAX + 10, FALSE); g_assert(!nm_hostname_is_valid( "au-xph5-rvgrdsb5hcxc-47et3a5vvkrc-server-wyoz4elpdpe3.openstack.local", FALSE)); g_assert(nm_hostname_is_valid("foobar", TRUE)); g_assert(nm_hostname_is_valid("foobar.com", TRUE)); g_assert(nm_hostname_is_valid("foobar.com.", TRUE)); g_assert(nm_hostname_is_valid("fooBAR", TRUE)); g_assert(nm_hostname_is_valid("fooBAR.com", TRUE)); g_assert(!nm_hostname_is_valid("fooBAR.", TRUE)); g_assert(nm_hostname_is_valid("fooBAR.com.", TRUE)); g_assert(!nm_hostname_is_valid("fööbar", TRUE)); g_assert(!nm_hostname_is_valid("", TRUE)); g_assert(!nm_hostname_is_valid(".", TRUE)); g_assert(!nm_hostname_is_valid("..", TRUE)); g_assert(!nm_hostname_is_valid("foobar.", TRUE)); g_assert(!nm_hostname_is_valid(".foobar", TRUE)); g_assert(!nm_hostname_is_valid("foo..bar", TRUE)); g_assert(!nm_hostname_is_valid("foo.bar..", TRUE)); g_assert( nm_hostname_is_valid("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", TRUE)); g_assert( !nm_hostname_is_valid("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", TRUE)); } /*****************************************************************************/ static void test_inet_utils(void) { g_assert(nm_ip_addr_is_site_local(AF_INET, nmtst_inet_from_string(AF_INET, "172.16.0.1"))); g_assert(nm_ip_addr_is_site_local(AF_INET, nmtst_inet_from_string(AF_INET, "172.17.0.1"))); g_assert(nm_ip_addr_is_site_local(AF_INET, nmtst_inet_from_string(AF_INET, "192.168.7.5"))); g_assert(!nm_ip_addr_is_site_local(AF_INET, nmtst_inet_from_string(AF_INET, "192.0.7.5"))); g_assert(nm_ip_addr_is_site_local(AF_INET6, nmtst_inet_from_string(AF_INET6, "fec0::"))); g_assert(!nm_ip_addr_is_site_local(AF_INET6, nmtst_inet_from_string(AF_INET6, "fc00::"))); } /*****************************************************************************/ static void test_ip6_addr_common_prefix_len(void) { struct in6_addr a; struct in6_addr b; /* identical addresses -> 128 */ a = nmtst_inet6_from_string("2001:db8::1"); b = nmtst_inet6_from_string("2001:db8::1"); g_assert_cmpuint(nm_ip6_addr_common_prefix_len(&a, &b), ==, 128); /* completely different -> 0 */ a = nmtst_inet6_from_string("8000::"); b = nmtst_inet6_from_string("::"); g_assert_cmpuint(nm_ip6_addr_common_prefix_len(&a, &b), ==, 0); /* first 64 bits in common, differ at bit 65 */ a = nmtst_inet6_from_string("2001:db8:abcd:1234:8000::"); b = nmtst_inet6_from_string("2001:db8:abcd:1234::"); g_assert_cmpuint(nm_ip6_addr_common_prefix_len(&a, &b), ==, 64); /* same /48 prefix */ a = nmtst_inet6_from_string("2001:db8:abcd::"); b = nmtst_inet6_from_string("2001:db8:abcd:ffff::"); g_assert_cmpuint(nm_ip6_addr_common_prefix_len(&a, &b), ==, 48); /* differ in 5th bit -> 4 common bits */ a = nmtst_inet6_from_string("f800::"); b = nmtst_inet6_from_string("f000::"); g_assert_cmpuint(nm_ip6_addr_common_prefix_len(&a, &b), ==, 4); /* differ in 2nd bit -> 1 common bit */ a = nmtst_inet6_from_string("c000::"); b = nmtst_inet6_from_string("8000::"); g_assert_cmpuint(nm_ip6_addr_common_prefix_len(&a, &b), ==, 1); /* both zero -> 128 */ a = nmtst_inet6_from_string("::"); b = nmtst_inet6_from_string("::"); g_assert_cmpuint(nm_ip6_addr_common_prefix_len(&a, &b), ==, 128); /* first 120 bits in common, differ at MSB of last byte */ a = nmtst_inet6_from_string("2001:db8::80"); b = nmtst_inet6_from_string("2001:db8::"); g_assert_cmpuint(nm_ip6_addr_common_prefix_len(&a, &b), ==, 120); /* first 127 bits in common, differ only in last bit */ a = nmtst_inet6_from_string("2001:db8::fe"); b = nmtst_inet6_from_string("2001:db8::ff"); g_assert_cmpuint(nm_ip6_addr_common_prefix_len(&a, &b), ==, 127); } /*****************************************************************************/ static gboolean _inet_parse(int addr_family, const char *str, gboolean accept_legacy, gpointer out_addr) { int addr_family2 = -1; int *const p_addr_family2 = nmtst_get_rand_bool() ? &addr_family2 : NULL; NMIPAddr addr; gboolean success; g_assert(NM_IN_SET(addr_family, AF_INET, AF_INET6)); success = nm_inet_parse_bin_full((p_addr_family2 && nmtst_get_rand_bool()) ? AF_UNSPEC : addr_family, accept_legacy, str, p_addr_family2, &addr); if (success) { g_assert(!p_addr_family2 || NM_IN_SET(*p_addr_family2, AF_INET, AF_INET6)); if (p_addr_family2 && *p_addr_family2 != addr_family) { success = FALSE; } else g_assert(!p_addr_family2 || *p_addr_family2 == addr_family); } else g_assert(addr_family2 == -1); if (out_addr && success) nm_ip_addr_set(addr_family, out_addr, &addr); return success; } #define _inet_parse_fail(check, accept_legacy) \ G_STMT_START \ { \ NMIPAddr _addr; \ gboolean _success; \ \ _success = _inet_parse(nmtst_get_rand_bool() ? AF_INET : AF_INET6, \ "" check "", \ (accept_legacy), \ nmtst_get_rand_bool() ? &_addr : NULL); \ g_assert(!_success); \ } \ G_STMT_END #define _inet_parse_good(check, expected, accept_legacy) \ G_STMT_START \ { \ int _accept_legacy = (accept_legacy); \ const char *const _check = "" check ""; \ const char *const _expected = expected ?: _check; \ NMIPAddr _addr[2]; \ gboolean _success[2]; \ \ if (_accept_legacy == -1) \ _accept_legacy = nmtst_get_rand_bool(); \ \ _success[0] = _inet_parse(AF_INET6, _check, _accept_legacy, &_addr[0]); \ _success[1] = _inet_parse(AF_INET, _check, _accept_legacy, &_addr[1]); \ \ g_assert(NM_IN_SET(_success[0], FALSE, TRUE)); \ g_assert(NM_IN_SET(_success[1], FALSE, TRUE)); \ g_assert(_success[0] != _success[1]); \ \ if (_success[0]) \ nmtst_assert_ip6_address(&_addr[0].addr6, _expected); \ else \ nmtst_assert_ip4_address(_addr[1].addr4, _expected); \ \ if (_success[1]) { \ in_addr_t _a4; \ int _r; \ \ _r = nmtst_inet_aton(_check, &_a4); \ g_assert_cmpint(_r, ==, 0); \ nmtst_assert_ip4_address(_a4, _expected); \ } \ } \ G_STMT_END static void test_inet_parse_ip4_legacy(void) { _inet_parse_fail("", -1); _inet_parse_fail(" ", -1); _inet_parse_fail("a", -1); _inet_parse_fail("0", -1); _inet_parse_fail("0.1", -1); _inet_parse_fail("0.4.1", -1); _inet_parse_fail("1.2.3.05", FALSE); _inet_parse_fail("192.000.002.010", FALSE); _inet_parse_fail("1.2.3..5", -1); _inet_parse_fail("1.2.3.0x", -1); _inet_parse_fail("0xC0000234", -1); _inet_parse_fail("192.0.2.2X", -1); _inet_parse_fail("192.0.2.3 Y", -1); _inet_parse_fail("192.0.2.4\nZ", -1); _inet_parse_fail("192.0.2.5\tT", -1); _inet_parse_fail("192.0.2.6 Y", -1); _inet_parse_fail("192.0.2.7\n", -1); _inet_parse_fail("192.0.2.7\t", -1); _inet_parse_fail("192.0.2.7 ", -1); _inet_parse_fail("00x0019.0000001.000000.0x1", -1); _inet_parse_fail("192.0.2.7.", -1); _inet_parse_fail("192.0.2.7.0", -1); _inet_parse_good("192.0.2.1", NULL, -1); _inet_parse_good("1.2.3.4", NULL, -1); _inet_parse_good("192.167.3.4", NULL, -1); _inet_parse_good("192.000.002.010", "192.0.2.8", TRUE); _inet_parse_good("255.000.000.000", "255.0.0.0", TRUE); _inet_parse_good("1.2.3.05", "1.2.3.5", TRUE); _inet_parse_good("01.2.3.05", "1.2.3.5", TRUE); _inet_parse_good("192.00167.0003.4", "192.119.3.4", TRUE); _inet_parse_good("0x19.00167.0003.4", "25.119.3.4", TRUE); _inet_parse_good("0x19.000000167.0000003.4", "25.119.3.4", TRUE); _inet_parse_good("0x0019.000000167.0000003.04", "25.119.3.4", TRUE); _inet_parse_good("0x0019.0000001.000000.0x1", "25.1.0.1", TRUE); } /*****************************************************************************/ static void test_garray(void) { gs_unref_array GArray *arr = NULL; int v; arr = g_array_new(FALSE, FALSE, sizeof(int)); g_assert(nm_g_array_index_p(arr, int, 0) == (gpointer) arr->data); v = 1; g_array_append_val(arr, v); g_assert(nm_g_array_index_p(arr, int, 0) == (gpointer) arr->data); g_assert(nm_g_array_index_p(arr, int, 1) == ((int *) ((gpointer) arr->data)) + 1); g_assert(&nm_g_array_index(arr, int, 0) == (gpointer) arr->data); g_assert(&nm_g_array_first(arr, int) == (gpointer) arr->data); g_assert(&nm_g_array_last(arr, int) == (gpointer) arr->data); g_assert(nm_g_array_index(arr, int, 0) == 1); v = 2; g_array_append_val(arr, v); g_assert(nm_g_array_index_p(arr, int, 0) == (gpointer) arr->data); g_assert(nm_g_array_index_p(arr, int, 1) == ((int *) ((gpointer) arr->data)) + 1); g_assert(nm_g_array_index_p(arr, int, 2) == ((int *) ((gpointer) arr->data)) + 2); g_assert(&nm_g_array_index(arr, int, 0) == (gpointer) arr->data); g_assert(&nm_g_array_first(arr, int) == (gpointer) arr->data); g_assert(&nm_g_array_last(arr, int) == ((int *) ((gpointer) arr->data)) + 1); g_assert(nm_g_array_index(arr, int, 0) == 1); g_assert(nm_g_array_index(arr, int, 1) == 2); } /*****************************************************************************/ static int _prioq_cmp(gconstpointer a, gconstpointer b) { NM_CMP_DIRECT(*((const guint32 *) a), *((const guint32 *) b)); return 0; } static int _prioq_cmp_with_data(gconstpointer a, gconstpointer b, gpointer user_data) { return _prioq_cmp(a, b); } static void test_nm_prioq(void) { nm_auto_prioq NMPrioq q = NM_PRIOQ_ZERO; guint32 data[200]; const guint32 *data_pop[200]; guint data_idx[G_N_ELEMENTS(data)]; guint i; guint n; guint m; gpointer p; if (nmtst_get_rand_one_case_in(10)) return; if (nmtst_get_rand_bool()) nm_prioq_init(&q, _prioq_cmp); else nm_prioq_init_with_data(&q, _prioq_cmp_with_data, NULL); g_assert(nm_prioq_size(&q) == 0); if (nmtst_get_rand_one_case_in(100)) return; for (i = 0; i < G_N_ELEMENTS(data); i++) { data[i] = nmtst_get_rand_uint32() % G_N_ELEMENTS(data); data_idx[i] = NM_PRIOQ_IDX_NULL; } nm_prioq_put(&q, &data[0], NULL); g_assert(nm_prioq_size(&q) == 1); p = nm_prioq_pop(&q); g_assert(p == &data[0]); g_assert(nm_prioq_size(&q) == 0); g_assert(!nm_prioq_pop(&q)); n = nmtst_get_rand_uint32() % G_N_ELEMENTS(data); for (i = 0; i < n; i++) nm_prioq_put(&q, &data[i], &data_idx[i]); m = n; for (i = 0; i < n; i++) { if (!nmtst_get_rand_bool()) continue; data[i] = nmtst_get_rand_uint32() % G_N_ELEMENTS(data); switch (nmtst_get_rand_uint32() % 4) { case 0: nm_prioq_reshuffle(&q, &data[i], &data_idx[i]); break; case 1: nm_prioq_remove(&q, &data[i], nmtst_get_rand_bool() ? &data_idx[i] : NULL); m--; break; case 2: nm_prioq_update(&q, &data[i], &data_idx[i], TRUE); break; case 3: nm_prioq_update(&q, &data[i], nmtst_get_rand_bool() ? &data_idx[i] : NULL, FALSE); m--; break; } } g_assert_cmpint(nm_prioq_size(&q), ==, m); if (nmtst_get_rand_one_case_in(50)) return; for (i = 0; i < m; i++) { data_pop[i] = nm_prioq_pop(&q); g_assert(data_pop[i]); g_assert_cmpint(*data_pop[i], >=, 0); g_assert_cmpint(*data_pop[i], <, G_N_ELEMENTS(data)); g_assert(data_pop[i] >= &data[0]); g_assert(data_pop[i] < &data[n]); if (i > 0) { g_assert(_prioq_cmp(data_pop[i - 1], data_pop[i]) <= 0); g_assert_cmpint(*data_pop[i - 1], <=, *data_pop[i]); } } g_assert(!nm_prioq_pop(&q)); g_assert(nm_prioq_size(&q) == 0); } /*****************************************************************************/ static const char * _getpwuid_name(uid_t uid) { static struct passwd *pw; pw = getpwuid(uid); return pw ? nm_str_not_empty(pw->pw_name) : NULL; } static void test_uid_to_name(void) { int i; for (i = 0; i < 20; i++) { gs_free char *name = NULL; gs_free struct passwd *pw = NULL; uid_t uid; if (i < 5) uid = i; else uid = nmtst_get_rand_uint32() % 2000u; name = nm_utils_uid_to_name(uid); g_assert_cmpstr(name, ==, _getpwuid_name(uid)); pw = nm_getpwuid(uid); g_assert_cmpstr(name, ==, nm_passwd_name(pw)); } } /*****************************************************************************/ 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 main(int argc, char **argv) { nmtst_init(&argc, &argv, TRUE); g_test_add_func("/general/test_nm_static_assert", test_nm_static_assert); g_test_add_func("/general/test_max", test_max); 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_timespect_to", test_timespect_to); 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_loopback", test_nm_ip4_addr_is_loopback); g_test_add_func("/general/test_nm_ip4_addr_netmask_from_prefix", test_nm_ip4_addr_netmask_from_prefix); g_test_add_func("/general/test_nm_ip6_addr_get_subnet_id", test_nm_ip6_addr_get_subnet_id); 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); g_test_add_func("/general/test_nm_g_source_sentinel", test_nm_g_source_sentinel); g_test_add_func("/general/test_nm_ascii", test_nm_ascii); g_test_add_func("/general/test_parse_env_file", test_parse_env_file); g_test_add_func("/general/test_unbase64char", test_unbase64char); g_test_add_func("/general/test_unbase64mem1", test_unbase64mem1); g_test_add_func("/general/test_unbase64mem2", test_unbase64mem2); g_test_add_func("/general/test_unbase64mem3", test_unbase64mem3); g_test_add_func("/general/test_path_compare", test_path_compare); g_test_add_func("/general/test_path_equal", test_path_equal); g_test_add_func("/general/test_path_find_first_component", test_path_find_first_component); g_test_add_func("/general/test_path_startswith", test_path_startswith); g_test_add_func("/general/test_path_simplify", test_path_simplify); g_test_add_func("/general/test_hostname_is_valid", test_hostname_is_valid); g_test_add_func("/general/test_inet_utils", test_inet_utils); g_test_add_func("/general/test_ip6_addr_common_prefix_len", test_ip6_addr_common_prefix_len); g_test_add_func("/general/test_inet_parse_ip4_legacy", test_inet_parse_ip4_legacy); g_test_add_func("/general/test_garray", test_garray); g_test_add_func("/general/test_nm_prioq", test_nm_prioq); 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(); }