glib/glib/tests/strfuncs.c
Philip Withnall feff097f27 gstrfuncs: Deprecate g_memdup() in favour of g_memdup2()
Unfortunately, `g_memdup()` accepts its size argument as a `guint`,
unlike most other functions which deal with memory sizes — they all use
`gsize`. `gsize` is 64 bits on 64-bit machines, while `guint` is only 32
bits. This can lead to a silent (with default compiler warnings)
truncation of the value provided by the caller. For large values, this
will result in the returned heap allocation being significantly smaller
than the caller expects, which will then lead to buffer overflow
reads/writes.

Any code using `g_memdup()` should immediately port to `g_memdup2()` and
check the pointer arithmetic around their call site to ensure there
aren’t other overflows.

Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Fixes: #2319
2021-02-04 17:34:03 +00:00

2604 lines
84 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* Unit tests for gstrfuncs
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* 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.
*/
#ifndef GLIB_DISABLE_DEPRECATION_WARNINGS
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#endif
#define _XOPEN_SOURCE 600
#include <ctype.h>
#include <errno.h>
#include <locale.h>
#include <math.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "glib.h"
#if defined (_MSC_VER) && (_MSC_VER <= 1800)
#define isnan(x) _isnan(x)
#ifndef NAN
static const unsigned long __nan[2] = {0xffffffff, 0x7fffffff};
#define NAN (*(const float *) __nan)
#endif
#ifndef INFINITY
#define INFINITY HUGE_VAL
#endif
#endif
#define GLIB_TEST_STRING "el dorado "
#define FOR_ALL_CTYPE(macro) \
macro(isalnum) \
macro(isalpha) \
macro(iscntrl) \
macro(isdigit) \
macro(isgraph) \
macro(islower) \
macro(isprint) \
macro(ispunct) \
macro(isspace) \
macro(isupper) \
macro(isxdigit)
#define DEFINE_CALL_CTYPE(function) \
static int \
call_##function (int c) \
{ \
return function (c); \
}
#define DEFINE_CALL_G_ASCII_CTYPE(function) \
static gboolean \
call_g_ascii_##function (gchar c) \
{ \
return g_ascii_##function (c); \
}
FOR_ALL_CTYPE (DEFINE_CALL_CTYPE)
FOR_ALL_CTYPE (DEFINE_CALL_G_ASCII_CTYPE)
static void
test_is_function (const char *name,
gboolean (* ascii_function) (gchar),
int (* c_library_function) (int),
gboolean (* unicode_function) (gunichar))
{
int c;
for (c = 0; c <= 0x7F; c++)
{
gboolean ascii_result = ascii_function ((gchar)c);
gboolean c_library_result = c_library_function (c) != 0;
gboolean unicode_result = unicode_function ((gunichar) c);
if (ascii_result != c_library_result && c != '\v')
{
g_error ("g_ascii_%s returned %d and %s returned %d for 0x%X",
name, ascii_result, name, c_library_result, c);
}
if (ascii_result != unicode_result)
{
g_error ("g_ascii_%s returned %d and g_unichar_%s returned %d for 0x%X",
name, ascii_result, name, unicode_result, c);
}
}
for (c = 0x80; c <= 0xFF; c++)
{
gboolean ascii_result = ascii_function ((gchar)c);
if (ascii_result)
{
g_error ("g_ascii_%s returned TRUE for 0x%X", name, c);
}
}
}
static void
test_to_function (const char *name,
gchar (* ascii_function) (gchar),
int (* c_library_function) (int),
gunichar (* unicode_function) (gunichar))
{
int c;
for (c = 0; c <= 0x7F; c++)
{
int ascii_result = (guchar) ascii_function ((gchar) c);
int c_library_result = c_library_function (c);
int unicode_result = unicode_function ((gunichar) c);
if (ascii_result != c_library_result)
{
g_error ("g_ascii_%s returned 0x%X and %s returned 0x%X for 0x%X",
name, ascii_result, name, c_library_result, c);
}
if (ascii_result != unicode_result)
{
g_error ("g_ascii_%s returned 0x%X and g_unichar_%s returned 0x%X for 0x%X",
name, ascii_result, name, unicode_result, c);
}
}
for (c = 0x80; c <= 0xFF; c++)
{
int ascii_result = (guchar) ascii_function ((gchar) c);
if (ascii_result != c)
{
g_error ("g_ascii_%s returned 0x%X for 0x%X",
name, ascii_result, c);
}
}
}
static void
test_digit_function (const char *name,
int (* ascii_function) (gchar),
int (* unicode_function) (gunichar))
{
int c;
for (c = 0; c <= 0x7F; c++)
{
int ascii_result = ascii_function ((gchar) c);
int unicode_result = unicode_function ((gunichar) c);
if (ascii_result != unicode_result)
{
g_error ("g_ascii_%s_value returned %d and g_unichar_%s_value returned %d for 0x%X",
name, ascii_result, name, unicode_result, c);
}
}
for (c = 0x80; c <= 0xFF; c++)
{
int ascii_result = ascii_function ((gchar) c);
if (ascii_result != -1)
{
g_error ("g_ascii_%s_value returned %d for 0x%X",
name, ascii_result, c);
}
}
}
static void
test_is_to_digit (void)
{
#define TEST_IS(name) test_is_function (#name, call_g_ascii_##name, call_##name, g_unichar_##name);
FOR_ALL_CTYPE(TEST_IS)
#undef TEST_IS
#define TEST_TO(name) test_to_function (#name, g_ascii_##name, name, g_unichar_##name)
TEST_TO (tolower);
TEST_TO (toupper);
#undef TEST_TO
#define TEST_DIGIT(name) test_digit_function (#name, g_ascii_##name##_value, g_unichar_##name##_value)
TEST_DIGIT (digit);
TEST_DIGIT (xdigit);
#undef TEST_DIGIT
}
/* Testing g_memdup() function with various positive and negative cases */
static void
test_memdup (void)
{
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
gchar *str_dup = NULL;
const gchar *str = "The quick brown fox jumps over the lazy dog";
/* Testing negative cases */
g_assert_null (g_memdup (NULL, 1024));
g_assert_null (g_memdup (str, 0));
g_assert_null (g_memdup (NULL, 0));
/* Testing normal usage cases */
str_dup = g_memdup (str, strlen (str) + 1);
g_assert_nonnull (str_dup);
g_assert_cmpstr (str, ==, str_dup);
g_free (str_dup);
G_GNUC_END_IGNORE_DEPRECATIONS
}
/* Testing g_memdup2() function with various positive and negative cases */
static void
test_memdup2 (void)
{
gchar *str_dup = NULL;
const gchar *str = "The quick brown fox jumps over the lazy dog";
/* Testing negative cases */
g_assert_null (g_memdup2 (NULL, 1024));
g_assert_null (g_memdup2 (str, 0));
g_assert_null (g_memdup2 (NULL, 0));
/* Testing normal usage cases */
str_dup = g_memdup2 (str, strlen (str) + 1);
g_assert_nonnull (str_dup);
g_assert_cmpstr (str, ==, str_dup);
g_free (str_dup);
}
/* Testing g_strpcpy() function with various positive and negative cases */
static void
test_stpcpy (void)
{
gchar *str = "The quick brown fox jumps over the lazy dog";
gchar str_cpy[45], *str_cpy_end = NULL;
if (g_test_undefined ())
{
/* Testing degenerated cases */
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
str_cpy_end = g_stpcpy (str_cpy, NULL);
g_test_assert_expected_messages ();
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
str_cpy_end = g_stpcpy (NULL, str);
g_test_assert_expected_messages ();
}
/* Testing normal usage cases */
str_cpy_end = g_stpcpy (str_cpy, str);
g_assert_nonnull (str_cpy);
g_assert_true (str_cpy + strlen (str) == str_cpy_end);
g_assert_cmpstr (str, ==, str_cpy);
g_assert_cmpstr (str, ==, str_cpy_end - strlen (str));
}
/* Testing g_strlcpy() function with various positive and negative cases */
static void
test_strlcpy (void)
{
gchar *str = "The quick brown fox jumps over the lazy dog";
gchar str_cpy[45];
gsize str_cpy_size = 0;
if (g_test_undefined ())
{
/* Testing degenerated cases */
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
str_cpy_size = g_strlcpy (str_cpy, NULL, 0);
g_test_assert_expected_messages ();
/* Returned 0 because g_strlcpy() failed */
g_assert_cmpint (str_cpy_size, ==, 0);
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
str_cpy_size = g_strlcpy (NULL, str, 0);
g_test_assert_expected_messages ();
/* Returned 0 because g_strlcpy() failed */
g_assert_cmpint (str_cpy_size, ==, 0);
}
str_cpy_size = g_strlcpy (str_cpy, "", 0);
g_assert_cmpint (str_cpy_size, ==, strlen (""));
/* Testing normal usage cases.
* Note that the @dest_size argument to g_strlcpy() is normally meant to be
* set to `sizeof (dest)`. We set it to various values `≤ sizeof (str_cpy)`
* for testing purposes. */
str_cpy_size = g_strlcpy (str_cpy, str, strlen (str) + 1);
g_assert_nonnull (str_cpy);
g_assert_cmpstr (str, ==, str_cpy);
g_assert_cmpint (str_cpy_size, ==, strlen (str));
str_cpy_size = g_strlcpy (str_cpy, str, strlen (str));
g_assert_nonnull (str_cpy);
g_assert_cmpstr ("The quick brown fox jumps over the lazy do", ==, str_cpy);
g_assert_cmpint (str_cpy_size, ==, strlen (str));
str_cpy_size = g_strlcpy (str_cpy, str, strlen (str) - 15);
g_assert_nonnull (str_cpy);
g_assert_cmpstr ("The quick brown fox jumps o", ==, str_cpy);
g_assert_cmpint (str_cpy_size, ==, strlen (str));
str_cpy_size = g_strlcpy (str_cpy, str, 0);
g_assert_nonnull (str_cpy);
g_assert_cmpstr ("The quick brown fox jumps o", ==, str_cpy);
g_assert_cmpint (str_cpy_size, ==, strlen (str));
str_cpy_size = g_strlcpy (str_cpy, str, strlen (str) + 15);
g_assert_nonnull (str_cpy);
g_assert_cmpstr (str, ==, str_cpy);
g_assert_cmpint (str_cpy_size, ==, strlen (str));
}
/* Testing g_strlcat() function with various positive and negative cases */
static void
test_strlcat (void)
{
gchar *str = "The quick brown fox jumps over the lazy dog";
gchar str_cpy[60] = { 0 };
gsize str_cpy_size = 0;
if (g_test_undefined ())
{
/* Testing degenerated cases */
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
str_cpy_size = g_strlcat (str_cpy, NULL, 0);
g_test_assert_expected_messages ();
/* Returned 0 because g_strlcpy() failed */
g_assert_cmpint (str_cpy_size, ==, 0);
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
str_cpy_size = g_strlcat (NULL, str, 0);
g_test_assert_expected_messages ();
/* Returned 0 because g_strlcpy() failed */
g_assert_cmpint (str_cpy_size, ==, 0);
}
str_cpy_size = g_strlcat (str_cpy, "", 0);
g_assert_cmpint (str_cpy_size, ==, strlen (""));
/* Testing normal usage cases.
* Note that the @dest_size argument to g_strlcat() is normally meant to be
* set to `sizeof (dest)`. We set it to various values `≤ sizeof (str_cpy)`
* for testing purposes. */
g_assert_cmpuint (strlen (str) + 1, <=, sizeof (str_cpy));
str_cpy_size = g_strlcat (str_cpy, str, strlen (str) + 1);
g_assert_cmpstr (str, ==, str_cpy);
g_assert_cmpint (str_cpy_size, ==, strlen (str));
g_assert_cmpuint (strlen (str), <=, sizeof (str_cpy));
str_cpy_size = g_strlcat (str_cpy, str, strlen (str));
g_assert_cmpstr (str, ==, str_cpy);
g_assert_cmpint (str_cpy_size, ==, 2 * strlen (str));
g_assert_cmpuint (strlen (str) - 15, <=, sizeof (str_cpy));
str_cpy_size = g_strlcat (str_cpy, str, strlen (str) - 15);
g_assert_cmpstr (str, ==, str_cpy);
g_assert_cmpint (str_cpy_size, ==, 2 * strlen (str) - 15);
g_assert_cmpuint (0, <=, sizeof (str_cpy));
str_cpy_size = g_strlcat (str_cpy, str, 0);
g_assert_cmpstr (str, ==, str_cpy);
g_assert_cmpint (str_cpy_size, ==, strlen (str));
g_assert_cmpuint (strlen (str) + 15, <=, sizeof (str_cpy));
str_cpy_size = g_strlcat (str_cpy, str, strlen (str) + 15);
g_assert_cmpstr ("The quick brown fox jumps over the lazy dogThe quick brow",
==, str_cpy);
g_assert_cmpint (str_cpy_size, ==, 2 * strlen (str));
}
/* Testing g_ascii_strdown() function with various positive and negative cases */
static void
test_ascii_strdown (void)
{
const gchar *str_down = "the quick brown fox jumps over the lazy dog.";
const gchar *str_up = "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG.";
gchar* str;
if (g_test_undefined ())
{
/* Testing degenerated cases */
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
str = g_ascii_strdown (NULL, 0);
g_test_assert_expected_messages ();
}
str = g_ascii_strdown ("", 0);
g_assert_nonnull (str);
g_assert_cmpstr (str, ==, "");
g_free (str);
str = g_ascii_strdown ("", -1);
g_assert_nonnull (str);
g_assert_cmpstr (str, ==, "");
g_free (str);
/* Testing normal usage cases */
str = g_ascii_strdown (str_down, strlen (str_down));
g_assert_nonnull (str);
g_assert_cmpstr (str, ==, str_down);
g_free (str);
str = g_ascii_strdown (str_up, strlen (str_up));
g_assert_nonnull (str);
g_assert_cmpstr (str, ==, str_down);
g_free (str);
str = g_ascii_strdown (str_up, -1);
g_assert_nonnull (str);
g_assert_cmpstr (str, ==, str_down);
g_free (str);
str = g_ascii_strdown (str_up, 0);
g_assert_nonnull (str);
g_assert_cmpstr (str, ==, "");
g_free (str);
}
/* Testing g_ascii_strup() function with various positive and negative cases */
static void
test_ascii_strup (void)
{
const gchar *str_down = "the quick brown fox jumps over the lazy dog.";
const gchar *str_up = "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG.";
gchar* str;
if (g_test_undefined ())
{
/* Testing degenerated cases */
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
str = g_ascii_strup (NULL, 0);
g_test_assert_expected_messages ();
}
str = g_ascii_strup ("", 0);
g_assert_nonnull (str);
g_assert_cmpstr (str, ==, "");
g_free (str);
str = g_ascii_strup ("", -1);
g_assert_nonnull (str);
g_assert_cmpstr (str, ==, "");
g_free (str);
/* Testing normal usage cases */
str = g_ascii_strup (str_up, strlen (str_up));
g_assert_nonnull (str);
g_assert_cmpstr (str, ==, str_up);
g_free (str);
str = g_ascii_strup (str_down, strlen (str_down));
g_assert_nonnull (str);
g_assert_cmpstr (str, ==, str_up);
g_free (str);
str = g_ascii_strup (str_down, -1);
g_assert_nonnull (str);
g_assert_cmpstr (str, ==, str_up);
g_free (str);
str = g_ascii_strup (str_down, 0);
g_assert_nonnull (str);
g_assert_cmpstr (str, ==, "");
g_free (str);
}
/* Testing g_strdup() function with various positive and negative cases */
static void
test_strdup (void)
{
gchar *str;
g_assert_null (g_strdup (NULL));
str = g_strdup (GLIB_TEST_STRING);
g_assert_nonnull (str);
g_assert_cmpstr (str, ==, GLIB_TEST_STRING);
g_free (str);
}
/* Testing g_strndup() function with various positive and negative cases */
static void
test_strndup (void)
{
gchar *str;
str = g_strndup (NULL, 3);
g_assert_null (str);
str = g_strndup ("aaaa", 5);
g_assert_nonnull (str);
g_assert_cmpstr (str, ==, "aaaa");
g_free (str);
str = g_strndup ("aaaa", 2);
g_assert_nonnull (str);
g_assert_cmpstr (str, ==, "aa");
g_free (str);
}
/* Testing g_strdup_printf() function with various positive and negative cases */
static void
test_strdup_printf (void)
{
gchar *str;
str = g_strdup_printf ("%05d %-5s", 21, "test");
g_assert_nonnull (str);
g_assert_cmpstr (str, ==, "00021 test ");
g_free (str);
}
/* Testing g_strdupv() function with various positive and negative cases */
static void
test_strdupv (void)
{
gchar *vec[] = { "Foo", "Bar", NULL };
gchar **copy;
copy = g_strdupv (NULL);
g_assert_null (copy);
copy = g_strdupv (vec);
g_assert_nonnull (copy);
g_assert_cmpstrv (copy, vec);
g_strfreev (copy);
}
/* Testing g_strfill() function with various positive and negative cases */
static void
test_strnfill (void)
{
gchar *str;
str = g_strnfill (0, 'a');
g_assert_nonnull (str);
g_assert_true (*str == '\0');
g_free (str);
str = g_strnfill (5, 'a');
g_assert_nonnull (str);
g_assert_cmpstr (str, ==, "aaaaa");
g_free (str);
}
/* Testing g_strconcat() function with various positive and negative cases */
static void
test_strconcat (void)
{
gchar *str;
str = g_strconcat (GLIB_TEST_STRING, NULL);
g_assert_nonnull (str);
g_assert_cmpstr (str, ==, GLIB_TEST_STRING);
g_free (str);
str = g_strconcat (GLIB_TEST_STRING,
GLIB_TEST_STRING,
GLIB_TEST_STRING,
NULL);
g_assert_nonnull (str);
g_assert_cmpstr (str, ==, GLIB_TEST_STRING GLIB_TEST_STRING GLIB_TEST_STRING);
g_free (str);
g_assert_null (g_strconcat (NULL, "bla", NULL));
}
/* Testing g_strjoinv() function with various positive and negative cases */
static void
test_strjoinv (void)
{
gchar *strings[] = { "string1", "string2", NULL };
gchar *empty_strings[] = { NULL };
gchar *str;
if (g_test_undefined ())
{
/* Testing degenerated cases */
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
str = g_strjoinv (NULL, NULL);
g_test_assert_expected_messages ();
}
str = g_strjoinv (":", strings);
g_assert_nonnull (str);
g_assert_cmpstr (str, ==, "string1:string2");
g_free (str);
str = g_strjoinv (NULL, strings);
g_assert_nonnull (str);
g_assert_cmpstr (str, ==, "string1string2");
g_free (str);
str = g_strjoinv (NULL, empty_strings);
g_assert_nonnull (str);
g_assert_cmpstr (str, ==, "");
g_free (str);
}
/* Testing g_strjoin() function with various positive and negative cases */
static void
test_strjoin (void)
{
gchar *str;
str = g_strjoin (NULL, NULL);
g_assert_nonnull (str);
g_assert_true (*str == '\0');
g_free (str);
str = g_strjoin (":", NULL);
g_assert_nonnull (str);
g_assert_true (*str == '\0');
g_free (str);
str = g_strjoin (NULL, GLIB_TEST_STRING, NULL);
g_assert_nonnull (str);
g_assert_cmpstr (str, ==, GLIB_TEST_STRING);
g_free (str);
str = g_strjoin (NULL,
GLIB_TEST_STRING,
GLIB_TEST_STRING,
GLIB_TEST_STRING,
NULL);
g_assert_nonnull (str);
g_assert_cmpstr (str, ==, GLIB_TEST_STRING GLIB_TEST_STRING GLIB_TEST_STRING);
g_free (str);
str = g_strjoin (":",
GLIB_TEST_STRING,
GLIB_TEST_STRING,
GLIB_TEST_STRING,
NULL);
g_assert_nonnull (str);
g_assert_cmpstr (str, ==, GLIB_TEST_STRING ":" GLIB_TEST_STRING ":" GLIB_TEST_STRING);
g_free (str);
}
/* Testing g_strcanon() function with various positive and negative cases */
static void
test_strcanon (void)
{
gchar *str;
if (g_test_undefined ())
{
gchar *ret;
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
str = g_strcanon (NULL, "ab", 'y');
g_test_assert_expected_messages ();
g_assert_null (str);
str = g_strdup ("abxabxab");
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
ret = g_strcanon (str, NULL, 'y');
g_test_assert_expected_messages ();
g_assert_null (ret);
g_free (str);
}
str = g_strdup ("abxabxab");
str = g_strcanon (str, "ab", 'y');
g_assert_nonnull (str);
g_assert_cmpstr (str, ==, "abyabyab");
g_free (str);
}
/* Testing g_strcompress() and g_strescape() functions with various cases */
static void
test_strcompress_strescape (void)
{
gchar *str;
gchar *tmp;
/* test compress */
if (g_test_undefined ())
{
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
str = g_strcompress (NULL);
g_test_assert_expected_messages ();
g_assert_null (str);
/* trailing slashes are not allowed */
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
"*trailing \\*");
str = g_strcompress ("abc\\");
g_test_assert_expected_messages ();
g_assert_cmpstr (str, ==, "abc");
g_free (str);
}
str = g_strcompress ("abc\\\\\\\"\\b\\f\\n\\r\\t\\v\\003\\177\\234\\313\\12345z");
g_assert_nonnull (str);
g_assert_cmpstr (str, ==, "abc\\\"\b\f\n\r\t\v\003\177\234\313\12345z");
g_free (str);
/* test escape */
if (g_test_undefined ())
{
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
str = g_strescape (NULL, NULL);
g_test_assert_expected_messages ();
g_assert_null (str);
}
str = g_strescape ("abc\\\"\b\f\n\r\t\v\003\177\234\313", NULL);
g_assert_nonnull (str);
g_assert_cmpstr (str, ==, "abc\\\\\\\"\\b\\f\\n\\r\\t\\v\\003\\177\\234\\313");
g_free (str);
str = g_strescape ("abc\\\"\b\f\n\r\t\v\003\177\234\313",
"\b\f\001\002\003\004");
g_assert_nonnull (str);
g_assert_cmpstr (str, ==, "abc\\\\\\\"\b\f\\n\\r\\t\\v\003\\177\\234\\313");
g_free (str);
/* round trip */
tmp = g_strescape ("abc\\\"\b\f\n\r\t\v\003\177\234\313", NULL);
str = g_strcompress (tmp);
g_assert_nonnull (str);
g_assert_cmpstr (str, ==, "abc\\\"\b\f\n\r\t\v\003\177\234\313");
g_free (str);
g_free (tmp);
/* Unicode round trip */
str = g_strescape ("héllø there⸘", NULL);
g_assert_nonnull (str);
g_assert_cmpstr (str, ==, "h\\303\\251ll\\303\\270 there\\342\\270\\230");
tmp = g_strcompress (str);
g_assert_nonnull (tmp);
g_assert_cmpstr (tmp, ==, "héllø there⸘");
g_free (tmp);
g_free (str);
/* Test expanding invalid escapes */
str = g_strcompress ("\\11/ \\118 \\8aa \\19");
g_assert_nonnull (str);
g_assert_cmpstr (str, ==, "\t/ \t8 8aa \0019");
g_free (str);
}
/* Testing g_ascii_strcasecmp() and g_ascii_strncasecmp() */
static void
test_ascii_strcasecmp (void)
{
gboolean res;
if (g_test_undefined ())
{
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
res = g_ascii_strcasecmp ("foo", NULL);
g_test_assert_expected_messages ();
g_assert_false (res);
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
res = g_ascii_strcasecmp (NULL, "foo");
g_test_assert_expected_messages ();
g_assert_false (res);
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
res = g_ascii_strncasecmp ("foo", NULL, 0);
g_test_assert_expected_messages ();
g_assert_false (res);
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
res = g_ascii_strncasecmp (NULL, "foo", 0);
g_test_assert_expected_messages ();
g_assert_false (res);
}
res = g_ascii_strcasecmp ("FroboZZ", "frobozz");
g_assert_cmpint (res, ==, 0);
res = g_ascii_strcasecmp ("frobozz", "frobozz");
g_assert_cmpint (res, ==, 0);
res = g_ascii_strcasecmp ("frobozz", "FROBOZZ");
g_assert_cmpint (res, ==, 0);
res = g_ascii_strcasecmp ("FROBOZZ", "froboz");
g_assert_cmpint (res, !=, 0);
res = g_ascii_strcasecmp ("", "");
g_assert_cmpint (res, ==, 0);
res = g_ascii_strcasecmp ("!#%&/()", "!#%&/()");
g_assert_cmpint (res, ==, 0);
res = g_ascii_strcasecmp ("a", "b");
g_assert_cmpint (res, <, 0);
res = g_ascii_strcasecmp ("a", "B");
g_assert_cmpint (res, <, 0);
res = g_ascii_strcasecmp ("A", "b");
g_assert_cmpint (res, <, 0);
res = g_ascii_strcasecmp ("A", "B");
g_assert_cmpint (res, <, 0);
res = g_ascii_strcasecmp ("b", "a");
g_assert_cmpint (res, >, 0);
res = g_ascii_strcasecmp ("b", "A");
g_assert_cmpint (res, >, 0);
res = g_ascii_strcasecmp ("B", "a");
g_assert_cmpint (res, >, 0);
res = g_ascii_strcasecmp ("B", "A");
g_assert_cmpint (res, >, 0);
/* g_ascii_strncasecmp() */
res = g_ascii_strncasecmp ("", "", 10);
g_assert_cmpint (res, ==, 0);
res = g_ascii_strncasecmp ("Frob0ZZ", "frob0zz", strlen ("frobozz"));
g_assert_cmpint (res, ==, 0);
res = g_ascii_strncasecmp ("Frob0ZZ", "frobozz", strlen ("frobozz"));
g_assert_cmpint (res, !=, 0);
res = g_ascii_strncasecmp ("frob0ZZ", "FroB0zz", strlen ("frobozz"));
g_assert_cmpint (res, ==, 0);
res = g_ascii_strncasecmp ("Frob0ZZ", "froB0zz", strlen ("frobozz") - 5);
g_assert_cmpint (res, ==, 0);
res = g_ascii_strncasecmp ("Frob0ZZ", "froB0zz", strlen ("frobozz") + 5);
g_assert_cmpint (res, ==, 0);
}
static void
do_test_strchug (const gchar *str, const gchar *expected)
{
gchar *tmp;
gboolean res;
tmp = g_strdup (str);
g_strchug (tmp);
res = (strcmp (tmp, expected) == 0);
g_free (tmp);
g_assert_cmpint (res, ==, TRUE);
}
/* Testing g_strchug() function with various positive and negative cases */
static void
test_strchug (void)
{
if (g_test_undefined ())
{
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
g_strchug (NULL);
g_test_assert_expected_messages ();
}
do_test_strchug ("", "");
do_test_strchug (" ", "");
do_test_strchug ("\t\r\n ", "");
do_test_strchug (" a", "a");
do_test_strchug (" a", "a");
do_test_strchug ("a a", "a a");
do_test_strchug (" a a", "a a");
}
static void
do_test_strchomp (const gchar *str, const gchar *expected)
{
gchar *tmp;
gboolean res;
tmp = g_strdup (str);
g_strchomp (tmp);
res = (strcmp (tmp, expected) == 0);
g_free (tmp);
g_assert_cmpint (res, ==, TRUE);
}
/* Testing g_strchomp() function with various positive and negative cases */
static void
test_strchomp (void)
{
if (g_test_undefined ())
{
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
g_strchomp (NULL);
g_test_assert_expected_messages ();
}
do_test_strchomp ("", "");
do_test_strchomp (" ", "");
do_test_strchomp (" \t\r\n", "");
do_test_strchomp ("a ", "a");
do_test_strchomp ("a ", "a");
do_test_strchomp ("a a", "a a");
do_test_strchomp ("a a ", "a a");
}
/* Testing g_str_tokenize_and_fold() functions */
static void
test_str_tokenize_and_fold (void)
{
const gchar *local_str = "en_GB";
const gchar *sample = "The quick brown fox¸ jumps over the lazy dog.";
const gchar *special_cases = "quıck QUİCK QUİı QUıİ İıck ıİCK àìøş";
gchar **tokens, **alternates;
gchar
*expected_tokens[] = \
{"the", "quick", "brown", "fox", "jumps", "over", "the", "lazy", "dog", NULL},
*expected_tokens_alt[] = \
{ "quick", "quick", "quii", "quii", "iick", "iick", "àìøş", NULL};
if (g_test_undefined ())
{
/* Testing degenerated cases */
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
tokens = g_str_tokenize_and_fold (NULL, local_str, NULL);
g_test_assert_expected_messages ();
}
tokens = g_str_tokenize_and_fold (special_cases, local_str, &alternates);
g_assert_cmpint (g_strv_length (tokens), ==,
g_strv_length (expected_tokens_alt));
g_assert_true (g_strv_equal ((const gchar * const *) tokens,
(const gchar * const *) expected_tokens_alt));
g_strfreev (tokens);
g_strfreev (alternates);
tokens = g_str_tokenize_and_fold (sample, local_str, &alternates);
g_assert_cmpint (g_strv_length (tokens), ==, g_strv_length (expected_tokens));
g_assert_true (g_strv_equal ((const gchar * const *) tokens,
(const gchar * const *) expected_tokens));
g_strfreev (tokens);
g_strfreev (alternates);
tokens = g_str_tokenize_and_fold (sample, local_str, NULL);
g_assert_cmpint (g_strv_length (tokens), ==, g_strv_length (expected_tokens));
g_assert_true (g_strv_equal ((const gchar * const *) tokens,
(const gchar * const *) expected_tokens));
g_strfreev (tokens);
tokens = g_str_tokenize_and_fold (sample, NULL, &alternates);
g_assert_cmpint (g_strv_length (tokens), ==, g_strv_length (expected_tokens));
g_assert_true (g_strv_equal ((const gchar * const *) tokens,
(const gchar * const *) expected_tokens));
g_strfreev (tokens);
g_strfreev (alternates);
}
/* Testing g_strreverse() function with various positive and negative cases */
static void
test_strreverse (void)
{
gchar *str;
gchar *p;
if (g_test_undefined ())
{
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
str = g_strreverse (NULL);
g_test_assert_expected_messages ();
g_assert_null (str);
}
str = p = g_strdup ("abcde");
str = g_strreverse (str);
g_assert_nonnull (str);
g_assert_true (p == str);
g_assert_cmpstr (str, ==, "edcba");
g_free (str);
}
/* Testing g_strncasecmp() functions */
static void
test_strncasecmp (void)
{
g_assert_cmpint (g_strncasecmp ("abc1", "ABC2", 3), ==, 0);
g_assert_cmpint (g_strncasecmp ("abc1", "ABC2", 4), !=, 0);
}
static void
test_strstr (void)
{
gchar *haystack;
gchar *res;
haystack = g_strdup ("FooBarFooBarFoo");
if (g_test_undefined ())
{
/* Testing degenerated cases */
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
res = g_strstr_len (NULL, 0, "xxx");
g_test_assert_expected_messages ();
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
res = g_strstr_len ("xxx", 0, NULL);
g_test_assert_expected_messages ();
}
/* strstr_len */
res = g_strstr_len (haystack, 6, "xxx");
g_assert_null (res);
res = g_strstr_len (haystack, 6, "FooBarFooBarFooBar");
g_assert_null (res);
res = g_strstr_len (haystack, 3, "Bar");
g_assert_null (res);
res = g_strstr_len (haystack, 6, "");
g_assert_true (res == haystack);
g_assert_cmpstr (res, ==, "FooBarFooBarFoo");
res = g_strstr_len (haystack, 6, "Bar");
g_assert_true (res == haystack + 3);
g_assert_cmpstr (res, ==, "BarFooBarFoo");
res = g_strstr_len (haystack, -1, "Bar");
g_assert_true (res == haystack + 3);
g_assert_cmpstr (res, ==, "BarFooBarFoo");
/* strrstr */
if (g_test_undefined ())
{
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
res = g_strrstr (NULL, "xxx");
g_test_assert_expected_messages ();
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
res = g_strrstr ("xxx", NULL);
g_test_assert_expected_messages ();
}
res = g_strrstr (haystack, "xxx");
g_assert_null (res);
res = g_strrstr (haystack, "FooBarFooBarFooBar");
g_assert_null (res);
res = g_strrstr (haystack, "");
g_assert_true (res == haystack);
g_assert_cmpstr (res, ==, "FooBarFooBarFoo");
res = g_strrstr (haystack, "Bar");
g_assert_true (res == haystack + 9);
g_assert_cmpstr (res, ==, "BarFoo");
/* strrstr_len */
if (g_test_undefined ())
{
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
res = g_strrstr_len (NULL, 14, "xxx");
g_test_assert_expected_messages ();
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
res = g_strrstr_len ("xxx", 14, NULL);
g_test_assert_expected_messages ();
}
res = g_strrstr_len (haystack, 14, "xxx");
g_assert_null (res);
res = g_strrstr_len (haystack, 14, "FooBarFooBarFooBar");
g_assert_null (res);
res = g_strrstr_len (haystack, 3, "Bar");
g_assert_null (res);
res = g_strrstr_len (haystack, 14, "BarFoo");
g_assert_true (res == haystack + 3);
g_assert_cmpstr (res, ==, "BarFooBarFoo");
res = g_strrstr_len (haystack, 15, "BarFoo");
g_assert_true (res == haystack + 9);
g_assert_cmpstr (res, ==, "BarFoo");
res = g_strrstr_len (haystack, -1, "BarFoo");
g_assert_true (res == haystack + 9);
g_assert_cmpstr (res, ==, "BarFoo");
/* test case for strings with \0 in the middle */
*(haystack + 7) = '\0';
res = g_strstr_len (haystack, 15, "BarFoo");
g_assert_null (res);
g_free (haystack);
}
/* Testing g_strtod() function with various positive and negative cases */
static void
test_strtod (void)
{
gchar *str_end = NULL;
double value = 0.0;
const double gold_ratio = 1.61803398874989484;
const gchar *gold_ratio_str = "1.61803398874989484";
const gchar *minus_gold_ratio_str = "-1.61803398874989484";
if (g_test_undefined ())
{
/* Testing degenerated cases */
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
value = g_strtod (NULL, NULL);
g_test_assert_expected_messages ();
g_assert_cmpfloat (value, ==, 0.0);
}
g_assert_cmpfloat (g_strtod ("\x00\x00\x00\x00", NULL), ==, 0.0);
g_assert_cmpfloat (g_strtod ("\x00\x00\x00\x00", &str_end), ==, 0.0);
g_assert_cmpstr (str_end, ==, "");
g_assert_cmpfloat (g_strtod ("\xff\xff\xff\xff", NULL), ==, 0.0);
g_assert_cmpfloat (g_strtod ("\xff\xff\xff\xff", &str_end), ==, 0.0);
g_assert_cmpstr (str_end, ==, "\xff\xff\xff\xff");
/* Testing normal usage cases */
g_assert_cmpfloat (g_strtod (gold_ratio_str, NULL), ==, gold_ratio);
g_assert_cmpfloat (g_strtod (gold_ratio_str, &str_end), ==, gold_ratio);
g_assert_true (str_end == gold_ratio_str + strlen (gold_ratio_str));
g_assert_cmpfloat (g_strtod (minus_gold_ratio_str, NULL), ==, -gold_ratio);
g_assert_cmpfloat (g_strtod (minus_gold_ratio_str, &str_end), ==, -gold_ratio);
g_assert_true (str_end == minus_gold_ratio_str + strlen (minus_gold_ratio_str));
}
/* Testing g_strdelimit() function */
static void
test_strdelimit (void)
{
const gchar *const_string = "ABCDE<*>Q";
gchar *string;
if (g_test_undefined ())
{
/* Testing degenerated cases */
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
string = g_strdelimit (NULL, "ABCDE", 'N');
g_test_assert_expected_messages ();
}
string = g_strdelimit (g_strdup (const_string), "<>", '?');
g_assert_cmpstr (string, ==, "ABCDE?*?Q");
g_free (string);
string = g_strdelimit (g_strdup (const_string), NULL, '?');
g_assert_cmpstr (string, ==, "ABCDE?*?Q");
g_free (string);
}
/* Testing g_str_has_prefix() */
static void
test_has_prefix (void)
{
gboolean res;
if (g_test_undefined ())
{
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
res = g_str_has_prefix ("foo", NULL);
g_test_assert_expected_messages ();
g_assert_false (res);
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
res = g_str_has_prefix (NULL, "foo");
g_test_assert_expected_messages ();
g_assert_false (res);
}
res = g_str_has_prefix ("foo", "bar");
g_assert_cmpint (res, ==, FALSE);
res = g_str_has_prefix ("foo", "foobar");
g_assert_cmpint (res, ==, FALSE);
res = g_str_has_prefix ("foobar", "bar");
g_assert_cmpint (res, ==, FALSE);
res = g_str_has_prefix ("foobar", "foo");
g_assert_cmpint (res, ==, TRUE);
res = g_str_has_prefix ("foo", "");
g_assert_cmpint (res, ==, TRUE);
res = g_str_has_prefix ("foo", "foo");
g_assert_cmpint (res, ==, TRUE);
res = g_str_has_prefix ("", "");
g_assert_cmpint (res, ==, TRUE);
}
static void
test_has_suffix (void)
{
gboolean res;
if (g_test_undefined ())
{
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
res = g_str_has_suffix ("foo", NULL);
g_test_assert_expected_messages ();
g_assert_false (res);
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
res = g_str_has_suffix (NULL, "foo");
g_test_assert_expected_messages ();
g_assert_false (res);
}
res = g_str_has_suffix ("foo", "bar");
g_assert_false (res);
res = g_str_has_suffix ("bar", "foobar");
g_assert_false (res);
res = g_str_has_suffix ("foobar", "foo");
g_assert_false (res);
res = g_str_has_suffix ("foobar", "bar");
g_assert_true (res);
res = g_str_has_suffix ("foo", "");
g_assert_true (res);
res = g_str_has_suffix ("foo", "foo");
g_assert_true (res);
res = g_str_has_suffix ("", "");
g_assert_true (res);
}
static void
strv_check (gchar **strv, ...)
{
gboolean ok = TRUE;
gint i = 0;
va_list list;
va_start (list, strv);
while (ok)
{
const gchar *str = va_arg (list, const char *);
if (strv[i] == NULL)
{
g_assert_null (str);
break;
}
if (str == NULL)
{
ok = FALSE;
}
else
{
g_assert_cmpstr (strv[i], ==, str);
}
i++;
}
va_end (list);
g_strfreev (strv);
}
/* Testing g_strsplit() function with various positive and negative cases */
static void
test_strsplit (void)
{
gchar **string = NULL;
if (g_test_undefined ())
{
/* Testing degenerated cases */
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
string = g_strsplit (NULL, ",", 0);
g_test_assert_expected_messages ();
g_assert_null (string);
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
string = g_strsplit ("x", NULL, 0);
g_test_assert_expected_messages ();
g_assert_null (string);
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion \'delimiter[0] != \'\\0\'*");
string = g_strsplit ("x", "", 0);
g_test_assert_expected_messages ();
g_assert_null (string);
}
strv_check (g_strsplit ("", ",", 0), NULL);
strv_check (g_strsplit ("x", ",", 0), "x", NULL);
strv_check (g_strsplit ("x,y", ",", 0), "x", "y", NULL);
strv_check (g_strsplit ("x,y,", ",", 0), "x", "y", "", NULL);
strv_check (g_strsplit (",x,y", ",", 0), "", "x", "y", NULL);
strv_check (g_strsplit (",x,y,", ",", 0), "", "x", "y", "", NULL);
strv_check (g_strsplit ("x,y,z", ",", 0), "x", "y", "z", NULL);
strv_check (g_strsplit ("x,y,z,", ",", 0), "x", "y", "z", "", NULL);
strv_check (g_strsplit (",x,y,z", ",", 0), "", "x", "y", "z", NULL);
strv_check (g_strsplit (",x,y,z,", ",", 0), "", "x", "y", "z", "", NULL);
strv_check (g_strsplit (",,x,,y,,z,,", ",", 0), "", "", "x", "", "y", "", "z", "", "", NULL);
strv_check (g_strsplit (",,x,,y,,z,,", ",,", 0), "", "x", "y", "z", "", NULL);
strv_check (g_strsplit ("", ",", 1), NULL);
strv_check (g_strsplit ("x", ",", 1), "x", NULL);
strv_check (g_strsplit ("x,y", ",", 1), "x,y", NULL);
strv_check (g_strsplit ("x,y,", ",", 1), "x,y,", NULL);
strv_check (g_strsplit (",x,y", ",", 1), ",x,y", NULL);
strv_check (g_strsplit (",x,y,", ",", 1), ",x,y,", NULL);
strv_check (g_strsplit ("x,y,z", ",", 1), "x,y,z", NULL);
strv_check (g_strsplit ("x,y,z,", ",", 1), "x,y,z,", NULL);
strv_check (g_strsplit (",x,y,z", ",", 1), ",x,y,z", NULL);
strv_check (g_strsplit (",x,y,z,", ",", 1), ",x,y,z,", NULL);
strv_check (g_strsplit (",,x,,y,,z,,", ",", 1), ",,x,,y,,z,,", NULL);
strv_check (g_strsplit (",,x,,y,,z,,", ",,", 1), ",,x,,y,,z,,", NULL);
strv_check (g_strsplit ("", ",", 2), NULL);
strv_check (g_strsplit ("x", ",", 2), "x", NULL);
strv_check (g_strsplit ("x,y", ",", 2), "x", "y", NULL);
strv_check (g_strsplit ("x,y,", ",", 2), "x", "y,", NULL);
strv_check (g_strsplit (",x,y", ",", 2), "", "x,y", NULL);
strv_check (g_strsplit (",x,y,", ",", 2), "", "x,y,", NULL);
strv_check (g_strsplit ("x,y,z", ",", 2), "x", "y,z", NULL);
strv_check (g_strsplit ("x,y,z,", ",", 2), "x", "y,z,", NULL);
strv_check (g_strsplit (",x,y,z", ",", 2), "", "x,y,z", NULL);
strv_check (g_strsplit (",x,y,z,", ",", 2), "", "x,y,z,", NULL);
strv_check (g_strsplit (",,x,,y,,z,,", ",", 2), "", ",x,,y,,z,,", NULL);
strv_check (g_strsplit (",,x,,y,,z,,", ",,", 2), "", "x,,y,,z,,", NULL);
}
/* Testing function g_strsplit_set() */
static void
test_strsplit_set (void)
{
gchar **string = NULL;
if (g_test_undefined ())
{
/* Testing degenerated cases */
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
string = g_strsplit_set (NULL, ",/", 0);
g_test_assert_expected_messages ();
g_assert_null (string);
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
string = g_strsplit_set ("", NULL, 0);
g_test_assert_expected_messages ();
g_assert_null (string);
}
strv_check (g_strsplit_set ("", ",/", 0), NULL);
strv_check (g_strsplit_set (":def/ghi:", ":/", -1), "", "def", "ghi", "", NULL);
strv_check (g_strsplit_set ("abc:def/ghi", ":/", -1), "abc", "def", "ghi", NULL);
strv_check (g_strsplit_set (",;,;,;,;", ",;", -1), "", "", "", "", "", "", "", "", "", NULL);
strv_check (g_strsplit_set (",,abc.def", ".,", -1), "", "", "abc", "def", NULL);
strv_check (g_strsplit_set (",x.y", ",.", 0), "", "x", "y", NULL);
strv_check (g_strsplit_set (".x,y,", ",.", 0), "", "x", "y", "", NULL);
strv_check (g_strsplit_set ("x,y.z", ",.", 0), "x", "y", "z", NULL);
strv_check (g_strsplit_set ("x.y,z,", ",.", 0), "x", "y", "z", "", NULL);
strv_check (g_strsplit_set (",x.y,z", ",.", 0), "", "x", "y", "z", NULL);
strv_check (g_strsplit_set (",x,y,z,", ",.", 0), "", "x", "y", "z", "", NULL);
strv_check (g_strsplit_set (",.x,,y,;z..", ".,;", 0), "", "", "x", "", "y", "", "z", "", "", NULL);
strv_check (g_strsplit_set (",,x,,y,,z,,", ",,", 0), "", "", "x", "", "y", "", "z", "", "", NULL);
strv_check (g_strsplit_set ("x,y.z", ",.", 1), "x,y.z", NULL);
strv_check (g_strsplit_set ("x.y,z,", ",.", 1), "x.y,z,", NULL);
strv_check (g_strsplit_set (",x,y,z", ",.", 1), ",x,y,z", NULL);
strv_check (g_strsplit_set (",x,y.z,", ",.", 1), ",x,y.z,", NULL);
strv_check (g_strsplit_set (",,x,.y,,z,,", ",.", 1), ",,x,.y,,z,,", NULL);
strv_check (g_strsplit_set (",.x,,y,,z,,", ",,..", 1), ",.x,,y,,z,,", NULL);
strv_check (g_strsplit_set ("", ",", 0), NULL);
strv_check (g_strsplit_set ("x", ",", 0), "x", NULL);
strv_check (g_strsplit_set ("x,y", ",", 0), "x", "y", NULL);
strv_check (g_strsplit_set ("x,y,", ",", 0), "x", "y", "", NULL);
strv_check (g_strsplit_set (",x,y", ",", 0), "", "x", "y", NULL);
strv_check (g_strsplit_set (",x,y,", ",", 0), "", "x", "y", "", NULL);
strv_check (g_strsplit_set ("x,y,z", ",", 0), "x", "y", "z", NULL);
strv_check (g_strsplit_set ("x,y,z,", ",", 0), "x", "y", "z", "", NULL);
strv_check (g_strsplit_set (",x,y,z", ",", 0), "", "x", "y", "z", NULL);
strv_check (g_strsplit_set (",x,y,z,", ",", 0), "", "x", "y", "z", "", NULL);
strv_check (g_strsplit_set (",,x,,y,,z,,", ",", 0), "", "", "x", "", "y", "", "z", "", "", NULL);
strv_check (g_strsplit_set ("", ",", 1), NULL);
strv_check (g_strsplit_set ("x", ",", 1), "x", NULL);
strv_check (g_strsplit_set ("x,y", ",", 1), "x,y", NULL);
strv_check (g_strsplit_set ("x,y,", ",", 1), "x,y,", NULL);
strv_check (g_strsplit_set (",x,y", ",", 1), ",x,y", NULL);
strv_check (g_strsplit_set (",x,y,", ",", 1), ",x,y,", NULL);
strv_check (g_strsplit_set ("x,y,z", ",", 1), "x,y,z", NULL);
strv_check (g_strsplit_set ("x,y,z,", ",", 1), "x,y,z,", NULL);
strv_check (g_strsplit_set (",x,y,z", ",", 1), ",x,y,z", NULL);
strv_check (g_strsplit_set (",x,y,z,", ",", 1), ",x,y,z,", NULL);
strv_check (g_strsplit_set (",,x,,y,,z,,", ",", 1), ",,x,,y,,z,,", NULL);
strv_check (g_strsplit_set (",,x,,y,,z,,", ",,", 1), ",,x,,y,,z,,", NULL);
strv_check (g_strsplit_set ("", ",", 2), NULL);
strv_check (g_strsplit_set ("x", ",", 2), "x", NULL);
strv_check (g_strsplit_set ("x,y", ",", 2), "x", "y", NULL);
strv_check (g_strsplit_set ("x,y,", ",", 2), "x", "y,", NULL);
strv_check (g_strsplit_set (",x,y", ",", 2), "", "x,y", NULL);
strv_check (g_strsplit_set (",x,y,", ",", 2), "", "x,y,", NULL);
strv_check (g_strsplit_set ("x,y,z", ",", 2), "x", "y,z", NULL);
strv_check (g_strsplit_set ("x,y,z,", ",", 2), "x", "y,z,", NULL);
strv_check (g_strsplit_set (",x,y,z", ",", 2), "", "x,y,z", NULL);
strv_check (g_strsplit_set (",x,y,z,", ",", 2), "", "x,y,z,", NULL);
strv_check (g_strsplit_set (",,x,,y,,z,,", ",", 2), "", ",x,,y,,z,,", NULL);
strv_check (g_strsplit_set (",,x,.y,..z,,", ",.", 3), "", "", "x,.y,..z,,", NULL);
}
/* Testing g_strv_length() function with various positive and negative cases */
static void
test_strv_length (void)
{
gchar **strv;
guint l;
if (g_test_undefined ())
{
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
l = g_strv_length (NULL);
g_test_assert_expected_messages ();
g_assert_cmpint (l, ==, 0);
}
strv = g_strsplit ("1,2,3,4", ",", -1);
l = g_strv_length (strv);
g_assert_cmpuint (l, ==, 4);
g_strfreev (strv);
}
static char *locales[] = {"sv_SE", "en_US", "fa_IR", "C", "ru_RU"};
static void
check_strtod_string (gchar *number,
double res,
gboolean check_end,
gsize correct_len)
{
double d;
gsize l;
gchar *dummy;
/* we try a copy of number, with some free space for malloc before that.
* This is supposed to smash the some wrong pointer calculations. */
dummy = g_malloc (100000);
number = g_strdup (number);
g_free (dummy);
for (l = 0; l < G_N_ELEMENTS (locales); l++)
{
gchar *end = "(unset)";
setlocale (LC_NUMERIC, locales[l]);
d = g_ascii_strtod (number, &end);
g_assert_true (isnan (res) ? isnan (d) : (d == res));
g_assert_true ((gsize) (end - number) ==
(check_end ? correct_len : strlen (number)));
}
g_free (number);
}
static void
check_strtod_number (gdouble num, gchar *fmt, gchar *str)
{
gsize l;
gchar buf[G_ASCII_DTOSTR_BUF_SIZE];
for (l = 0; l < G_N_ELEMENTS (locales); l++)
{
setlocale (LC_ALL, locales[l]);
g_ascii_formatd (buf, G_ASCII_DTOSTR_BUF_SIZE, fmt, num);
g_assert_cmpstr (buf, ==, str);
}
}
/* Testing g_ascii_strtod() function with various positive and negative cases */
static void
test_ascii_strtod (void)
{
gdouble d, our_nan, our_inf;
char buffer[G_ASCII_DTOSTR_BUF_SIZE];
#ifdef NAN
our_nan = NAN;
#else
/* Do this before any call to setlocale. */
our_nan = atof ("NaN");
#endif
g_assert_true (isnan (our_nan));
#ifdef INFINITY
our_inf = INFINITY;
#else
our_inf = atof ("Infinity");
#endif
g_assert_true (our_inf > 1 && our_inf == our_inf / 2);
/* Testing degenerated cases */
if (g_test_undefined ())
{
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
d = g_ascii_strtod (NULL, NULL);
g_test_assert_expected_messages ();
}
/* Testing normal cases */
check_strtod_string ("123.123", 123.123, FALSE, 0);
check_strtod_string ("123.123e2", 123.123e2, FALSE, 0);
check_strtod_string ("123.123e-2", 123.123e-2, FALSE, 0);
check_strtod_string ("-123.123", -123.123, FALSE, 0);
check_strtod_string ("-123.123e2", -123.123e2, FALSE, 0);
check_strtod_string ("-123.123e-2", -123.123e-2, FALSE, 0);
check_strtod_string ("5.4", 5.4, TRUE, 3);
check_strtod_string ("5.4,5.5", 5.4, TRUE, 3);
check_strtod_string ("5,4", 5.0, TRUE, 1);
#ifndef _MSC_VER
/* hex strings for strtod() is a C99 feature which Visual C++ does not support */
check_strtod_string ("0xa.b", 10.6875, TRUE, 5);
check_strtod_string ("0xa.bP3", 85.5, TRUE, 7);
check_strtod_string ("0xa.bp+3", 85.5, TRUE, 8);
check_strtod_string ("0xa.bp-2", 2.671875, TRUE, 8);
check_strtod_string ("0xA.BG", 10.6875, TRUE, 5);
#endif
/* the following are for #156421 */
check_strtod_string ("1e1", 1e1, FALSE, 0);
#ifndef _MSC_VER
/* NAN/-nan/INF/-infinity strings for strtod() are C99 features which Visual C++ does not support */
check_strtod_string ("NAN", our_nan, FALSE, 0);
check_strtod_string ("-nan", -our_nan, FALSE, 0);
check_strtod_string ("INF", our_inf, FALSE, 0);
check_strtod_string ("-infinity", -our_inf, FALSE, 0);
#endif
check_strtod_string ("-.75,0", -0.75, TRUE, 4);
#ifndef _MSC_VER
/* the values of d in the following 2 tests generate a C1064 compiler limit error */
d = 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0;
g_assert_true (d == g_ascii_strtod (g_ascii_dtostr (buffer, sizeof (buffer), d), NULL));
d = -179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0;
g_assert_true (d == g_ascii_strtod (g_ascii_dtostr (buffer, sizeof (buffer), d), NULL));
#endif
d = pow (2.0, -1024.1);
g_assert_true (d == g_ascii_strtod (g_ascii_dtostr (buffer, sizeof (buffer), d), NULL));
d = -pow (2.0, -1024.1);
g_assert_true (d == g_ascii_strtod (g_ascii_dtostr (buffer, sizeof (buffer), d), NULL));
/* for #343899 */
check_strtod_string (" 0.75", 0.75, FALSE, 0);
check_strtod_string (" +0.75", 0.75, FALSE, 0);
check_strtod_string (" -0.75", -0.75, FALSE, 0);
check_strtod_string ("\f0.75", 0.75, FALSE, 0);
check_strtod_string ("\n0.75", 0.75, FALSE, 0);
check_strtod_string ("\r0.75", 0.75, FALSE, 0);
check_strtod_string ("\t0.75", 0.75, FALSE, 0);
#if 0
/* g_ascii_isspace() returns FALSE for vertical tab, see #59388 */
check_strtod_string ("\v0.75", 0.75, FALSE, 0);
#endif
/* for #343899 */
check_strtod_number (0.75, "%0.2f", "0.75");
check_strtod_number (0.75, "%5.2f", " 0.75");
check_strtod_number (-0.75, "%0.2f", "-0.75");
check_strtod_number (-0.75, "%5.2f", "-0.75");
check_strtod_number (1e99, "%.0e", "1e+99");
}
static void
check_uint64 (const gchar *str,
const gchar *end,
gint base,
guint64 result,
gint error)
{
guint64 actual;
gchar *endptr = NULL;
gint err;
errno = 0;
actual = g_ascii_strtoull (str, &endptr, base);
err = errno;
g_assert_true (actual == result);
g_assert_cmpstr (end, ==, endptr);
g_assert_true (err == error);
}
static void
check_int64 (const gchar *str,
const gchar *end,
gint base,
gint64 result,
gint error)
{
gint64 actual;
gchar *endptr = NULL;
gint err;
errno = 0;
actual = g_ascii_strtoll (str, &endptr, base);
err = errno;
g_assert_true (actual == result);
g_assert_cmpstr (end, ==, endptr);
g_assert_true (err == error);
}
static void
test_strtoll (void)
{
check_uint64 ("0", "", 10, 0, 0);
check_uint64 ("+0", "", 10, 0, 0);
check_uint64 ("-0", "", 10, 0, 0);
check_uint64 ("18446744073709551615", "", 10, G_MAXUINT64, 0);
check_uint64 ("18446744073709551616", "", 10, G_MAXUINT64, ERANGE);
check_uint64 ("20xyz", "xyz", 10, 20, 0);
check_uint64 ("-1", "", 10, G_MAXUINT64, 0);
check_uint64 ("-FF4", "", 16, -((guint64) 0xFF4), 0);
check_int64 ("0", "", 10, 0, 0);
check_int64 ("9223372036854775807", "", 10, G_MAXINT64, 0);
check_int64 ("9223372036854775808", "", 10, G_MAXINT64, ERANGE);
check_int64 ("-9223372036854775808", "", 10, G_MININT64, 0);
check_int64 ("-9223372036854775809", "", 10, G_MININT64, ERANGE);
check_int64 ("32768", "", 10, 32768, 0);
check_int64 ("-32768", "", 10, -32768, 0);
check_int64 ("001", "", 10, 1, 0);
check_int64 ("-001", "", 10, -1, 0);
}
/* Testing g_str_match_string() function with various cases */
static void
test_str_match_string (void)
{
gboolean result = TRUE;
const gchar *str = "The quick brown fox¸ jumps over the lazy dog.";
if (g_test_undefined ())
{
/* Testing degenerated cases */
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
result = g_str_match_string (NULL, "AAA", TRUE);
g_test_assert_expected_messages ();
g_assert_false (result);
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
result = g_str_match_string (str, NULL, TRUE);
g_test_assert_expected_messages ();
g_assert_false (result);
}
g_assert_false (g_str_match_string (str, "AAA", TRUE));
g_assert_false (g_str_match_string (str, "AAA", FALSE));
}
/* Testing functions bounds */
static void
test_bounds (void)
{
GMappedFile *file, *before, *after;
char buffer[4097];
char *tmp, *tmp2;
char **array;
char *string;
const char * const strjoinv_0[] = { NULL };
const char * const strjoinv_1[] = { "foo", NULL };
/* if we allocate the file between two others and then free those
* other two, then hopefully we end up with unmapped memory on either
* side.
*/
before = g_mapped_file_new ("4096-random-bytes", TRUE, NULL);
/* quick workaround until #549783 can be fixed */
if (before == NULL)
return;
file = g_mapped_file_new ("4096-random-bytes", TRUE, NULL);
after = g_mapped_file_new ("4096-random-bytes", TRUE, NULL);
g_mapped_file_unref (before);
g_mapped_file_unref (after);
g_assert_nonnull (file);
g_assert_cmpint (g_mapped_file_get_length (file), ==, 4096);
string = g_mapped_file_get_contents (file);
/* ensure they're all non-nul */
g_assert_null (memchr (string, '\0', 4096));
/* test set 1: ensure that nothing goes past its maximum length, even in
* light of a missing nul terminator.
*
* we try to test all of the 'n' functions here.
*/
tmp = g_strndup (string, 4096);
g_assert_cmpint (strlen (tmp), ==, 4096);
g_free (tmp);
/* found no bugs in gnome, i hope :) */
g_assert_null (g_strstr_len (string, 4096, "BUGS"));
g_strstr_len (string, 4096, "B");
g_strstr_len (string, 4096, ".");
g_strstr_len (string, 4096, "");
g_strrstr_len (string, 4096, "BUGS");
g_strrstr_len (string, 4096, "B");
g_strrstr_len (string, 4096, ".");
g_strrstr_len (string, 4096, "");
tmp = g_ascii_strup (string, 4096);
tmp2 = g_ascii_strup (tmp, 4096);
g_assert_cmpint (g_ascii_strncasecmp (string, tmp, 4096), ==, 0);
g_assert_cmpint (g_ascii_strncasecmp (string, tmp2, 4096), ==, 0);
g_assert_cmpint (g_ascii_strncasecmp (tmp, tmp2, 4096), ==, 0);
g_free (tmp);
g_free (tmp2);
tmp = g_ascii_strdown (string, 4096);
tmp2 = g_ascii_strdown (tmp, 4096);
g_assert_cmpint (g_ascii_strncasecmp (string, tmp, 4096), ==, 0);
g_assert_cmpint (g_ascii_strncasecmp (string, tmp2, 4096), ==, 0);
g_assert_cmpint (g_ascii_strncasecmp (tmp, tmp2, 4096), ==, 0);
g_free (tmp);
g_free (tmp2);
tmp = g_markup_escape_text (string, 4096);
g_free (tmp);
/* test set 2: ensure that nothing reads even one byte past a '\0'.
*/
g_assert_cmpint (string[4095], ==, '\n');
string[4095] = '\0';
tmp = g_strdup (string);
g_assert_cmpint (strlen (tmp), ==, 4095);
g_free (tmp);
tmp = g_strndup (string, 10000);
g_assert_cmpint (strlen (tmp), ==, 4095);
g_free (tmp);
g_stpcpy (buffer, string);
g_assert_cmpint (strlen (buffer), ==, 4095);
g_strstr_len (string, 10000, "BUGS");
g_strstr_len (string, 10000, "B");
g_strstr_len (string, 10000, ".");
g_strstr_len (string, 10000, "");
g_strrstr (string, "BUGS");
g_strrstr (string, "B");
g_strrstr (string, ".");
g_strrstr (string, "");
g_strrstr_len (string, 10000, "BUGS");
g_strrstr_len (string, 10000, "B");
g_strrstr_len (string, 10000, ".");
g_strrstr_len (string, 10000, "");
g_str_has_prefix (string, "this won't do very much...");
g_str_has_suffix (string, "but maybe this will...");
g_str_has_suffix (string, "HMMMM.");
g_str_has_suffix (string, "MMMM.");
g_str_has_suffix (string, "M.");
g_strlcpy (buffer, string, sizeof buffer);
g_assert_cmpint (strlen (buffer), ==, 4095);
g_strlcpy (buffer, string, sizeof buffer);
buffer[0] = '\0';
g_strlcat (buffer, string, sizeof buffer);
g_assert_cmpint (strlen (buffer), ==, 4095);
tmp = g_strdup_printf ("<%s>", string);
g_assert_cmpint (strlen (tmp), ==, 4095 + 2);
g_free (tmp);
tmp = g_ascii_strdown (string, -1);
tmp2 = g_ascii_strdown (tmp, -1);
g_assert_cmpint (strlen (tmp), ==, strlen (tmp2));
g_assert_cmpint (strlen (string), ==, strlen (tmp));
g_assert_cmpint (g_ascii_strncasecmp (string, tmp, -1), ==, 0);
g_assert_cmpint (g_ascii_strncasecmp (string, tmp2, -1), ==, 0);
g_assert_cmpint (g_ascii_strncasecmp (tmp, tmp2, -1), ==, 0);
g_free (tmp);
g_free (tmp2);
tmp = g_ascii_strup (string, -1);
tmp2 = g_ascii_strup (string, -1);
g_assert_cmpint (strlen (tmp), ==, strlen (tmp2));
g_assert_cmpint (strlen (string), ==, strlen (tmp));
g_assert_cmpint (g_ascii_strncasecmp (string, tmp, -1), ==, 0);
g_assert_cmpint (g_ascii_strncasecmp (string, tmp2, -1), ==, 0);
g_assert_cmpint (g_ascii_strncasecmp (tmp, tmp2, -1), ==, 0);
g_free (tmp);
g_free (tmp2);
g_ascii_strcasecmp (string, string);
g_ascii_strncasecmp (string, string, 10000);
g_strreverse (string);
g_strreverse (string);
g_strchug (string);
g_strchomp (string);
g_strstrip (string);
g_assert_cmpint (strlen (string), ==, 4095);
g_strdelimit (string, "M", 'N');
g_strcanon (string, " N.", ':');
g_assert_cmpint (strlen (string), ==, 4095);
array = g_strsplit (string, ".", -1);
tmp = g_strjoinv (".", array);
g_strfreev (array);
g_assert_cmpmem (tmp, strlen (tmp), string, 4095);
g_free (tmp);
tmp = g_strjoinv ("/", (char **) strjoinv_0);
g_assert_cmpstr (tmp, ==, "");
g_free (tmp);
tmp = g_strjoinv ("/", (char **) strjoinv_1);
g_assert_cmpstr (tmp, ==, "foo");
g_free (tmp);
tmp = g_strconcat (string, string, string, NULL);
g_assert_cmpint (strlen (tmp), ==, 4095 * 3);
g_free (tmp);
tmp = g_strjoin ("!", string, string, NULL);
g_assert_cmpint (strlen (tmp), ==, 4095 + 1 + 4095);
g_free (tmp);
tmp = g_markup_escape_text (string, -1);
g_free (tmp);
tmp = g_markup_printf_escaped ("%s", string);
g_free (tmp);
tmp = g_strescape (string, NULL);
tmp2 = g_strcompress (tmp);
g_assert_cmpstr (string, ==, tmp2);
g_free (tmp2);
g_free (tmp);
g_mapped_file_unref (file);
}
/* Testing g_strip_context() function with various cases */
static void
test_strip_context (void)
{
const gchar *msgid;
const gchar *msgval;
const gchar *s;
msgid = "blabla";
msgval = "bla";
s = g_strip_context (msgid, msgval);
g_assert_true (s == msgval);
msgid = msgval = "blabla";
s = g_strip_context (msgid, msgval);
g_assert_true (s == msgval);
msgid = msgval = "blabla|foo";
s = g_strip_context (msgid, msgval);
g_assert_true (s == msgval + 7);
msgid = msgval = "blabla||bar";
s = g_strip_context (msgid, msgval);
g_assert_true (s == msgval + 7);
}
/* Test the strings returned by g_strerror() are valid and unique. On Windows,
* fewer than 200 error numbers are used, so we expect some strings to
* return a generic unknown error code message. */
static void
test_strerror (void)
{
GHashTable *strs;
gint i;
const gchar *str, *unknown_str;
setlocale (LC_ALL, "C");
unknown_str = g_strerror (-1);
strs = g_hash_table_new (g_str_hash, g_str_equal);
for (i = 1; i < 200; i++)
{
gboolean is_unknown;
str = g_strerror (i);
is_unknown = (strcmp (str, unknown_str) == 0);
g_assert_nonnull (str);
g_assert_true (g_utf8_validate (str, -1, NULL));
g_assert_true (!g_hash_table_contains (strs, str) || is_unknown);
g_hash_table_add (strs, (gpointer) str);
}
g_hash_table_unref (strs);
}
/* Testing g_strsignal() function with various cases */
static void
test_strsignal (void)
{
gint i;
const gchar *str;
for (i = 1; i < 20; i++)
{
str = g_strsignal (i);
g_assert_nonnull (str);
g_assert_true (g_utf8_validate (str, -1, NULL));
}
}
/* Testing g_strup(), g_strdown() and g_strcasecmp() */
static void
test_strup (void)
{
gchar *s = NULL;
if (g_test_undefined ())
{
/* Testing degenerated cases */
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
s = g_strup (NULL);
g_test_assert_expected_messages ();
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
s = g_strdown (NULL);
g_test_assert_expected_messages ();
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
g_strcasecmp (NULL, "ABCD");
g_test_assert_expected_messages ();
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
g_strcasecmp ("abcd", NULL);
g_test_assert_expected_messages ();
}
s = g_strdup ("lower UPPER");
g_assert_cmpstr (g_strup (s), ==, "LOWER UPPER");
g_assert_cmpstr (g_strdown (s), ==, "lower upper");
g_assert_true (g_strcasecmp ("lower", "LOWER") == 0);
g_free (s);
}
/* Testing g_str_to_ascii() function with various cases */
static void
test_transliteration (void)
{
gchar *out;
/* ...to test the defaults */
setlocale (LC_ALL, "C");
/* Test something trivial */
out = g_str_to_ascii ("hello", NULL);
g_assert_cmpstr (out, ==, "hello");
g_free (out);
/* Test something above 0xffff */
out = g_str_to_ascii ("𝐀𝐀𝐀", NULL);
g_assert_cmpstr (out, ==, "AAA");
g_free (out);
/* Test something with no good match */
out = g_str_to_ascii ("a ∧ ¬a", NULL);
g_assert_cmpstr (out, ==, "a ? ?a");
g_free (out);
/* Make sure 'ö' is handled differently per locale */
out = g_str_to_ascii ("ö", NULL);
g_assert_cmpstr (out, ==, "o");
g_free (out);
out = g_str_to_ascii ("ö", "sv");
g_assert_cmpstr (out, ==, "o");
g_free (out);
out = g_str_to_ascii ("ö", "de");
g_assert_cmpstr (out, ==, "oe");
g_free (out);
/* Make sure we can find a locale by a wide range of names */
out = g_str_to_ascii ("ö", "de_DE");
g_assert_cmpstr (out, ==, "oe");
g_free (out);
out = g_str_to_ascii ("ö", "de_DE.UTF-8");
g_assert_cmpstr (out, ==, "oe");
g_free (out);
out = g_str_to_ascii ("ö", "de_DE.UTF-8@euro");
g_assert_cmpstr (out, ==, "oe");
g_free (out);
out = g_str_to_ascii ("ö", "de@euro");
g_assert_cmpstr (out, ==, "oe");
g_free (out);
/* Test some invalid locale names */
out = g_str_to_ascii ("ö", "de_DE@euro.UTF-8");
g_assert_cmpstr (out, ==, "o");
g_free (out);
out = g_str_to_ascii ("ö", "de@DE@euro");
g_assert_cmpstr (out, ==, "o");
g_free (out);
out = g_str_to_ascii ("ö", "doesnotexist");
g_assert_cmpstr (out, ==, "o");
g_free (out);
out = g_str_to_ascii ("ö", "thislocalenameistoolong");
g_assert_cmpstr (out, ==, "o");
g_free (out);
/* Try a lookup of a locale with a variant */
out = g_str_to_ascii ("б", "sr_RS");
g_assert_cmpstr (out, ==, "b");
g_free (out);
out = g_str_to_ascii ("б", "sr_RS@latin");
g_assert_cmpstr (out, ==, "?");
g_free (out);
/* Ukrainian contains the only multi-character mappings.
* Try a string that contains one ('зг') along with a partial
* sequence ('з') at the end.
*/
out = g_str_to_ascii ("Зліва направо, згори вниз", "uk");
g_assert_cmpstr (out, ==, "Zliva napravo, zghory vnyz");
g_free (out);
/* Try out the other combinations */
out = g_str_to_ascii ("Зг", "uk");
g_assert_cmpstr (out, ==, "Zgh");
g_free (out);
out = g_str_to_ascii ("зГ", "uk");
g_assert_cmpstr (out, ==, "zGH");
g_free (out);
out = g_str_to_ascii ("ЗГ", "uk");
g_assert_cmpstr (out, ==, "ZGH");
g_free (out);
/* And a non-combination */
out = g_str_to_ascii ("зя", "uk");
g_assert_cmpstr (out, ==, "zya");
g_free (out);
}
/* Testing g_strv_contains() function with various cases */
static void
test_strv_contains (void)
{
gboolean result = TRUE;
const gchar *strv_simple[] = { "hello", "there", NULL };
const gchar *strv_dupe[] = { "dupe", "dupe", NULL };
const gchar *strv_empty[] = { NULL };
if (g_test_undefined ())
{
/* Testing degenerated cases */
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
result = g_strv_contains (NULL, "hello");
g_test_assert_expected_messages ();
g_assert_false (result);
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
result = g_strv_contains (strv_simple, NULL);
g_test_assert_expected_messages ();
g_assert_false (result);
}
g_assert_true (g_strv_contains (strv_simple, "hello"));
g_assert_true (g_strv_contains (strv_simple, "there"));
g_assert_false (g_strv_contains (strv_simple, "non-existent"));
g_assert_false (g_strv_contains (strv_simple, ""));
g_assert_true (g_strv_contains (strv_dupe, "dupe"));
g_assert_false (g_strv_contains (strv_empty, "empty!"));
g_assert_false (g_strv_contains (strv_empty, ""));
}
/* Test g_strv_equal() works for various inputs. */
static void
test_strv_equal (void)
{
gboolean result = TRUE;
const gchar *strv_empty[] = { NULL };
const gchar *strv_empty2[] = { NULL };
const gchar *strv_simple[] = { "hello", "you", NULL };
const gchar *strv_simple2[] = { "hello", "you", NULL };
const gchar *strv_simple_reordered[] = { "you", "hello", NULL };
const gchar *strv_simple_superset[] = { "hello", "you", "again", NULL };
const gchar *strv_another[] = { "not", "a", "coded", "message", NULL };
if (g_test_undefined ())
{
/* Testing degenerated cases */
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
result = g_strv_equal (NULL, strv_simple2);
g_test_assert_expected_messages ();
g_assert_false (result);
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
result = g_strv_equal (strv_simple, NULL);
g_test_assert_expected_messages ();
g_assert_false (result);
}
g_assert_true (g_strv_equal (strv_empty, strv_empty));
g_assert_true (g_strv_equal (strv_empty, strv_empty2));
g_assert_true (g_strv_equal (strv_empty2, strv_empty));
g_assert_false (g_strv_equal (strv_empty, strv_simple));
g_assert_false (g_strv_equal (strv_simple, strv_empty));
g_assert_true (g_strv_equal (strv_simple, strv_simple));
g_assert_true (g_strv_equal (strv_simple, strv_simple2));
g_assert_true (g_strv_equal (strv_simple2, strv_simple));
g_assert_false (g_strv_equal (strv_simple, strv_simple_reordered));
g_assert_false (g_strv_equal (strv_simple_reordered, strv_simple));
g_assert_false (g_strv_equal (strv_simple, strv_simple_superset));
g_assert_false (g_strv_equal (strv_simple_superset, strv_simple));
g_assert_false (g_strv_equal (strv_simple, strv_another));
g_assert_false (g_strv_equal (strv_another, strv_simple));
}
typedef enum
{
SIGNED,
UNSIGNED
} SignType;
typedef struct
{
const gchar *str;
SignType sign_type;
guint base;
gint min;
gint max;
gint expected;
gboolean should_fail;
GNumberParserError error_code;
} TestData;
const TestData test_data[] = {
/* typical cases for signed */
{ "0", SIGNED, 10, -2, 2, 0, FALSE, 0 },
{ "+0", SIGNED, 10, -2, 2, 0, FALSE, 0 },
{ "-0", SIGNED, 10, -2, 2, 0, FALSE, 0 },
{ "-2", SIGNED, 10, -2, 2, -2, FALSE, 0 },
{"-02", SIGNED, 10, -2, 2, -2, FALSE, 0 },
{ "2", SIGNED, 10, -2, 2, 2, FALSE, 0 },
{ "02", SIGNED, 10, -2, 2, 2, FALSE, 0 },
{ "+2", SIGNED, 10, -2, 2, 2, FALSE, 0 },
{"+02", SIGNED, 10, -2, 2, 2, FALSE, 0 },
{ "3", SIGNED, 10, -2, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_OUT_OF_BOUNDS },
{ "+3", SIGNED, 10, -2, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_OUT_OF_BOUNDS },
{ "-3", SIGNED, 10, -2, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_OUT_OF_BOUNDS },
/* typical cases for unsigned */
{ "-1", UNSIGNED, 10, 0, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID },
{ "1", UNSIGNED, 10, 0, 2, 1, FALSE, 0 },
{ "+1", UNSIGNED, 10, 0, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID },
{ "0", UNSIGNED, 10, 0, 2, 0, FALSE, 0 },
{ "+0", UNSIGNED, 10, 0, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID },
{ "-0", UNSIGNED, 10, 0, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID },
{ "2", UNSIGNED, 10, 0, 2, 2, FALSE, 0 },
{ "+2", UNSIGNED, 10, 0, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID },
{ "3", UNSIGNED, 10, 0, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_OUT_OF_BOUNDS },
{ "+3", UNSIGNED, 10, 0, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID },
/* min == max cases for signed */
{ "-2", SIGNED, 10, -2, -2, -2, FALSE, 0 },
{ "-1", SIGNED, 10, -2, -2, 0, TRUE, G_NUMBER_PARSER_ERROR_OUT_OF_BOUNDS },
{ "-3", SIGNED, 10, -2, -2, 0, TRUE, G_NUMBER_PARSER_ERROR_OUT_OF_BOUNDS },
/* min == max cases for unsigned */
{ "2", UNSIGNED, 10, 2, 2, 2, FALSE, 0 },
{ "3", UNSIGNED, 10, 2, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_OUT_OF_BOUNDS },
{ "1", UNSIGNED, 10, 2, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_OUT_OF_BOUNDS },
/* invalid inputs */
{ "", SIGNED, 10, -2, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID },
{ "", UNSIGNED, 10, 0, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID },
{ "a", SIGNED, 10, -2, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID },
{ "a", UNSIGNED, 10, 0, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID },
{ "1a", SIGNED, 10, -2, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID },
{ "1a", UNSIGNED, 10, 0, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID },
{ "- 1", SIGNED, 10, -2, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID },
/* leading/trailing whitespace */
{ " 1", SIGNED, 10, -2, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID },
{ " 1", UNSIGNED, 10, 0, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID },
{ "1 ", SIGNED, 10, -2, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID },
{ "1 ", UNSIGNED, 10, 0, 2, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID },
/* hexadecimal numbers */
{ "a", SIGNED, 16, 0, 15, 10, FALSE, 0 },
{ "a", UNSIGNED, 16, 0, 15, 10, FALSE, 0 },
{ "0a", UNSIGNED, 16, 0, 15, 10, FALSE, 0 },
{ "0xa", SIGNED, 16, 0, 15, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID },
{ "0xa", UNSIGNED, 16, 0, 15, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID },
{ "-0xa", SIGNED, 16, -15, 15, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID },
{ "-0xa", UNSIGNED, 16, 0, 15, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID },
{ "+0xa", SIGNED, 16, 0, 15, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID },
{ "+0xa", UNSIGNED, 16, 0, 15, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID },
{ "- 0xa", SIGNED, 16, -15, 15, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID },
{ "- 0xa", UNSIGNED, 16, 0, 15, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID },
{ "+ 0xa", SIGNED, 16, -15, 15, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID },
{ "+ 0xa", UNSIGNED, 16, 0, 15, 0, TRUE, G_NUMBER_PARSER_ERROR_INVALID },
};
/* Testing g_ascii_string_to_signed() and g_ascii_string_to_unsigned() functions */
static void
test_ascii_string_to_number_usual (void)
{
gsize idx;
gboolean result;
GError *error = NULL;
const TestData *data;
gint value;
gint64 value64 = 0;
guint64 valueu64 = 0;
/*** g_ascii_string_to_signed() ***/
data = &test_data[0]; /* Setting data to signed data */
if (g_test_undefined ())
{
/* Testing degenerated cases */
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
result = g_ascii_string_to_signed (NULL,
data->base,
data->min,
data->max,
&value64,
&error);
g_test_assert_expected_messages ();
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion \'base >= 2 && base <= 36\'*");
result = g_ascii_string_to_signed (data->str,
1,
data->min,
data->max,
&value64,
&error);
g_test_assert_expected_messages ();
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion \'base >= 2 && base <= 36\'*");
result = g_ascii_string_to_signed (data->str,
40,
data->min,
data->max,
&value64,
&error);
g_test_assert_expected_messages ();
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion \'min <= max\'*");
result = g_ascii_string_to_signed (data->str,
data->base,
data->max,
data->min,
&value64,
&error);
g_test_assert_expected_messages ();
}
/* Catching first part of (error == NULL || *error == NULL) */
result = g_ascii_string_to_signed (data->str,
data->base,
data->min,
data->max,
&value64,
NULL);
/*** g_ascii_string_to_unsigned() ***/
data = &test_data[12]; /* Setting data to unsigned data */
if (g_test_undefined ())
{
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion*!= NULL*");
result = g_ascii_string_to_unsigned (NULL,
data->base,
data->min,
data->max,
&valueu64,
&error);
g_test_assert_expected_messages ();
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion \'base >= 2 && base <= 36\'*");
result = g_ascii_string_to_unsigned (data->str,
1,
data->min,
data->max,
&valueu64,
&error);
g_test_assert_expected_messages ();
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion \'base >= 2 && base <= 36\'*");
result = g_ascii_string_to_unsigned (data->str,
40,
data->min,
data->max,
&valueu64,
&error);
g_test_assert_expected_messages ();
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*assertion \'min <= max\'*");
result = g_ascii_string_to_unsigned (data->str,
data->base,
data->max,
data->min,
&valueu64,
&error);
g_test_assert_expected_messages ();
}
/* Catching first part of (error == NULL || *error == NULL) */
result = g_ascii_string_to_unsigned (data->str,
data->base,
data->min,
data->max,
&valueu64,
NULL);
/* Testing usual cases */
for (idx = 0; idx < G_N_ELEMENTS (test_data); ++idx)
{
data = &test_data[idx];
switch (data->sign_type)
{
case SIGNED:
{
result = g_ascii_string_to_signed (data->str,
data->base,
data->min,
data->max,
&value64,
&error);
value = value64;
g_assert_cmpint (value, ==, value64);
break;
}
case UNSIGNED:
{
guint64 value64 = 0;
result = g_ascii_string_to_unsigned (data->str,
data->base,
data->min,
data->max,
&value64,
&error);
value = value64;
g_assert_cmpint (value, ==, value64);
break;
}
default:
g_assert_not_reached ();
}
if (data->should_fail)
{
g_assert_false (result);
g_assert_error (error, G_NUMBER_PARSER_ERROR, (gint) data->error_code);
g_clear_error (&error);
}
else
{
g_assert_true (result);
g_assert_no_error (error);
g_assert_cmpint (value, ==, data->expected);
}
}
}
/* Testing pathological cases for g_ascii_string_to_(un)signed() */
static void
test_ascii_string_to_number_pathological (void)
{
GError *error = NULL;
const gchar *crazy_high = "999999999999999999999999999999999999";
const gchar *crazy_low = "-999999999999999999999999999999999999";
const gchar *max_uint64 = "18446744073709551615";
const gchar *max_int64 = "9223372036854775807";
const gchar *min_int64 = "-9223372036854775808";
guint64 uvalue = 0;
gint64 svalue = 0;
g_assert_false (g_ascii_string_to_unsigned (crazy_high,
10,
0,
G_MAXUINT64,
NULL,
&error));
g_assert_error (error, G_NUMBER_PARSER_ERROR, G_NUMBER_PARSER_ERROR_OUT_OF_BOUNDS);
g_clear_error (&error);
g_assert_false (g_ascii_string_to_unsigned (crazy_low,
10,
0,
G_MAXUINT64,
NULL,
&error));
// crazy_low is a signed number so it is not a valid unsigned number
g_assert_error (error, G_NUMBER_PARSER_ERROR, G_NUMBER_PARSER_ERROR_INVALID);
g_clear_error (&error);
g_assert_false (g_ascii_string_to_signed (crazy_high,
10,
G_MININT64,
G_MAXINT64,
NULL,
&error));
g_assert_error (error, G_NUMBER_PARSER_ERROR, G_NUMBER_PARSER_ERROR_OUT_OF_BOUNDS);
g_clear_error (&error);
g_assert_false (g_ascii_string_to_signed (crazy_low,
10,
G_MININT64,
G_MAXINT64,
NULL,
&error));
g_assert_error (error, G_NUMBER_PARSER_ERROR, G_NUMBER_PARSER_ERROR_OUT_OF_BOUNDS);
g_clear_error (&error);
g_assert_true (g_ascii_string_to_unsigned (max_uint64,
10,
0,
G_MAXUINT64,
&uvalue,
&error));
g_assert_no_error (error);
g_assert_cmpint (uvalue, ==, G_MAXUINT64);
g_assert_true (g_ascii_string_to_signed (max_int64,
10,
G_MININT64,
G_MAXINT64,
&svalue,
&error));
g_assert_no_error (error);
g_assert_cmpint (svalue, ==, G_MAXINT64);
g_assert_true (g_ascii_string_to_signed (min_int64,
10,
G_MININT64,
G_MAXINT64,
&svalue,
&error));
g_assert_no_error (error);
g_assert_cmpint (svalue, ==, G_MININT64);
}
int
main (int argc,
char *argv[])
{
g_test_init (&argc, &argv, NULL);
g_test_add_func ("/strfuncs/ascii-strcasecmp", test_ascii_strcasecmp);
g_test_add_func ("/strfuncs/ascii-string-to-num/pathological", test_ascii_string_to_number_pathological);
g_test_add_func ("/strfuncs/ascii-string-to-num/usual", test_ascii_string_to_number_usual);
g_test_add_func ("/strfuncs/ascii_strdown", test_ascii_strdown);
g_test_add_func ("/strfuncs/ascii_strdup", test_ascii_strup);
g_test_add_func ("/strfuncs/ascii_strtod", test_ascii_strtod);
g_test_add_func ("/strfuncs/bounds-check", test_bounds);
g_test_add_func ("/strfuncs/has-prefix", test_has_prefix);
g_test_add_func ("/strfuncs/has-suffix", test_has_suffix);
g_test_add_func ("/strfuncs/memdup", test_memdup);
g_test_add_func ("/strfuncs/memdup2", test_memdup2);
g_test_add_func ("/strfuncs/stpcpy", test_stpcpy);
g_test_add_func ("/strfuncs/str_match_string", test_str_match_string);
g_test_add_func ("/strfuncs/str_tokenize_and_fold", test_str_tokenize_and_fold);
g_test_add_func ("/strfuncs/strcanon", test_strcanon);
g_test_add_func ("/strfuncs/strchomp", test_strchomp);
g_test_add_func ("/strfuncs/strchug", test_strchug);
g_test_add_func ("/strfuncs/strcompress-strescape", test_strcompress_strescape);
g_test_add_func ("/strfuncs/strconcat", test_strconcat);
g_test_add_func ("/strfuncs/strdelimit", test_strdelimit);
g_test_add_func ("/strfuncs/strdup", test_strdup);
g_test_add_func ("/strfuncs/strdup-printf", test_strdup_printf);
g_test_add_func ("/strfuncs/strdupv", test_strdupv);
g_test_add_func ("/strfuncs/strerror", test_strerror);
g_test_add_func ("/strfuncs/strip-context", test_strip_context);
g_test_add_func ("/strfuncs/strjoin", test_strjoin);
g_test_add_func ("/strfuncs/strjoinv", test_strjoinv);
g_test_add_func ("/strfuncs/strlcat", test_strlcat);
g_test_add_func ("/strfuncs/strlcpy", test_strlcpy);
g_test_add_func ("/strfuncs/strncasecmp", test_strncasecmp);
g_test_add_func ("/strfuncs/strndup", test_strndup);
g_test_add_func ("/strfuncs/strnfill", test_strnfill);
g_test_add_func ("/strfuncs/strreverse", test_strreverse);
g_test_add_func ("/strfuncs/strsignal", test_strsignal);
g_test_add_func ("/strfuncs/strsplit", test_strsplit);
g_test_add_func ("/strfuncs/strsplit-set", test_strsplit_set);
g_test_add_func ("/strfuncs/strstr", test_strstr);
g_test_add_func ("/strfuncs/strtod", test_strtod);
g_test_add_func ("/strfuncs/strtoull-strtoll", test_strtoll);
g_test_add_func ("/strfuncs/strup", test_strup);
g_test_add_func ("/strfuncs/strv-contains", test_strv_contains);
g_test_add_func ("/strfuncs/strv-equal", test_strv_equal);
g_test_add_func ("/strfuncs/strv-length", test_strv_length);
g_test_add_func ("/strfuncs/test-is-to-digit", test_is_to_digit);
g_test_add_func ("/strfuncs/transliteration", test_transliteration);
return g_test_run();
}