Merge branch 'wip/nielsdg/g_assert_cmpstrv' into 'master'

Add g_assert_cmpstrv() test utility

Closes #2015

See merge request GNOME/glib!1732
This commit is contained in:
Philip Withnall 2020-11-14 18:59:46 +00:00
commit e21bdf2219
7 changed files with 173 additions and 26 deletions

View File

@ -3547,6 +3547,7 @@ g_assert
g_assert_not_reached g_assert_not_reached
g_assert_cmpstr g_assert_cmpstr
g_assert_cmpstrv
g_assert_cmpint g_assert_cmpint
g_assert_cmpuint g_assert_cmpuint
g_assert_cmphex g_assert_cmphex

View File

@ -350,6 +350,7 @@ wait_for_file (const gchar *want_this,
static void static void
test_actions (void) test_actions (void)
{ {
const char *expected[] = { "frob", "tweak", "twiddle", "broken", NULL };
const gchar * const *actions; const gchar * const *actions;
GDesktopAppInfo *appinfo; GDesktopAppInfo *appinfo;
gchar *name; gchar *name;
@ -358,11 +359,7 @@ test_actions (void)
g_assert_nonnull (appinfo); g_assert_nonnull (appinfo);
actions = g_desktop_app_info_list_actions (appinfo); actions = g_desktop_app_info_list_actions (appinfo);
g_assert_cmpstr (actions[0], ==, "frob"); g_assert_cmpstrv (actions, expected);
g_assert_cmpstr (actions[1], ==, "tweak");
g_assert_cmpstr (actions[2], ==, "twiddle");
g_assert_cmpstr (actions[3], ==, "broken");
g_assert_cmpstr (actions[4], ==, NULL);
name = g_desktop_app_info_get_action_name (appinfo, "frob"); name = g_desktop_app_info_get_action_name (appinfo, "frob");
g_assert_cmpstr (name, ==, "Frobnicate"); g_assert_cmpstr (name, ==, "Frobnicate");

View File

@ -576,6 +576,30 @@
* Since: 2.16 * Since: 2.16
*/ */
/**
* g_assert_cmpstrv:
* @strv1: (nullable): a string array (may be %NULL)
* @strv2: (nullable): another string array (may be %NULL)
*
* Debugging macro to check if two %NULL-terminated string arrays (i.e. 2
* #GStrv) are equal. If they are not equal, an error message is logged and the
* application is either terminated or the testcase marked as failed.
* If both arrays are %NULL, the check passes. If one array is %NULL but the
* other is not, an error message is logged.
*
* The effect of `g_assert_cmpstrv (strv1, strv2)` is the same as
* `g_assert_true (g_strv_equal (strv1, strv2))` (if both arrays are not
* %NULL). The advantage of this macro is that it can produce a message that
* includes how @strv1 and @strv2 are different.
*
* |[<!-- language="C" -->
* const char *expected[] = { "one", "two", "three", NULL };
* g_assert_cmpstrv (mystrv, expected);
* ]|
*
* Since: 2.68
*/
/** /**
* g_assert_cmpint: * g_assert_cmpint:
* @n1: an integer * @n1: an integer
@ -3018,6 +3042,31 @@ g_assertion_message_cmpstr (const char *domain,
g_free (s); g_free (s);
} }
void
g_assertion_message_cmpstrv (const char *domain,
const char *file,
int line,
const char *func,
const char *expr,
const char * const *arg1,
const char * const *arg2,
gsize first_wrong_idx)
{
const char *s1 = arg1[first_wrong_idx], *s2 = arg2[first_wrong_idx];
char *a1, *a2, *s, *t1 = NULL, *t2 = NULL;
a1 = arg1 ? g_strconcat ("\"", t1 = g_strescape (s1, NULL), "\"", NULL) : g_strdup ("NULL");
a2 = arg2 ? g_strconcat ("\"", t2 = g_strescape (s2, NULL), "\"", NULL) : g_strdup ("NULL");
g_free (t1);
g_free (t2);
s = g_strdup_printf ("assertion failed (%s): first differing element at index %" G_GSIZE_FORMAT ": %s does not equal %s",
expr, first_wrong_idx, a1, a2);
g_free (a1);
g_free (a2);
g_assertion_message (domain, file, line, func, s);
g_free (s);
}
void void
g_assertion_message_error (const char *domain, g_assertion_message_error (const char *domain,
const char *file, const char *file,

View File

@ -111,6 +111,51 @@ typedef void (*GTestFixtureFunc) (gpointer fixture,
} \ } \
} \ } \
G_STMT_END G_STMT_END
#define g_assert_cmpstrv(strv1, strv2) \
G_STMT_START \
{ \
const char * const *__strv1 = (const char * const *) (strv1); \
const char * const *__strv2 = (const char * const *) (strv2); \
if (!__strv1 || !__strv2) \
{ \
if (__strv1) \
{ \
g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
"assertion failed (" #strv1 " == " #strv2 "): " #strv2 " is NULL, but " #strv1 " is not"); \
} \
else if (__strv2) \
{ \
g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
"assertion failed (" #strv1 " == " #strv2 "): " #strv1 " is NULL, but " #strv2 " is not"); \
} \
} \
else \
{ \
guint __l1 = g_strv_length ((char **) __strv1); \
guint __l2 = g_strv_length ((char **) __strv2); \
if (__l1 != __l2) \
{ \
char *__msg; \
__msg = g_strdup_printf ("assertion failed (" #strv1 " == " #strv2 "): length %u does not equal length %u", __l1, __l2); \
g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, __msg); \
g_free (__msg); \
} \
else \
{ \
guint __i; \
for (__i = 0; __i < __l1; __i++) \
{ \
if (g_strcmp0 (__strv1[__i], __strv2[__i]) != 0) \
{ \
g_assertion_message_cmpstrv (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
#strv1 " == " #strv2, \
__strv1, __strv2, __i); \
} \
} \
} \
} \
} \
G_STMT_END
#define g_assert_no_errno(expr) G_STMT_START { \ #define g_assert_no_errno(expr) G_STMT_START { \
int __ret, __errsv; \ int __ret, __errsv; \
errno = 0; \ errno = 0; \
@ -483,6 +528,16 @@ void g_assertion_message_cmpstr (const char *domain,
const char *arg1, const char *arg1,
const char *cmp, const char *cmp,
const char *arg2) G_ANALYZER_NORETURN; const char *arg2) G_ANALYZER_NORETURN;
GLIB_AVAILABLE_IN_2_68
void g_assertion_message_cmpstrv (const char *domain,
const char *file,
int line,
const char *func,
const char *expr,
const char * const *arg1,
const char * const *arg2,
gsize first_wrong_idx) G_ANALYZER_NORETURN;
GLIB_AVAILABLE_IN_ALL GLIB_AVAILABLE_IN_ALL
void g_assertion_message_cmpnum (const char *domain, void g_assertion_message_cmpnum (const char *domain,
const char *file, const char *file,

View File

@ -2992,18 +2992,6 @@ test_varargs_empty_array (void)
g_assert_not_reached (); g_assert_not_reached ();
} }
static void
assert_cmpstrv (const gchar **strv1, const gchar **strv2)
{
gsize i;
for (i = 0; strv1[i] != NULL && strv2[i] != NULL; i++)
g_assert_cmpstr (strv1[i], ==, strv2[i]);
g_assert_null (strv1[i]);
g_assert_null (strv2[i]);
}
static void static void
test_varargs (void) test_varargs (void)
{ {
@ -3153,8 +3141,8 @@ test_varargs (void)
g_variant_iter_next (&tuple, "^a&s", &strv); g_variant_iter_next (&tuple, "^a&s", &strv);
g_variant_iter_next (&tuple, "^as", &my_strv); g_variant_iter_next (&tuple, "^as", &my_strv);
assert_cmpstrv (strv, strvector); g_assert_cmpstrv (strv, strvector);
assert_cmpstrv ((const char **)my_strv, strvector); g_assert_cmpstrv (my_strv, strvector);
g_variant_unref (value); g_variant_unref (value);
g_strfreev (my_strv); g_strfreev (my_strv);
@ -3223,8 +3211,8 @@ test_varargs (void)
g_variant_iter_next (&tuple, "^a&ay", &strv); g_variant_iter_next (&tuple, "^a&ay", &strv);
g_variant_iter_next (&tuple, "^aay", &my_strv); g_variant_iter_next (&tuple, "^aay", &my_strv);
assert_cmpstrv (strv, strvector); g_assert_cmpstrv (strv, strvector);
assert_cmpstrv ((const char **)my_strv, strvector); g_assert_cmpstrv (my_strv, strvector);
g_variant_unref (value); g_variant_unref (value);
g_strfreev (my_strv); g_strfreev (my_strv);
@ -3272,8 +3260,8 @@ test_varargs (void)
g_variant_iter_next (&tuple, "^a&o", &strv); g_variant_iter_next (&tuple, "^a&o", &strv);
g_variant_iter_next (&tuple, "^ao", &my_strv); g_variant_iter_next (&tuple, "^ao", &my_strv);
assert_cmpstrv (strv, strvector); g_assert_cmpstrv (strv, strvector);
assert_cmpstrv ((const char **)my_strv, strvector); g_assert_cmpstrv (my_strv, strvector);
g_variant_unref (value); g_variant_unref (value);
g_strfreev (my_strv); g_strfreev (my_strv);

View File

@ -525,9 +525,7 @@ test_strdupv (void)
copy = g_strdupv (vec); copy = g_strdupv (vec);
g_assert_nonnull (copy); g_assert_nonnull (copy);
g_assert_cmpstr (copy[0], ==, "Foo"); g_assert_cmpstrv (copy, vec);
g_assert_cmpstr (copy[1], ==, "Bar");
g_assert_null (copy[2]);
g_strfreev (copy); g_strfreev (copy);
} }

View File

@ -66,6 +66,40 @@ test_assertions_bad_cmpvariant_values (void)
exit (0); exit (0);
} }
static void
test_assertions_bad_cmpstrv_null1 (void)
{
const char *strv[] = { "one", "two", "three", NULL };
g_assert_cmpstrv (strv, NULL);
exit (0);
}
static void
test_assertions_bad_cmpstrv_null2 (void)
{
const char *strv[] = { "one", "two", "three", NULL };
g_assert_cmpstrv (NULL, strv);
exit (0);
}
static void
test_assertions_bad_cmpstrv_length (void)
{
const char *strv1[] = { "one", "two", "three", NULL };
const char *strv2[] = { "one", "two", NULL };
g_assert_cmpstrv (strv1, strv2);
exit (0);
}
static void
test_assertions_bad_cmpstrv_values (void)
{
const char *strv1[] = { "one", "two", "three", NULL };
const char *strv2[] = { "one", "too", "three", NULL };
g_assert_cmpstrv (strv1, strv2);
exit (0);
}
static void static void
test_assertions_bad_cmpstr (void) test_assertions_bad_cmpstr (void)
{ {
@ -132,6 +166,8 @@ test_assertions_bad_no_errno (void)
static void static void
test_assertions (void) test_assertions (void)
{ {
const char *strv1[] = { "one", "two", "three", NULL };
const char *strv2[] = { "one", "two", "three", NULL };
GVariant *v1, *v2; GVariant *v1, *v2;
gchar *fuu; gchar *fuu;
@ -160,6 +196,9 @@ test_assertions (void)
g_assert_cmpmem ("foo", 0, NULL, 0); g_assert_cmpmem ("foo", 0, NULL, 0);
g_assert_no_errno (return_no_errno ()); g_assert_no_errno (return_no_errno ());
g_assert_cmpstrv (NULL, NULL);
g_assert_cmpstrv (strv1, strv2);
v1 = g_variant_new_parsed ("['hello', 'there']"); v1 = g_variant_new_parsed ("['hello', 'there']");
v2 = g_variant_new_parsed ("['hello', 'there']"); v2 = g_variant_new_parsed ("['hello', 'there']");
@ -181,6 +220,22 @@ test_assertions (void)
g_test_trap_assert_failed (); g_test_trap_assert_failed ();
g_test_trap_assert_stderr ("*assertion failed*"); g_test_trap_assert_stderr ("*assertion failed*");
g_test_trap_subprocess ("/misc/assertions/subprocess/bad_cmpstrv_null1", 0, 0);
g_test_trap_assert_failed ();
g_test_trap_assert_stderr ("*assertion failed*");
g_test_trap_subprocess ("/misc/assertions/subprocess/bad_cmpstrv_null2", 0, 0);
g_test_trap_assert_failed ();
g_test_trap_assert_stderr ("*assertion failed*");
g_test_trap_subprocess ("/misc/assertions/subprocess/bad_cmpstrv_length", 0, 0);
g_test_trap_assert_failed ();
g_test_trap_assert_stderr ("*assertion failed*");
g_test_trap_subprocess ("/misc/assertions/subprocess/bad_cmpstrv_values", 0, 0);
g_test_trap_assert_failed ();
g_test_trap_assert_stderr ("*assertion failed*");
g_test_trap_subprocess ("/misc/assertions/subprocess/bad_cmpint", 0, 0); g_test_trap_subprocess ("/misc/assertions/subprocess/bad_cmpint", 0, 0);
g_test_trap_assert_failed (); g_test_trap_assert_failed ();
g_test_trap_assert_stderr ("*assertion failed*"); g_test_trap_assert_stderr ("*assertion failed*");
@ -1303,6 +1358,10 @@ main (int argc,
g_test_add_func ("/misc/assertions/subprocess/bad_cmpvariant_types", test_assertions_bad_cmpvariant_types); g_test_add_func ("/misc/assertions/subprocess/bad_cmpvariant_types", test_assertions_bad_cmpvariant_types);
g_test_add_func ("/misc/assertions/subprocess/bad_cmpvariant_values", test_assertions_bad_cmpvariant_values); g_test_add_func ("/misc/assertions/subprocess/bad_cmpvariant_values", test_assertions_bad_cmpvariant_values);
g_test_add_func ("/misc/assertions/subprocess/bad_cmpstr", test_assertions_bad_cmpstr); g_test_add_func ("/misc/assertions/subprocess/bad_cmpstr", test_assertions_bad_cmpstr);
g_test_add_func ("/misc/assertions/subprocess/bad_cmpstrv_null1", test_assertions_bad_cmpstrv_null1);
g_test_add_func ("/misc/assertions/subprocess/bad_cmpstrv_null2", test_assertions_bad_cmpstrv_null2);
g_test_add_func ("/misc/assertions/subprocess/bad_cmpstrv_length", test_assertions_bad_cmpstrv_length);
g_test_add_func ("/misc/assertions/subprocess/bad_cmpstrv_values", test_assertions_bad_cmpstrv_values);
g_test_add_func ("/misc/assertions/subprocess/bad_cmpint", test_assertions_bad_cmpint); g_test_add_func ("/misc/assertions/subprocess/bad_cmpint", test_assertions_bad_cmpint);
g_test_add_func ("/misc/assertions/subprocess/bad_cmpmem_len", test_assertions_bad_cmpmem_len); g_test_add_func ("/misc/assertions/subprocess/bad_cmpmem_len", test_assertions_bad_cmpmem_len);
g_test_add_func ("/misc/assertions/subprocess/bad_cmpmem_data", test_assertions_bad_cmpmem_data); g_test_add_func ("/misc/assertions/subprocess/bad_cmpmem_data", test_assertions_bad_cmpmem_data);