diff --git a/ChangeLog b/ChangeLog index d1437630a..349f11c7d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2007-12-19 20:30:18 Tim Janik + + * glib/gtestutils.c: capture g_log() messages and send to gtester. + also, send assertion messages to gtester. + + * glib/gtester.c: add error messages to output log file. + force child poll loop to abort if waitpid() signaled child exit, + eventhough the child's report file descriptor wasn't closed. + 2007-12-19 Christian Persch * glib/gchecksum.c: (g_checksum_type_get_length), diff --git a/glib/gtester.c b/glib/gtester.c index 62337b724..ac91ef199 100644 --- a/glib/gtester.c +++ b/glib/gtester.c @@ -122,10 +122,15 @@ test_log_msg (GTestLogMsg *msg) { switch (msg->log_type) { + guint i; + gchar **strv; case G_TEST_LOG_NONE: break; case G_TEST_LOG_ERROR: - g_printerr ("%s\n", msg->strings[0]); + strv = g_strsplit (msg->strings[0], "\n", -1); + for (i = 0; strv[i]; i++) + test_log_printfe ("%s%s\n", sindent (log_indent), strv[i]); + g_strfreev (strv); break; case G_TEST_LOG_START_BINARY: test_log_printfe ("%s\n", sindent (log_indent), msg->strings[0]); @@ -219,6 +224,7 @@ child_report_cb (GIOChannel *source, (void) status; } while (length > 0); + // g_print ("LASTIOSTATE: first_read_eof=%d condition=%d\n", first_read_eof, condition); if (first_read_eof || (condition & (G_IO_ERR | G_IO_HUP))) { /* if there's no data to read and select() reports an error or hangup, @@ -270,6 +276,8 @@ launch_test_binary (const char *binary, const gchar *argv[99 + g_slist_length (subtest_args) + g_slist_length (subtest_paths)]; GPid pid = 0; gint report_pipe[2] = { -1, -1 }; + guint child_report_cb_id = 0; + gboolean loop_pending; gint i = 0; if (pipe (report_pipe) < 0) @@ -347,16 +355,27 @@ launch_test_binary (const char *binary, g_io_channel_set_flags (ioc_report, G_IO_FLAG_NONBLOCK, NULL); g_io_channel_set_encoding (ioc_report, NULL, NULL); g_io_channel_set_buffered (ioc_report, FALSE); - g_io_add_watch_full (ioc_report, G_PRIORITY_DEFAULT - 1, G_IO_IN | G_IO_ERR | G_IO_HUP, child_report_cb, tlb, NULL); + child_report_cb_id = g_io_add_watch_full (ioc_report, G_PRIORITY_DEFAULT - 1, G_IO_IN | G_IO_ERR | G_IO_HUP, child_report_cb, tlb, NULL); g_io_channel_unref (ioc_report); } g_child_watch_add_full (G_PRIORITY_DEFAULT + 1, pid, child_watch_cb, NULL, NULL); - while (subtest_running || /* FALSE once child exits */ - subtest_io_pending || /* FALSE once ioc_report closes */ - g_main_context_pending (NULL)) /* TRUE while idler, etc are running */ - g_main_context_iteration (NULL, TRUE); + loop_pending = g_main_context_pending (NULL); + while (subtest_running || /* FALSE once child exits */ + subtest_io_pending || /* FALSE once ioc_report closes */ + loop_pending) /* TRUE while idler, etc are running */ + { + // g_print ("LOOPSTATE: subtest_running=%d subtest_io_pending=%d\n", subtest_running, subtest_io_pending); + /* check for unexpected hangs that are not signalled on report_pipe */ + if (!subtest_running && /* child exited */ + subtest_io_pending && /* no EOF detected on report_pipe */ + !loop_pending) /* no IO events pending however */ + break; + g_main_context_iteration (NULL, TRUE); + loop_pending = g_main_context_pending (NULL); + } + g_source_remove (child_report_cb_id); close (report_pipe[0]); g_test_log_buffer_free (tlb); diff --git a/glib/gtestutils.c b/glib/gtestutils.c index c182cbc3d..af9695bd7 100644 --- a/glib/gtestutils.c +++ b/glib/gtestutils.c @@ -64,10 +64,15 @@ struct DestroyEntry }; /* --- prototypes --- */ -static void test_run_seed (const gchar *rseed); -static void test_trap_clear (void); -static guint8* g_test_log_dump (GTestLogMsg *msg, - guint *len); +static void test_run_seed (const gchar *rseed); +static void test_trap_clear (void); +static guint8* g_test_log_dump (GTestLogMsg *msg, + guint *len); +static void gtest_default_log_handler (const gchar *log_domain, + GLogLevelFlags log_level, + const gchar *message, + gpointer unused_data); + /* --- variables --- */ static int test_log_fd = -1; @@ -430,6 +435,7 @@ g_test_init (int *argc, test_run_seed (test_run_seedstr); /* report program start */ + g_log_set_default_handler (gtest_default_log_handler, NULL); g_test_log (G_TEST_LOG_START_BINARY, g_get_prgname(), test_run_seedstr, 0, NULL); } @@ -1097,6 +1103,45 @@ g_test_run_suite (GTestSuite *suite) return n_bad; } +static void +gtest_default_log_handler (const gchar *log_domain, + GLogLevelFlags log_level, + const gchar *message, + gpointer unused_data) +{ + const gchar *strv[16]; + gchar *msg; + guint i = 0; + if (log_domain) + { + strv[i++] = log_domain; + strv[i++] = "-"; + } + if (log_level & G_LOG_FLAG_FATAL) + strv[i++] = "FATAL-"; + if (log_level & G_LOG_FLAG_RECURSION) + strv[i++] = "RECURSIVE-"; + if (log_level & G_LOG_LEVEL_ERROR) + strv[i++] = "ERROR"; + if (log_level & G_LOG_LEVEL_CRITICAL) + strv[i++] = "CRITICAL"; + if (log_level & G_LOG_LEVEL_WARNING) + strv[i++] = "WARNING"; + if (log_level & G_LOG_LEVEL_MESSAGE) + strv[i++] = "MESSAGE"; + if (log_level & G_LOG_LEVEL_INFO) + strv[i++] = "INFO"; + if (log_level & G_LOG_LEVEL_DEBUG) + strv[i++] = "DEBUG"; + strv[i++] = ": "; + strv[i++] = message; + strv[i++] = NULL; + msg = g_strjoinv ("", (gchar**) strv); + g_test_log (G_TEST_LOG_ERROR, msg, NULL, 0, NULL); + g_log_default_handler (log_domain, log_level, message, unused_data); + g_free (msg); +} + void g_assertion_message (const char *domain, const char *file, @@ -1114,6 +1159,7 @@ g_assertion_message (const char *domain, func, func[0] ? ":" : "", " ", message, NULL); g_printerr ("**\n** %s\n", s); + g_test_log (G_TEST_LOG_ERROR, s, NULL, 0, NULL); g_free (s); abort(); } @@ -1363,6 +1409,7 @@ g_test_trap_fork (guint64 usec_timeout, GTestTrapFlags test_trap_flags) { #ifdef G_OS_UNIX + gboolean pass_on_forked_log = FALSE; int stdout_pipe[2] = { -1, -1 }; int stderr_pipe[2] = { -1, -1 }; int stdtst_pipe[2] = { -1, -1 }; @@ -1441,7 +1488,7 @@ g_test_trap_fork (guint64 usec_timeout, gint l, r = read (stdtst_pipe[0], buffer, sizeof (buffer)); if (r > 0 && test_log_fd > 0) do - l = write (test_log_fd, buffer, r); + l = write (pass_on_forked_log ? test_log_fd : -1, buffer, r); while (l < 0 && errno == EINTR); if (r == 0 || (r < 0 && errno != EINTR && errno != EAGAIN)) {