mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-03-28 10:30:03 +01:00
This reverts commit 476e33c3f3632bd32370fadc67b10d61da9a4098. We’ve decided to remove `G_OS_DARWIN` in favour of recommending people use `__APPLE__` instead. As per the discussion on #2802 and linked issues, * Adding a new define shifts the complexity from “which of these platform-provided defines do I use” to “which platform-provided defines does G_OS_DARWIN use” * There should ideally be no cases where a user of GLib has to use their own platform-specific code, since GLib should be providing appropriate abstractions * Providing a single `G_OS_DARWIN` to cover all Apple products (macOS and iOS) hides the complexity of what the user is actually testing: are they testing for the Mach kernel, the Carbon and/or Cocoa user space toolkits, macOS vs iOS vs tvOS, etc Helps: #2802
1187 lines
29 KiB
C
1187 lines
29 KiB
C
/* Unit tests for utilities
|
||
* Copyright (C) 2010 Red Hat, Inc.
|
||
*
|
||
* SPDX-License-Identifier: LicenseRef-old-glib-tests
|
||
*
|
||
* This work is provided "as is"; redistribution and modification
|
||
* in whole or in part, in any medium, physical or electronic is
|
||
* permitted without restriction.
|
||
*
|
||
* This work is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||
*
|
||
* In no event shall the authors or contributors be liable for any
|
||
* direct, indirect, incidental, special, exemplary, or consequential
|
||
* damages (including, but not limited to, procurement of substitute
|
||
* goods or services; loss of use, data, or profits; or business
|
||
* interruption) however caused and on any theory of liability, whether
|
||
* in contract, strict liability, or tort (including negligence or
|
||
* otherwise) arising in any way out of the use of this software, even
|
||
* if advised of the possibility of such damage.
|
||
*
|
||
* Author: Matthias Clasen
|
||
*/
|
||
|
||
#ifndef GLIB_DISABLE_DEPRECATION_WARNINGS
|
||
#define GLIB_DISABLE_DEPRECATION_WARNINGS
|
||
#endif
|
||
|
||
#include "glib.h"
|
||
#include "glib-private.h"
|
||
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <stdarg.h>
|
||
#ifdef G_OS_UNIX
|
||
#include <sys/utsname.h>
|
||
#endif
|
||
#ifdef G_OS_WIN32
|
||
#include <windows.h>
|
||
#endif
|
||
|
||
static gboolean
|
||
strv_check (const gchar * const *strv, ...)
|
||
{
|
||
va_list args;
|
||
gchar *s;
|
||
gint i;
|
||
|
||
va_start (args, strv);
|
||
for (i = 0; strv[i]; i++)
|
||
{
|
||
s = va_arg (args, gchar*);
|
||
if (g_strcmp0 (strv[i], s) != 0)
|
||
{
|
||
va_end (args);
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
va_end (args);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
static void
|
||
test_language_names (void)
|
||
{
|
||
const gchar * const *names;
|
||
|
||
g_setenv ("LANGUAGE", "de:en_US", TRUE);
|
||
names = g_get_language_names ();
|
||
g_assert (strv_check (names, "de", "en_US", "en", "C", NULL));
|
||
|
||
g_setenv ("LANGUAGE", "tt_RU.UTF-8@iqtelif", TRUE);
|
||
names = g_get_language_names ();
|
||
g_assert (strv_check (names,
|
||
"tt_RU.UTF-8@iqtelif",
|
||
"tt_RU@iqtelif",
|
||
"tt.UTF-8@iqtelif",
|
||
"tt@iqtelif",
|
||
"tt_RU.UTF-8",
|
||
"tt_RU",
|
||
"tt.UTF-8",
|
||
"tt",
|
||
"C",
|
||
NULL));
|
||
}
|
||
|
||
static void
|
||
test_locale_variants (void)
|
||
{
|
||
char **v;
|
||
|
||
v = g_get_locale_variants ("fr_BE");
|
||
g_assert (strv_check ((const gchar * const *) v, "fr_BE", "fr", NULL));
|
||
g_strfreev (v);
|
||
|
||
v = g_get_locale_variants ("sr_SR@latin");
|
||
g_assert (strv_check ((const gchar * const *) v, "sr_SR@latin", "sr@latin", "sr_SR", "sr", NULL));
|
||
g_strfreev (v);
|
||
}
|
||
|
||
static void
|
||
test_version (void)
|
||
{
|
||
if (g_test_verbose ())
|
||
g_printerr ("(header %d.%d.%d library %d.%d.%d) ",
|
||
GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION,
|
||
glib_major_version, glib_minor_version, glib_micro_version);
|
||
|
||
g_assert (glib_check_version (GLIB_MAJOR_VERSION,
|
||
GLIB_MINOR_VERSION,
|
||
GLIB_MICRO_VERSION) == NULL);
|
||
g_assert (glib_check_version (GLIB_MAJOR_VERSION,
|
||
GLIB_MINOR_VERSION,
|
||
0) == NULL);
|
||
g_assert (glib_check_version (GLIB_MAJOR_VERSION - 1,
|
||
0,
|
||
0) != NULL);
|
||
g_assert (glib_check_version (GLIB_MAJOR_VERSION + 1,
|
||
0,
|
||
0) != NULL);
|
||
g_assert (glib_check_version (GLIB_MAJOR_VERSION,
|
||
GLIB_MINOR_VERSION + 1,
|
||
0) != NULL);
|
||
/* don't use + 1 here, since a +/-1 difference can
|
||
* happen due to post-release version bumps in git
|
||
*/
|
||
g_assert (glib_check_version (GLIB_MAJOR_VERSION,
|
||
GLIB_MINOR_VERSION,
|
||
GLIB_MICRO_VERSION + 3) != NULL);
|
||
}
|
||
|
||
static const gchar *argv0;
|
||
|
||
static void
|
||
test_appname (void)
|
||
{
|
||
const gchar *prgname;
|
||
const gchar *appname;
|
||
|
||
prgname = g_get_prgname ();
|
||
appname = g_get_application_name ();
|
||
g_assert_cmpstr (prgname, ==, argv0);
|
||
g_assert_cmpstr (appname, ==, prgname);
|
||
|
||
g_set_prgname ("prgname");
|
||
|
||
prgname = g_get_prgname ();
|
||
appname = g_get_application_name ();
|
||
g_assert_cmpstr (prgname, ==, "prgname");
|
||
g_assert_cmpstr (appname, ==, "prgname");
|
||
|
||
g_set_application_name ("appname");
|
||
|
||
prgname = g_get_prgname ();
|
||
appname = g_get_application_name ();
|
||
g_assert_cmpstr (prgname, ==, "prgname");
|
||
g_assert_cmpstr (appname, ==, "appname");
|
||
}
|
||
|
||
static gpointer
|
||
thread_prgname_check (gpointer data)
|
||
{
|
||
gint *n_threads_got_prgname = (gint *) data;
|
||
const gchar *old_prgname;
|
||
|
||
old_prgname = g_get_prgname ();
|
||
g_assert_cmpstr (old_prgname, ==, "prgname");
|
||
|
||
g_atomic_int_inc (n_threads_got_prgname);
|
||
|
||
while (g_strcmp0 (g_get_prgname (), "prgname2") != 0);
|
||
|
||
return NULL;
|
||
}
|
||
|
||
static void
|
||
test_prgname_thread_safety (void)
|
||
{
|
||
gsize i;
|
||
gint n_threads_got_prgname;
|
||
GThread *threads[4];
|
||
|
||
g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/847");
|
||
g_test_summary ("Test that threads racing to get and set the program name "
|
||
"always receive a valid program name.");
|
||
|
||
g_set_prgname ("prgname");
|
||
g_atomic_int_set (&n_threads_got_prgname, 0);
|
||
|
||
for (i = 0; i < G_N_ELEMENTS (threads); i++)
|
||
threads[i] = g_thread_new (NULL, thread_prgname_check, &n_threads_got_prgname);
|
||
|
||
while (g_atomic_int_get (&n_threads_got_prgname) != G_N_ELEMENTS (threads))
|
||
g_usleep (50);
|
||
|
||
g_set_prgname ("prgname2");
|
||
|
||
/* Wait for all the workers to exit. */
|
||
for (i = 0; i < G_N_ELEMENTS (threads); i++)
|
||
g_thread_join (threads[i]);
|
||
|
||
/* reset prgname */
|
||
g_set_prgname ("prgname");
|
||
}
|
||
|
||
static void
|
||
test_tmpdir (void)
|
||
{
|
||
g_test_bug ("https://bugzilla.gnome.org/show_bug.cgi?id=627969");
|
||
g_assert_cmpstr (g_get_tmp_dir (), !=, "");
|
||
}
|
||
|
||
#if defined(__GNUC__) && (__GNUC__ >= 4)
|
||
#define TEST_BUILTINS 1
|
||
#else
|
||
#define TEST_BUILTINS 0
|
||
#endif
|
||
|
||
#if TEST_BUILTINS
|
||
static gint
|
||
builtin_bit_nth_lsf1 (gulong mask, gint nth_bit)
|
||
{
|
||
if (nth_bit >= 0)
|
||
{
|
||
if (G_LIKELY (nth_bit < GLIB_SIZEOF_LONG * 8 - 1))
|
||
mask &= -(1UL << (nth_bit + 1));
|
||
else
|
||
mask = 0;
|
||
}
|
||
return __builtin_ffsl (mask) - 1;
|
||
}
|
||
|
||
static gint
|
||
builtin_bit_nth_lsf2 (gulong mask, gint nth_bit)
|
||
{
|
||
if (nth_bit >= 0)
|
||
{
|
||
if (G_LIKELY (nth_bit < GLIB_SIZEOF_LONG * 8 - 1))
|
||
mask &= -(1UL << (nth_bit + 1));
|
||
else
|
||
mask = 0;
|
||
}
|
||
return mask ? __builtin_ctzl (mask) : -1;
|
||
}
|
||
|
||
static gint
|
||
builtin_bit_nth_msf (gulong mask, gint nth_bit)
|
||
{
|
||
if (nth_bit >= 0 && nth_bit < GLIB_SIZEOF_LONG * 8)
|
||
mask &= (1UL << nth_bit) - 1;
|
||
return mask ? GLIB_SIZEOF_LONG * 8 - 1 - __builtin_clzl (mask) : -1;
|
||
}
|
||
|
||
static guint
|
||
builtin_bit_storage (gulong number)
|
||
{
|
||
return number ? GLIB_SIZEOF_LONG * 8 - __builtin_clzl (number) : 1;
|
||
}
|
||
#endif
|
||
|
||
static gint
|
||
naive_bit_nth_lsf (gulong mask, gint nth_bit)
|
||
{
|
||
if (G_UNLIKELY (nth_bit < -1))
|
||
nth_bit = -1;
|
||
while (nth_bit < ((GLIB_SIZEOF_LONG * 8) - 1))
|
||
{
|
||
nth_bit++;
|
||
if (mask & (1UL << nth_bit))
|
||
return nth_bit;
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
static gint
|
||
naive_bit_nth_msf (gulong mask, gint nth_bit)
|
||
{
|
||
if (nth_bit < 0 || G_UNLIKELY (nth_bit > GLIB_SIZEOF_LONG * 8))
|
||
nth_bit = GLIB_SIZEOF_LONG * 8;
|
||
while (nth_bit > 0)
|
||
{
|
||
nth_bit--;
|
||
if (mask & (1UL << nth_bit))
|
||
return nth_bit;
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
static guint
|
||
naive_bit_storage (gulong number)
|
||
{
|
||
guint n_bits = 0;
|
||
|
||
do
|
||
{
|
||
n_bits++;
|
||
number >>= 1;
|
||
}
|
||
while (number);
|
||
return n_bits;
|
||
}
|
||
|
||
static void
|
||
test_basic_bits (void)
|
||
{
|
||
gulong i;
|
||
gint nth_bit;
|
||
|
||
/* we loop like this: 0, -1, 1, -2, 2, -3, 3, ... */
|
||
for (i = 0; (glong) i < 1500; i = -(i + ((glong) i >= 0)))
|
||
{
|
||
guint naive_bit_storage_i = naive_bit_storage (i);
|
||
|
||
/* Test the g_bit_*() implementations against the compiler builtins (if
|
||
* available), and against a slow-but-correct ‘naive’ implementation.
|
||
* They should all agree.
|
||
*
|
||
* The macro and function versions of the g_bit_*() functions are tested,
|
||
* hence one call with the function name in brackets (to avoid it being
|
||
* expanded as a macro). */
|
||
#if TEST_BUILTINS
|
||
g_assert_cmpint (naive_bit_storage_i, ==, builtin_bit_storage (i));
|
||
#endif
|
||
g_assert_cmpint (naive_bit_storage_i, ==, g_bit_storage (i));
|
||
g_assert_cmpint (naive_bit_storage_i, ==, (g_bit_storage) (i));
|
||
|
||
for (nth_bit = -3; nth_bit <= 2 + GLIB_SIZEOF_LONG * 8; nth_bit++)
|
||
{
|
||
gint naive_bit_nth_lsf_i_nth_bit = naive_bit_nth_lsf (i, nth_bit);
|
||
gint naive_bit_nth_msf_i_nth_bit = naive_bit_nth_msf (i, nth_bit);
|
||
|
||
#if TEST_BUILTINS
|
||
g_assert_cmpint (naive_bit_nth_lsf_i_nth_bit, ==,
|
||
builtin_bit_nth_lsf1 (i, nth_bit));
|
||
g_assert_cmpint (naive_bit_nth_lsf_i_nth_bit, ==,
|
||
builtin_bit_nth_lsf2 (i, nth_bit));
|
||
#endif
|
||
g_assert_cmpint (naive_bit_nth_lsf_i_nth_bit, ==,
|
||
g_bit_nth_lsf (i, nth_bit));
|
||
g_assert_cmpint (naive_bit_nth_lsf_i_nth_bit, ==,
|
||
(g_bit_nth_lsf) (i, nth_bit));
|
||
|
||
#if TEST_BUILTINS
|
||
g_assert_cmpint (naive_bit_nth_msf_i_nth_bit, ==,
|
||
builtin_bit_nth_msf (i, nth_bit));
|
||
#endif
|
||
g_assert_cmpint (naive_bit_nth_msf_i_nth_bit, ==,
|
||
g_bit_nth_msf (i, nth_bit));
|
||
g_assert_cmpint (naive_bit_nth_msf_i_nth_bit, ==,
|
||
(g_bit_nth_msf) (i, nth_bit));
|
||
}
|
||
}
|
||
}
|
||
|
||
static void
|
||
test_bits (void)
|
||
{
|
||
gulong mask;
|
||
gint max_bit;
|
||
gint i, pos;
|
||
|
||
pos = g_bit_nth_lsf (0, -1);
|
||
g_assert_cmpint (pos, ==, -1);
|
||
|
||
max_bit = sizeof (gulong) * 8;
|
||
for (i = 0; i < max_bit; i++)
|
||
{
|
||
mask = 1UL << i;
|
||
|
||
pos = g_bit_nth_lsf (mask, -1);
|
||
g_assert_cmpint (pos, ==, i);
|
||
|
||
pos = g_bit_nth_lsf (mask, i - 3);
|
||
g_assert_cmpint (pos , ==, i);
|
||
|
||
pos = g_bit_nth_lsf (mask, i);
|
||
g_assert_cmpint (pos , ==, -1);
|
||
|
||
pos = g_bit_nth_lsf (mask, i + 1);
|
||
g_assert_cmpint (pos , ==, -1);
|
||
}
|
||
|
||
pos = g_bit_nth_msf (0, -1);
|
||
g_assert_cmpint (pos, ==, -1);
|
||
|
||
for (i = 0; i < max_bit; i++)
|
||
{
|
||
mask = 1UL << i;
|
||
|
||
pos = g_bit_nth_msf (mask, -1);
|
||
g_assert_cmpint (pos, ==, i);
|
||
|
||
pos = g_bit_nth_msf (mask, i + 3);
|
||
g_assert_cmpint (pos , ==, i);
|
||
|
||
pos = g_bit_nth_msf (mask, i);
|
||
g_assert_cmpint (pos , ==, -1);
|
||
|
||
if (i > 0)
|
||
{
|
||
pos = g_bit_nth_msf (mask, i - 1);
|
||
g_assert_cmpint (pos , ==, -1);
|
||
}
|
||
}
|
||
}
|
||
|
||
static void
|
||
test_swap (void)
|
||
{
|
||
guint16 a16, b16;
|
||
guint32 a32, b32;
|
||
guint64 a64, b64;
|
||
|
||
a16 = 0xaabb;
|
||
b16 = 0xbbaa;
|
||
|
||
g_assert_cmpint (GUINT16_SWAP_LE_BE (a16), ==, b16);
|
||
|
||
a32 = 0xaaaabbbb;
|
||
b32 = 0xbbbbaaaa;
|
||
|
||
g_assert_cmpint (GUINT32_SWAP_LE_BE (a32), ==, b32);
|
||
|
||
a64 = G_GUINT64_CONSTANT(0xaaaaaaaabbbbbbbb);
|
||
b64 = G_GUINT64_CONSTANT(0xbbbbbbbbaaaaaaaa);
|
||
|
||
g_assert_cmpint (GUINT64_SWAP_LE_BE (a64), ==, b64);
|
||
}
|
||
|
||
static void
|
||
test_find_program (void)
|
||
{
|
||
gchar *res;
|
||
|
||
#ifdef G_OS_UNIX
|
||
gchar *relative_path;
|
||
gchar *absolute_path;
|
||
gchar *cwd;
|
||
gsize i;
|
||
|
||
res = g_find_program_in_path ("sh");
|
||
g_assert (res != NULL);
|
||
g_free (res);
|
||
|
||
res = g_find_program_in_path ("/bin/sh");
|
||
g_assert (res != NULL);
|
||
g_free (res);
|
||
|
||
cwd = g_get_current_dir ();
|
||
absolute_path = g_find_program_in_path ("sh");
|
||
relative_path = g_strdup (absolute_path);
|
||
for (i = 0; cwd[i] != '\0'; i++)
|
||
{
|
||
if (cwd[i] == '/' && cwd[i + 1] != '\0')
|
||
{
|
||
gchar *relative_path_2 = g_strconcat ("../", relative_path, NULL);
|
||
g_free (relative_path);
|
||
relative_path = relative_path_2;
|
||
}
|
||
}
|
||
res = g_find_program_in_path (relative_path);
|
||
g_assert_nonnull (res);
|
||
g_assert_true (g_path_is_absolute (res));
|
||
g_free (cwd);
|
||
g_free (absolute_path);
|
||
g_free (relative_path);
|
||
g_free (res);
|
||
|
||
#else
|
||
/* There's not a lot we can search for that would reliably work both
|
||
* on real Windows and mingw.
|
||
*/
|
||
#endif
|
||
|
||
res = g_find_program_in_path ("this_program_does_not_exit");
|
||
g_assert (res == NULL);
|
||
|
||
res = g_find_program_in_path ("/bin");
|
||
g_assert (res == NULL);
|
||
|
||
res = g_find_program_in_path ("/etc/passwd");
|
||
g_assert (res == NULL);
|
||
}
|
||
|
||
static void
|
||
test_debug (void)
|
||
{
|
||
GDebugKey keys[] = {
|
||
{ "key1", 1 },
|
||
{ "key2", 2 },
|
||
{ "key3", 4 },
|
||
};
|
||
guint res;
|
||
|
||
res = g_parse_debug_string (NULL, keys, G_N_ELEMENTS (keys));
|
||
g_assert_cmpint (res, ==, 0);
|
||
|
||
res = g_parse_debug_string ("foobabla;#!%!$%112 223", keys, G_N_ELEMENTS (keys));
|
||
g_assert_cmpint (res, ==, 0);
|
||
|
||
res = g_parse_debug_string ("key1:key2", keys, G_N_ELEMENTS (keys));
|
||
g_assert_cmpint (res, ==, 3);
|
||
|
||
res = g_parse_debug_string ("key1;key2", keys, G_N_ELEMENTS (keys));
|
||
g_assert_cmpint (res, ==, 3);
|
||
|
||
res = g_parse_debug_string ("key1,key2", keys, G_N_ELEMENTS (keys));
|
||
g_assert_cmpint (res, ==, 3);
|
||
|
||
res = g_parse_debug_string ("key1 key2", keys, G_N_ELEMENTS (keys));
|
||
g_assert_cmpint (res, ==, 3);
|
||
|
||
res = g_parse_debug_string ("key1\tkey2", keys, G_N_ELEMENTS (keys));
|
||
g_assert_cmpint (res, ==, 3);
|
||
|
||
res = g_parse_debug_string ("all", keys, G_N_ELEMENTS (keys));
|
||
g_assert_cmpint (res, ==, 7);
|
||
|
||
if (g_test_subprocess ())
|
||
{
|
||
res = g_parse_debug_string ("help", keys, G_N_ELEMENTS (keys));
|
||
g_assert_cmpint (res, ==, 0);
|
||
return;
|
||
}
|
||
g_test_trap_subprocess (NULL, 0, G_TEST_SUBPROCESS_DEFAULT);
|
||
g_test_trap_assert_passed ();
|
||
g_test_trap_assert_stderr ("*Supported debug values: key1 key2 key3 all help*");
|
||
}
|
||
|
||
static void
|
||
test_codeset (void)
|
||
{
|
||
gchar *c;
|
||
const gchar *c2;
|
||
|
||
c = g_get_codeset ();
|
||
g_get_charset (&c2);
|
||
|
||
g_assert_cmpstr (c, ==, c2);
|
||
|
||
g_free (c);
|
||
}
|
||
|
||
static void
|
||
test_codeset2 (void)
|
||
{
|
||
if (g_test_subprocess ())
|
||
{
|
||
const gchar *c;
|
||
g_setenv ("CHARSET", "UTF-8", TRUE);
|
||
g_get_charset (&c);
|
||
g_assert_cmpstr (c, ==, "UTF-8");
|
||
return;
|
||
}
|
||
g_test_trap_subprocess (NULL, 0, G_TEST_SUBPROCESS_DEFAULT);
|
||
g_test_trap_assert_passed ();
|
||
}
|
||
|
||
static void
|
||
test_console_charset (void)
|
||
{
|
||
const gchar *c1;
|
||
const gchar *c2;
|
||
|
||
#ifdef G_OS_WIN32
|
||
/* store current environment and unset $LANG to make sure it does not interfere */
|
||
const unsigned int initial_cp = GetConsoleOutputCP ();
|
||
gchar *initial_lang = g_strdup (g_getenv ("LANG"));
|
||
g_unsetenv ("LANG");
|
||
|
||
/* set console output codepage to something specific (ISO-8859-1 aka CP28591) and query it */
|
||
SetConsoleOutputCP (28591);
|
||
g_get_console_charset (&c1);
|
||
g_assert_cmpstr (c1, ==, "ISO-8859-1");
|
||
|
||
/* set $LANG to something specific (should override the console output codepage) and query it */
|
||
g_setenv ("LANG", "de_DE.ISO-8859-15@euro", TRUE);
|
||
g_get_console_charset (&c2);
|
||
g_assert_cmpstr (c2, ==, "ISO-8859-15");
|
||
|
||
/* reset environment */
|
||
if (initial_cp)
|
||
SetConsoleOutputCP (initial_cp);
|
||
if (initial_lang)
|
||
g_setenv ("LANG", initial_lang, TRUE);
|
||
g_free (initial_lang);
|
||
#else
|
||
g_get_charset (&c1);
|
||
g_get_console_charset (&c2);
|
||
|
||
g_assert_cmpstr (c1, ==, c2);
|
||
#endif
|
||
}
|
||
|
||
extern const gchar *glib_pgettext (const gchar *msgidctxt, gsize msgidoffset);
|
||
|
||
static void
|
||
test_gettext (void)
|
||
{
|
||
const gchar *am0, *am1, *am2, *am3;
|
||
|
||
am0 = glib_pgettext ("GDateTime\004AM", strlen ("GDateTime") + 1);
|
||
am1 = g_dpgettext ("glib20", "GDateTime\004AM", strlen ("GDateTime") + 1);
|
||
am2 = g_dpgettext ("glib20", "GDateTime|AM", 0);
|
||
am3 = g_dpgettext2 ("glib20", "GDateTime", "AM");
|
||
|
||
g_assert_cmpstr (am0, ==, am1);
|
||
g_assert_cmpstr (am1, ==, am2);
|
||
g_assert_cmpstr (am2, ==, am3);
|
||
}
|
||
|
||
static void
|
||
test_username (void)
|
||
{
|
||
const gchar *name;
|
||
|
||
name = g_get_user_name ();
|
||
|
||
g_assert (name != NULL);
|
||
}
|
||
|
||
static void
|
||
test_realname (void)
|
||
{
|
||
const gchar *name;
|
||
|
||
name = g_get_real_name ();
|
||
|
||
g_assert (name != NULL);
|
||
}
|
||
|
||
static void
|
||
test_hostname (void)
|
||
{
|
||
const gchar *name;
|
||
|
||
name = g_get_host_name ();
|
||
|
||
g_assert (name != NULL);
|
||
g_assert_true (g_utf8_validate (name, -1, NULL));
|
||
}
|
||
|
||
#ifdef G_OS_UNIX
|
||
static void
|
||
test_xdg_dirs (void)
|
||
{
|
||
gchar *xdg;
|
||
const gchar *dir;
|
||
const gchar * const *dirs;
|
||
gchar *s;
|
||
|
||
xdg = g_strdup (g_getenv ("XDG_CONFIG_HOME"));
|
||
if (!xdg)
|
||
xdg = g_build_filename (g_get_home_dir (), ".config", NULL);
|
||
|
||
dir = g_get_user_config_dir ();
|
||
|
||
g_assert_cmpstr (dir, ==, xdg);
|
||
g_free (xdg);
|
||
|
||
xdg = g_strdup (g_getenv ("XDG_DATA_HOME"));
|
||
if (!xdg)
|
||
xdg = g_build_filename (g_get_home_dir (), ".local", "share", NULL);
|
||
|
||
dir = g_get_user_data_dir ();
|
||
|
||
g_assert_cmpstr (dir, ==, xdg);
|
||
g_free (xdg);
|
||
|
||
xdg = g_strdup (g_getenv ("XDG_CACHE_HOME"));
|
||
if (!xdg)
|
||
xdg = g_build_filename (g_get_home_dir (), ".cache", NULL);
|
||
|
||
dir = g_get_user_cache_dir ();
|
||
|
||
g_assert_cmpstr (dir, ==, xdg);
|
||
g_free (xdg);
|
||
|
||
xdg = g_strdup (g_getenv ("XDG_STATE_HOME"));
|
||
if (!xdg)
|
||
xdg = g_build_filename (g_get_home_dir (), ".local/state", NULL);
|
||
|
||
dir = g_get_user_state_dir ();
|
||
|
||
g_assert_cmpstr (dir, ==, xdg);
|
||
g_free (xdg);
|
||
|
||
xdg = g_strdup (g_getenv ("XDG_RUNTIME_DIR"));
|
||
if (!xdg)
|
||
xdg = g_strdup (g_get_user_cache_dir ());
|
||
|
||
dir = g_get_user_runtime_dir ();
|
||
|
||
g_assert_cmpstr (dir, ==, xdg);
|
||
g_free (xdg);
|
||
|
||
xdg = (gchar *)g_getenv ("XDG_CONFIG_DIRS");
|
||
if (!xdg)
|
||
xdg = "/etc/xdg";
|
||
|
||
dirs = g_get_system_config_dirs ();
|
||
|
||
s = g_strjoinv (":", (gchar **)dirs);
|
||
|
||
g_assert_cmpstr (s, ==, xdg);
|
||
|
||
g_free (s);
|
||
}
|
||
#endif
|
||
|
||
static void
|
||
test_special_dir (void)
|
||
{
|
||
const gchar *dir, *dir2;
|
||
|
||
dir = g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP);
|
||
g_reload_user_special_dirs_cache ();
|
||
dir2 = g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP);
|
||
|
||
g_assert_cmpstr (dir, ==, dir2);
|
||
}
|
||
|
||
static void
|
||
test_desktop_special_dir (void)
|
||
{
|
||
const gchar *dir, *dir2;
|
||
|
||
dir = g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP);
|
||
g_assert (dir != NULL);
|
||
|
||
g_reload_user_special_dirs_cache ();
|
||
dir2 = g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP);
|
||
g_assert (dir2 != NULL);
|
||
}
|
||
|
||
static void
|
||
test_os_info (void)
|
||
{
|
||
gchar *name;
|
||
gchar *contents = NULL;
|
||
#if defined (G_OS_UNIX) && !(defined (G_OS_WIN32) || defined (__APPLE__))
|
||
struct utsname info;
|
||
#endif
|
||
|
||
/* Whether this is implemented or not, it must not crash */
|
||
name = g_get_os_info (G_OS_INFO_KEY_NAME);
|
||
g_test_message ("%s: %s",
|
||
G_OS_INFO_KEY_NAME,
|
||
name == NULL ? "(null)" : name);
|
||
|
||
#if defined (G_OS_WIN32) || defined (__APPLE__)
|
||
/* These OSs have a special case so NAME should always succeed */
|
||
g_assert_nonnull (name);
|
||
#elif defined (G_OS_UNIX)
|
||
if (g_file_get_contents ("/etc/os-release", &contents, NULL, NULL) ||
|
||
g_file_get_contents ("/usr/lib/os-release", &contents, NULL, NULL) ||
|
||
uname (&info) == 0)
|
||
g_assert_nonnull (name);
|
||
else
|
||
g_test_skip ("os-release(5) API not implemented on this platform");
|
||
#else
|
||
g_test_skip ("g_get_os_info() not supported on this platform");
|
||
#endif
|
||
|
||
g_free (name);
|
||
g_free (contents);
|
||
}
|
||
|
||
static void
|
||
source_test (gpointer data)
|
||
{
|
||
g_assert_not_reached ();
|
||
}
|
||
|
||
static void
|
||
test_clear_source (void)
|
||
{
|
||
guint id;
|
||
|
||
id = g_idle_add_once (source_test, NULL);
|
||
g_assert_cmpuint (id, >, 0);
|
||
|
||
g_clear_handle_id (&id, g_source_remove);
|
||
g_assert_cmpuint (id, ==, 0);
|
||
|
||
id = g_timeout_add_once (100, source_test, NULL);
|
||
g_assert_cmpuint (id, >, 0);
|
||
|
||
g_clear_handle_id (&id, g_source_remove);
|
||
g_assert_cmpuint (id, ==, 0);
|
||
}
|
||
|
||
static void
|
||
test_clear_pointer (void)
|
||
{
|
||
gpointer a;
|
||
|
||
a = g_malloc (5);
|
||
g_clear_pointer (&a, g_free);
|
||
g_assert (a == NULL);
|
||
|
||
a = g_malloc (5);
|
||
(g_clear_pointer) (&a, g_free);
|
||
g_assert (a == NULL);
|
||
}
|
||
|
||
/* Test that g_clear_pointer() works with a GDestroyNotify which contains a cast.
|
||
* See https://gitlab.gnome.org/GNOME/glib/issues/1425 */
|
||
static void
|
||
test_clear_pointer_cast (void)
|
||
{
|
||
GHashTable *hash_table = NULL;
|
||
|
||
hash_table = g_hash_table_new (g_str_hash, g_str_equal);
|
||
|
||
g_assert_nonnull (hash_table);
|
||
|
||
g_clear_pointer (&hash_table, (void (*) (GHashTable *)) g_hash_table_destroy);
|
||
|
||
g_assert_null (hash_table);
|
||
}
|
||
|
||
/* Test that the macro version of g_clear_pointer() only evaluates its argument
|
||
* once, just like the function version would. */
|
||
static void
|
||
test_clear_pointer_side_effects (void)
|
||
{
|
||
gchar **my_string_array, **i;
|
||
|
||
my_string_array = g_new0 (gchar*, 3);
|
||
my_string_array[0] = g_strdup ("hello");
|
||
my_string_array[1] = g_strdup ("there");
|
||
my_string_array[2] = NULL;
|
||
|
||
i = my_string_array;
|
||
|
||
g_clear_pointer (i++, g_free);
|
||
|
||
g_assert_true (i == &my_string_array[1]);
|
||
g_assert_null (my_string_array[0]);
|
||
g_assert_nonnull (my_string_array[1]);
|
||
g_assert_null (my_string_array[2]);
|
||
|
||
g_free (my_string_array[1]);
|
||
g_free (my_string_array[2]);
|
||
g_free (my_string_array);
|
||
}
|
||
|
||
static int obj_count;
|
||
|
||
static void
|
||
get_obj (gpointer *obj_out)
|
||
{
|
||
gpointer obj = g_malloc (5);
|
||
obj_count++;
|
||
|
||
if (obj_out)
|
||
*obj_out = g_steal_pointer (&obj);
|
||
|
||
if (obj)
|
||
{
|
||
g_free (obj);
|
||
obj_count--;
|
||
}
|
||
}
|
||
|
||
static void
|
||
test_take_pointer (void)
|
||
{
|
||
gpointer a;
|
||
gpointer b;
|
||
|
||
get_obj (NULL);
|
||
|
||
get_obj (&a);
|
||
g_assert (a);
|
||
|
||
/* ensure that it works to skip the macro */
|
||
b = (g_steal_pointer) (&a);
|
||
g_assert (!a);
|
||
obj_count--;
|
||
g_free (b);
|
||
|
||
g_assert (!obj_count);
|
||
}
|
||
|
||
static void
|
||
test_misc_mem (void)
|
||
{
|
||
gpointer a;
|
||
|
||
a = g_try_malloc (0);
|
||
g_assert (a == NULL);
|
||
|
||
a = g_try_malloc0 (0);
|
||
g_assert (a == NULL);
|
||
|
||
a = g_malloc (16);
|
||
a = g_try_realloc (a, 20);
|
||
a = g_try_realloc (a, 0);
|
||
|
||
g_assert (a == NULL);
|
||
}
|
||
|
||
static void
|
||
aligned_alloc_nz (void)
|
||
{
|
||
gpointer a;
|
||
|
||
/* Test an alignment that’s zero */
|
||
a = g_aligned_alloc (16, sizeof(char), 0);
|
||
g_aligned_free (a);
|
||
exit (0);
|
||
}
|
||
|
||
static void
|
||
aligned_alloc_npot (void)
|
||
{
|
||
gpointer a;
|
||
|
||
/* Test an alignment that’s not a power of two */
|
||
a = g_aligned_alloc (16, sizeof(char), 15);
|
||
g_aligned_free (a);
|
||
exit (0);
|
||
}
|
||
|
||
static void
|
||
aligned_alloc_nmov (void)
|
||
{
|
||
gpointer a;
|
||
|
||
/* Test an alignment that’s not a multiple of sizeof(void*) */
|
||
a = g_aligned_alloc (16, sizeof(char), sizeof(void *) / 2);
|
||
g_aligned_free (a);
|
||
exit (0);
|
||
}
|
||
|
||
static void
|
||
test_aligned_mem (void)
|
||
{
|
||
gpointer a;
|
||
|
||
g_test_summary ("Aligned memory allocator");
|
||
|
||
a = g_aligned_alloc (0, sizeof(int), 8);
|
||
g_assert_null (a);
|
||
|
||
a = g_aligned_alloc0 (0, sizeof(int), 8);
|
||
g_assert_null (a);
|
||
|
||
a = g_aligned_alloc (16, 0, 8);
|
||
g_assert_null (a);
|
||
|
||
#define CHECK_SUBPROCESS_FAIL(name,msg) do { \
|
||
if (g_test_undefined ()) \
|
||
{ \
|
||
g_test_message (msg); \
|
||
g_test_trap_subprocess ("/utils/aligned-mem/subprocess/" #name, 0, \
|
||
G_TEST_SUBPROCESS_DEFAULT); \
|
||
g_test_trap_assert_failed (); \
|
||
} \
|
||
} while (0)
|
||
|
||
CHECK_SUBPROCESS_FAIL (aligned_alloc_nz, "Alignment must not be zero");
|
||
CHECK_SUBPROCESS_FAIL (aligned_alloc_npot, "Alignment must be a power of two");
|
||
CHECK_SUBPROCESS_FAIL (aligned_alloc_nmov, "Alignment must be a multiple of sizeof(void*)");
|
||
}
|
||
|
||
static void
|
||
test_aligned_mem_alignment (void)
|
||
{
|
||
gchar *p;
|
||
|
||
g_test_summary ("Check that g_aligned_alloc() returns a correctly aligned pointer");
|
||
|
||
p = g_aligned_alloc (5, sizeof (*p), 256);
|
||
g_assert_nonnull (p);
|
||
g_assert_cmpuint (((guintptr) p) % 256, ==, 0);
|
||
|
||
g_aligned_free (p);
|
||
}
|
||
|
||
static void
|
||
test_aligned_mem_zeroed (void)
|
||
{
|
||
gsize n_blocks = 10;
|
||
guint *p;
|
||
gsize i;
|
||
|
||
g_test_summary ("Check that g_aligned_alloc0() zeroes out its allocation");
|
||
|
||
p = g_aligned_alloc0 (n_blocks, sizeof (*p), 16);
|
||
g_assert_nonnull (p);
|
||
|
||
for (i = 0; i < n_blocks; i++)
|
||
g_assert_cmpuint (p[i], ==, 0);
|
||
|
||
g_aligned_free (p);
|
||
}
|
||
|
||
static void
|
||
test_nullify (void)
|
||
{
|
||
gpointer p = &test_nullify;
|
||
|
||
g_assert (p != NULL);
|
||
|
||
g_nullify_pointer (&p);
|
||
|
||
g_assert (p == NULL);
|
||
}
|
||
|
||
static void
|
||
atexit_func (void)
|
||
{
|
||
g_print ("atexit called");
|
||
}
|
||
|
||
static void
|
||
test_atexit (void)
|
||
{
|
||
if (g_test_subprocess ())
|
||
{
|
||
g_atexit (atexit_func);
|
||
return;
|
||
}
|
||
g_test_trap_subprocess (NULL, 0, G_TEST_SUBPROCESS_DEFAULT);
|
||
g_test_trap_assert_passed ();
|
||
g_test_trap_assert_stdout ("*atexit called*");
|
||
}
|
||
|
||
static void
|
||
test_check_setuid (void)
|
||
{
|
||
gboolean res;
|
||
|
||
res = GLIB_PRIVATE_CALL(g_check_setuid) ();
|
||
g_assert (!res);
|
||
}
|
||
|
||
/* Test the defined integer limits are correct, as some compilers have had
|
||
* problems with signed/unsigned conversion in the past. These limits should not
|
||
* vary between platforms, compilers or architectures.
|
||
*
|
||
* Use string comparisons to avoid the same systematic problems with unary minus
|
||
* application in C++. See https://gitlab.gnome.org/GNOME/glib/issues/1663. */
|
||
static void
|
||
test_int_limits (void)
|
||
{
|
||
gchar *str = NULL;
|
||
|
||
g_test_bug ("https://gitlab.gnome.org/GNOME/glib/issues/1663");
|
||
|
||
str = g_strdup_printf ("%d %d %u\n"
|
||
"%" G_GINT16_FORMAT " %" G_GINT16_FORMAT " %" G_GUINT16_FORMAT "\n"
|
||
"%" G_GINT32_FORMAT " %" G_GINT32_FORMAT " %" G_GUINT32_FORMAT "\n"
|
||
"%" G_GINT64_FORMAT " %" G_GINT64_FORMAT " %" G_GUINT64_FORMAT "\n",
|
||
G_MININT8, G_MAXINT8, G_MAXUINT8,
|
||
G_MININT16, G_MAXINT16, G_MAXUINT16,
|
||
G_MININT32, G_MAXINT32, G_MAXUINT32,
|
||
G_MININT64, G_MAXINT64, G_MAXUINT64);
|
||
|
||
g_assert_cmpstr (str, ==,
|
||
"-128 127 255\n"
|
||
"-32768 32767 65535\n"
|
||
"-2147483648 2147483647 4294967295\n"
|
||
"-9223372036854775808 9223372036854775807 18446744073709551615\n");
|
||
g_free (str);
|
||
}
|
||
|
||
static void
|
||
test_clear_list (void)
|
||
{
|
||
GList *list = NULL;
|
||
|
||
g_clear_list (&list, NULL);
|
||
g_assert_null (list);
|
||
|
||
list = g_list_prepend (list, "test");
|
||
g_assert_nonnull (list);
|
||
|
||
g_clear_list (&list, NULL);
|
||
g_assert_null (list);
|
||
|
||
g_clear_list (&list, g_free);
|
||
g_assert_null (list);
|
||
|
||
list = g_list_prepend (list, g_malloc (16));
|
||
g_assert_nonnull (list);
|
||
|
||
g_clear_list (&list, g_free);
|
||
g_assert_null (list);
|
||
}
|
||
|
||
static void
|
||
test_clear_slist (void)
|
||
{
|
||
GSList *slist = NULL;
|
||
|
||
g_clear_slist (&slist, NULL);
|
||
g_assert_null (slist);
|
||
|
||
slist = g_slist_prepend (slist, "test");
|
||
g_assert_nonnull (slist);
|
||
|
||
g_clear_slist (&slist, NULL);
|
||
g_assert_null (slist);
|
||
|
||
g_clear_slist (&slist, g_free);
|
||
g_assert_null (slist);
|
||
|
||
slist = g_slist_prepend (slist, g_malloc (16));
|
||
g_assert_nonnull (slist);
|
||
|
||
g_clear_slist (&slist, g_free);
|
||
g_assert_null (slist);
|
||
}
|
||
|
||
int
|
||
main (int argc,
|
||
char *argv[])
|
||
{
|
||
argv0 = argv[0];
|
||
|
||
/* for tmpdir test, need to do this early before g_get_any_init */
|
||
g_setenv ("TMPDIR", "", TRUE);
|
||
g_unsetenv ("TMP");
|
||
g_unsetenv ("TEMP");
|
||
|
||
/* g_test_init() only calls g_set_prgname() if g_get_prgname()
|
||
* returns %NULL, but g_get_prgname() on Windows never returns NULL.
|
||
* So we need to do this by hand to make test_appname() work on
|
||
* Windows.
|
||
*/
|
||
g_set_prgname (argv[0]);
|
||
|
||
g_test_init (&argc, &argv, NULL);
|
||
|
||
g_test_add_func ("/utils/language-names", test_language_names);
|
||
g_test_add_func ("/utils/locale-variants", test_locale_variants);
|
||
g_test_add_func ("/utils/version", test_version);
|
||
g_test_add_func ("/utils/appname", test_appname);
|
||
g_test_add_func ("/utils/prgname-thread-safety", test_prgname_thread_safety);
|
||
g_test_add_func ("/utils/tmpdir", test_tmpdir);
|
||
g_test_add_func ("/utils/basic_bits", test_basic_bits);
|
||
g_test_add_func ("/utils/bits", test_bits);
|
||
g_test_add_func ("/utils/swap", test_swap);
|
||
g_test_add_func ("/utils/find-program", test_find_program);
|
||
g_test_add_func ("/utils/debug", test_debug);
|
||
g_test_add_func ("/utils/codeset", test_codeset);
|
||
g_test_add_func ("/utils/codeset2", test_codeset2);
|
||
g_test_add_func ("/utils/console-charset", test_console_charset);
|
||
g_test_add_func ("/utils/gettext", test_gettext);
|
||
g_test_add_func ("/utils/username", test_username);
|
||
g_test_add_func ("/utils/realname", test_realname);
|
||
g_test_add_func ("/utils/hostname", test_hostname);
|
||
#ifdef G_OS_UNIX
|
||
g_test_add_func ("/utils/xdgdirs", test_xdg_dirs);
|
||
#endif
|
||
g_test_add_func ("/utils/specialdir", test_special_dir);
|
||
g_test_add_func ("/utils/specialdir/desktop", test_desktop_special_dir);
|
||
g_test_add_func ("/utils/os-info", test_os_info);
|
||
g_test_add_func ("/utils/clear-pointer", test_clear_pointer);
|
||
g_test_add_func ("/utils/clear-pointer-cast", test_clear_pointer_cast);
|
||
g_test_add_func ("/utils/clear-pointer/side-effects", test_clear_pointer_side_effects);
|
||
g_test_add_func ("/utils/take-pointer", test_take_pointer);
|
||
g_test_add_func ("/utils/clear-source", test_clear_source);
|
||
g_test_add_func ("/utils/misc-mem", test_misc_mem);
|
||
g_test_add_func ("/utils/aligned-mem", test_aligned_mem);
|
||
g_test_add_func ("/utils/aligned-mem/subprocess/aligned_alloc_nz", aligned_alloc_nz);
|
||
g_test_add_func ("/utils/aligned-mem/subprocess/aligned_alloc_npot", aligned_alloc_npot);
|
||
g_test_add_func ("/utils/aligned-mem/subprocess/aligned_alloc_nmov", aligned_alloc_nmov);
|
||
g_test_add_func ("/utils/aligned-mem/alignment", test_aligned_mem_alignment);
|
||
g_test_add_func ("/utils/aligned-mem/zeroed", test_aligned_mem_zeroed);
|
||
g_test_add_func ("/utils/nullify", test_nullify);
|
||
g_test_add_func ("/utils/atexit", test_atexit);
|
||
g_test_add_func ("/utils/check-setuid", test_check_setuid);
|
||
g_test_add_func ("/utils/int-limits", test_int_limits);
|
||
g_test_add_func ("/utils/clear-list", test_clear_list);
|
||
g_test_add_func ("/utils/clear-slist", test_clear_slist);
|
||
|
||
return g_test_run ();
|
||
}
|