Bug 579050 Allow making selected critical and warning messages non-fatal
authorChristian Dywan <christian@lanedo.com>
Thu, 10 Sep 2009 14:40:11 +0000 (16:40 +0200)
committerChristian Dywan <christian@twotoasts.de>
Thu, 10 Sep 2009 14:45:49 +0000 (16:45 +0200)
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
glib/gmessages.c
glib/gtestutils.c
glib/gtestutils.h
glib/tests/testing.c

index 0a96980..6e3a63b 100644 (file)
@@ -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
index e080ad6..0f4bf42 100644 (file)
@@ -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);
              
index 3f19fbc..fdb9494 100644 (file)
@@ -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);
index 4c47458..ac1ed28 100644 (file)
@@ -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__ */
index cfbf8d4..ef8bcf9 100644 (file)
@@ -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();
 }