From 9e45b95816f36ae3bafbffdc97b5193897f6a1b9 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 31 Oct 2019 11:22:16 +0000 Subject: [PATCH 1/2] gtestutils: Add a new g_assert_no_errno() test macro This is for use in testing POSIX-style functions like `rmdir()`, which return an integer < 0 on failure, and return their error information in `errno`. The new macro prints `errno` and `g_strerror (errno)` on failure. Includes a unit test. Signed-off-by: Philip Withnall --- docs/reference/glib/glib-sections.txt | 1 + glib/gtestutils.c | 18 ++++++++++++++++++ glib/gtestutils.h | 15 +++++++++++++++ glib/tests/testing.c | 27 +++++++++++++++++++++++++++ 4 files changed, 61 insertions(+) diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt index b1d78ccc3..30cd94a78 100644 --- a/docs/reference/glib/glib-sections.txt +++ b/docs/reference/glib/glib-sections.txt @@ -3459,6 +3459,7 @@ g_assert_true g_assert_false g_assert_null g_assert_nonnull +g_assert_no_errno g_test_set_nonfatal_assertions GTestCase diff --git a/glib/gtestutils.c b/glib/gtestutils.c index 1010dcc1b..d9e9b5edd 100644 --- a/glib/gtestutils.c +++ b/glib/gtestutils.c @@ -659,6 +659,24 @@ * Since: 2.58 */ +/** + * g_assert_no_errno: + * @expr: the expression to check + * + * Debugging macro to check that an expression has a non-negative return value, + * as used by traditional POSIX functions (such as `rmdir()`) to indicate + * success. + * + * If the assertion fails (i.e. the @expr returns a negative value), an error + * message is logged and the testcase is marked as failed. The error message + * will contain the value of `errno` and its human-readable message from + * g_strerror(). + * + * This macro will clear the value of `errno` before executing @expr. + * + * Since: 2.66 + */ + /** * g_assert_cmpmem: * @m1: (nullable): pointer to a buffer diff --git a/glib/gtestutils.h b/glib/gtestutils.h index 66b7ef3b7..298caa403 100644 --- a/glib/gtestutils.h +++ b/glib/gtestutils.h @@ -27,6 +27,7 @@ #include #include #include +#include #include G_BEGIN_DECLS @@ -110,6 +111,20 @@ typedef void (*GTestFixtureFunc) (gpointer fixture, } \ } \ G_STMT_END +#define g_assert_no_errno(expr) G_STMT_START { \ + int __ret, __errsv; \ + errno = 0; \ + __ret = expr; \ + __errsv = errno; \ + if (__ret < 0) \ + { \ + gchar *__msg; \ + __msg = g_strdup_printf ("assertion failed (" #expr " >= 0): errno %i: %s", __errsv, g_strerror (__errsv)); \ + g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, __msg); \ + g_free (__msg); \ + } \ + } G_STMT_END \ + GLIB_AVAILABLE_MACRO_IN_2_66 #define g_assert_no_error(err) G_STMT_START { \ if (err) \ g_assertion_message_error (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \ diff --git a/glib/tests/testing.c b/glib/tests/testing.c index d0ce2c1e7..ed4c8d6f7 100644 --- a/glib/tests/testing.c +++ b/glib/tests/testing.c @@ -108,6 +108,27 @@ test_assertions_bad_cmpfloat_epsilon (void) exit (0); } +/* Emulates something like rmdir() failing. */ +static int +return_errno (void) +{ + errno = ERANGE; /* arbitrary non-zero value */ + return -1; +} + +/* Emulates something like rmdir() succeeding. */ +static int +return_no_errno (void) +{ + return 0; +} + +static void +test_assertions_bad_no_errno (void) +{ + g_assert_no_errno (return_errno ()); +} + static void test_assertions (void) { @@ -137,6 +158,7 @@ test_assertions (void) g_assert_cmpmem (NULL, 0, NULL, 0); g_assert_cmpmem (NULL, 0, "foot", 0); g_assert_cmpmem ("foo", 0, NULL, 0); + g_assert_no_errno (return_no_errno ()); v1 = g_variant_new_parsed ("['hello', 'there']"); v2 = g_variant_new_parsed ("['hello', 'there']"); @@ -179,6 +201,10 @@ test_assertions (void) g_test_trap_subprocess ("/misc/assertions/subprocess/bad_cmpfloat_epsilon", 0, 0); g_test_trap_assert_failed (); g_test_trap_assert_stderr ("*assertion failed*"); + + g_test_trap_subprocess ("/misc/assertions/subprocess/bad_no_errno", 0, 0); + g_test_trap_assert_failed (); + g_test_trap_assert_stderr ("*assertion failed*"); } /* test g_test_timer* API */ @@ -1282,6 +1308,7 @@ main (int argc, g_test_add_func ("/misc/assertions/subprocess/bad_cmpmem_data", test_assertions_bad_cmpmem_data); g_test_add_func ("/misc/assertions/subprocess/bad_cmpmem_null", test_assertions_bad_cmpmem_null); g_test_add_func ("/misc/assertions/subprocess/bad_cmpfloat_epsilon", test_assertions_bad_cmpfloat_epsilon); + g_test_add_func ("/misc/assertions/subprocess/bad_no_errno", test_assertions_bad_no_errno); g_test_add_data_func ("/misc/test-data", (void*) 0xc0c0baba, test_data_test); g_test_add ("/misc/primetoul", Fixturetest, (void*) 0xc0cac01a, fixturetest_setup, fixturetest_test, fixturetest_teardown); if (g_test_perf()) From 9166a0e0add37911ffb710090a3246620fd2ab6d Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 31 Oct 2019 11:24:31 +0000 Subject: [PATCH 2/2] gtestutils: Clarify documentation for g_test_set_nonfatal_assertions() It seems a bit unhelpful to list every single `g_assert_*()` macro, to rephrase the documentation to use globs instead. Add a missing word below. Signed-off-by: Philip Withnall --- glib/gtestutils.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/glib/gtestutils.c b/glib/gtestutils.c index d9e9b5edd..e054cb7b7 100644 --- a/glib/gtestutils.c +++ b/glib/gtestutils.c @@ -2327,16 +2327,14 @@ g_test_failed (void) /** * g_test_set_nonfatal_assertions: * - * Changes the behaviour of g_assert_cmpstr(), g_assert_cmpint(), - * g_assert_cmpuint(), g_assert_cmphex(), g_assert_cmpfloat(), - * g_assert_true(), g_assert_false(), g_assert_null(), g_assert_no_error(), - * g_assert_error(), g_test_assert_expected_messages() and the various - * g_test_trap_assert_*() macros to not abort to program, but instead + * Changes the behaviour of the various `g_assert_*()` macros, + * g_test_assert_expected_messages() and the various + * `g_test_trap_assert_*()` macros to not abort to program, but instead * call g_test_fail() and continue. (This also changes the behavior of * g_test_fail() so that it will not cause the test program to abort * after completing the failed test.) * - * Note that the g_assert_not_reached() and g_assert() are not + * Note that the g_assert_not_reached() and g_assert() macros are not * affected by this. * * This function can only be called after g_test_init().