From 278ac0a45d2b677a0928b1c31b3e20a4c265ffb0 Mon Sep 17 00:00:00 2001 From: Christian Dywan Date: Thu, 10 Sep 2009 16:40:11 +0200 Subject: [PATCH] Bug 579050 Allow making selected critical and warning messages non-fatal Implement g_test_log_set_fatal_handler which is a function similar to g_log_set_default_handler but for use in unit tests where certain errors have to be ignored because it is not possible to fix or avoid them otherwise. A unit test is added. --- glib/glib.symbols | 3 +++ glib/gmessages.c | 47 +++++++++++++++++++++++++++++++++++++++++++++-- glib/gtestutils.c | 1 + glib/gtestutils.h | 21 +++++++++++++++++++++ glib/tests/testing.c | 27 +++++++++++++++++++++++++++ 5 files changed, 97 insertions(+), 2 deletions(-) diff --git a/glib/glib.symbols b/glib/glib.symbols index 0a96980..6e3a63b 100644 --- a/glib/glib.symbols +++ b/glib/glib.symbols @@ -1332,6 +1332,9 @@ g_thread_pool_set_sort_function #endif #if IN_HEADER(__G_TEST_UTILS_H__) +#if IN_FILE(__G_MESSAGES_C__) +g_test_log_set_fatal_handler +#endif #if IN_FILE(__G_TEST_UTILS_C__) g_assertion_message G_GNUC_NORETURN g_assertion_message_cmpnum G_GNUC_NORETURN diff --git a/glib/gmessages.c b/glib/gmessages.c index e080ad6..0f4bf42 100644 --- a/glib/gmessages.c +++ b/glib/gmessages.c @@ -86,6 +86,8 @@ static GPrivate *g_log_depth = NULL; static GLogLevelFlags g_log_msg_prefix = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_DEBUG; static GLogFunc default_log_func = g_log_default_handler; static gpointer default_log_data = NULL; +static GTestLogFatalFunc fatal_log_func = NULL; +static gpointer fatal_log_data; /* --- functions --- */ #ifdef G_OS_WIN32 @@ -346,6 +348,39 @@ g_log_set_default_handler (GLogFunc log_func, return old_log_func; } +/** + * g_test_log_set_fatal_handler: + * @log_func: the log handler function. + * @user_data: data passed to the log handler. + * + * Installs a non-error fatal log handler which can be + * used to decide whether log messages which are counted + * as fatal abort the program. + * + * The use case here is that you are running a test case + * that depends on particular libraries or circumstances + * and cannot prevent certain known critical or warning + * messages. So you install a handler that compares the + * domain and message to precisely not abort in such a case. + * + * Note that the handler is reset at the beginning of + * any test case, so you have to set it inside each test + * function which needs the special behavior. + * + * This handler has no effect on g_error messages. + * + * Since: 2.22 + **/ +void +g_test_log_set_fatal_handler (GTestLogFatalFunc log_func, + gpointer user_data) +{ + g_mutex_lock (g_messages_lock); + fatal_log_func = log_func; + fatal_log_data = user_data; + g_mutex_unlock (g_messages_lock); +} + void g_log_remove_handler (const gchar *log_domain, guint handler_id) @@ -456,6 +491,7 @@ g_logv (const gchar *log_domain, } } + gboolean masquerade_fatal = FALSE; if (test_level & G_LOG_FLAG_RECURSION) { /* we use a stack buffer of fixed size, since we're likely @@ -482,11 +518,18 @@ g_logv (const gchar *log_domain, log_func (log_domain, test_level, msg, data); + if ((test_level & G_LOG_FLAG_FATAL) + && !(test_level & G_LOG_LEVEL_ERROR)) + { + masquerade_fatal = fatal_log_func + && !fatal_log_func (log_domain, test_level, msg, data); + } + g_free (msg); } - if (test_level & G_LOG_FLAG_FATAL) - { + if ((test_level & G_LOG_FLAG_FATAL) && !masquerade_fatal) + { #ifdef G_OS_WIN32 gchar *locale_msg = g_locale_from_utf8 (fatal_msg_buf, -1, NULL, NULL, NULL); diff --git a/glib/gtestutils.c b/glib/gtestutils.c index 3f19fbc..fdb9494 100644 --- a/glib/gtestutils.c +++ b/glib/gtestutils.c @@ -1122,6 +1122,7 @@ test_case_run (GTestCase *tc) void *fixture; g_test_log (G_TEST_LOG_START_CASE, test_run_name, NULL, 0, NULL); test_run_forks = 0; + g_test_log_set_fatal_handler (NULL, NULL); g_timer_start (test_run_timer); fixture = tc->fixture_size ? g_malloc0 (tc->fixture_size) : tc->test_data; test_run_seed (test_run_seedstr); diff --git a/glib/gtestutils.h b/glib/gtestutils.h index 4c47458..ac1ed28 100644 --- a/glib/gtestutils.h +++ b/glib/gtestutils.h @@ -262,6 +262,27 @@ void g_test_log_buffer_push (GTestLogBuffer *tbuffer, GTestLogMsg* g_test_log_buffer_pop (GTestLogBuffer *tbuffer); void g_test_log_msg_free (GTestLogMsg *tmsg); +/** + * GTestLogFatalFunc: + * @log_domain: the log domain of the message + * @log_level: the log level of the message (including the fatal and recursion flags) + * @message: the message to process + * @user_data: user data, set in g_test_log_set_fatal_handler() + * + * Specifies the prototype of fatal log handler functions. + * + * Return value: %TRUE if the program should abort, %FALSE otherwise + * + * Since: 2.22 + */ +typedef gboolean (*GTestLogFatalFunc) (const gchar *log_domain, + GLogLevelFlags log_level, + const gchar *message, + gpointer user_data); +void +g_test_log_set_fatal_handler (GTestLogFatalFunc log_func, + gpointer user_data); + G_END_DECLS #endif /* __G_TEST_UTILS_H__ */ diff --git a/glib/tests/testing.c b/glib/tests/testing.c index cfbf8d4..ef8bcf9 100644 --- a/glib/tests/testing.c +++ b/glib/tests/testing.c @@ -191,6 +191,32 @@ test_random_conversions (void) g_free (str); } +static gboolean +fatal_handler (const gchar *log_domain, + GLogLevelFlags log_level, + const gchar *message, + gpointer user_data) +{ + return FALSE; +} + +static void +test_log_handler (void) +{ + g_test_log_set_fatal_handler (fatal_handler, NULL); + g_str_has_prefix (NULL, "file://"); + g_critical ("Test passing"); + + g_test_log_set_fatal_handler (NULL, NULL); + if (g_test_trap_fork (0, 0)) + g_error ("Test failing"); + g_test_trap_assert_failed (); + + if (g_test_trap_fork (0, 0)) + g_str_has_prefix (NULL, "file://"); + g_test_trap_assert_failed (); +} + int main (int argc, char *argv[]) @@ -209,6 +235,7 @@ main (int argc, g_test_add_func ("/forking/patterns", test_fork_patterns); if (g_test_slow()) g_test_add_func ("/forking/timeout", test_fork_timeout); + g_test_add_func ("/misc/log-handler", test_log_handler); return g_test_run(); } -- 2.7.4