/* This file is part of GLib * * Copyright (C) 2010 Sven Herzberg * * This work is provided "as is"; redistribution and modification * in whole or in part, in any medium, physical or electronic is * permitted without restriction. * * This work is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * In no event shall the authors or contributors be liable for any * direct, indirect, incidental, special, exemplary, or consequential * damages (including, but not limited to, procurement of substitute * goods or services; loss of use, data, or profits; or business * interruption) however caused and on any theory of liability, whether * in contract, strict liability, or tort (including negligence or * otherwise) arising in any way out of the use of this software, even * if advised of the possibility of such damage. */ #include /* errno */ #include #ifdef G_OS_UNIX #include /* pipe() */ #endif #ifdef G_OS_WIN32 #include #include #define pipe(fds) _pipe(fds, 4096, _O_BINARY) #endif static const char *argv0; static void debug (void) { if (g_test_subprocess ()) g_debug ("this is a regular g_debug() from the test suite"); } static void info (void) { if (g_test_subprocess ()) g_info ("this is a regular g_info from the test suite"); } static void message (void) { if (g_test_subprocess ()) g_message ("this is a regular g_message() from the test suite"); } static void warning (void) { if (g_test_subprocess ()) g_warning ("this is a regular g_warning() from the test suite"); } static void critical (void) { if (g_test_subprocess ()) g_critical ("this is a regular g_critical() from the test suite"); } static void error (void) { if (g_test_subprocess ()) g_error ("this is a regular g_error() from the test suite"); } static void gtest_message (void) { if (g_test_subprocess ()) g_test_message ("this is a regular g_test_message() from the test suite"); } static gboolean test_message_cb1 (GIOChannel * channel, GIOCondition condition, gpointer user_data) { GIOStatus status; guchar buf[512]; gsize read_bytes = 0; g_assert_cmpuint (condition, ==, G_IO_IN); for (status = g_io_channel_read_chars (channel, (gchar*)buf, sizeof (buf), &read_bytes, NULL); status == G_IO_STATUS_NORMAL; status = g_io_channel_read_chars (channel, (gchar*)buf, sizeof (buf), &read_bytes, NULL)) { g_test_log_buffer_push (user_data, read_bytes, buf); } g_assert_cmpuint (status, ==, G_IO_STATUS_AGAIN); return TRUE; } static void test_message_cb2 (GPid pid, gint status, gpointer user_data) { g_spawn_close_pid (pid); g_main_loop_quit (user_data); } static void test_message (void) { gchar* argv[] = { (gchar*)argv0, NULL, "--GTestSubprocess", "-p", "/glib/testing/protocol/debug", "-p", "/glib/testing/protocol/message", "-p", "/glib/testing/protocol/gtest-message", NULL }; GTestLogBuffer* tlb; GTestLogMsg * msg; GIOChannel * channel; GMainLoop * loop; GError * error = NULL; gulong child_source; gulong io_source; GPid pid = 0; int pipes[2]; int passed = 0; int messages = 0; const char * line_term; int line_term_len; if (0 > pipe (pipes)) { g_error ("error creating pipe: %s", g_strerror (errno)); } argv[1] = g_strdup_printf ("--GTestLogFD=%u", pipes[1]); if (!g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_LEAVE_DESCRIPTORS_OPEN | G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, &pid, &error)) { g_error ("error spawning the test: %s", error->message); } tlb = g_test_log_buffer_new (); loop = g_main_loop_new (NULL, FALSE); channel = g_io_channel_unix_new (pipes[0]); g_io_channel_set_close_on_unref (channel, TRUE); g_io_channel_set_encoding (channel, NULL, NULL); g_io_channel_set_buffered (channel, FALSE); g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, NULL); g_assert (g_io_channel_get_line_term (channel, NULL) == NULL); g_io_channel_set_line_term (channel, "\n", 1); line_term = g_io_channel_get_line_term (channel, &line_term_len); g_assert_cmpint (*line_term, ==, '\n'); g_assert_cmpint (line_term_len, ==, 1); g_assert (g_io_channel_get_close_on_unref (channel)); g_assert (g_io_channel_get_encoding (channel) == NULL); g_assert (!g_io_channel_get_buffered (channel)); io_source = g_io_add_watch (channel, G_IO_IN, test_message_cb1, tlb); child_source = g_child_watch_add (pid, test_message_cb2, loop); g_main_loop_run (loop); test_message_cb1 (channel, G_IO_IN, tlb); g_test_expect_message ("GLib", G_LOG_LEVEL_CRITICAL, "Source ID*"); g_assert (!g_source_remove (child_source)); g_test_assert_expected_messages (); g_assert (g_source_remove (io_source)); g_io_channel_unref (channel); for (msg = g_test_log_buffer_pop (tlb); msg; msg = g_test_log_buffer_pop (tlb)) { switch (msg->log_type) { case G_TEST_LOG_START_BINARY: case G_TEST_LOG_START_CASE: case G_TEST_LOG_START_SUITE: case G_TEST_LOG_STOP_SUITE: /* ignore */ break; case G_TEST_LOG_STOP_CASE: passed++; break; case G_TEST_LOG_MESSAGE: { gchar const* known_messages[] = { "this is a regular g_test_message() from the test suite", "GLib-MESSAGE: this is a regular g_message() from the test suite", "GLib-DEBUG: this is a regular g_debug() from the test suite" }; g_assert_cmpint (messages, <, G_N_ELEMENTS (known_messages)); g_assert_cmpstr (msg->strings[0], ==, known_messages[messages]); messages++; } break; case G_TEST_LOG_ERROR: g_assert_not_reached (); break; default: g_error ("unexpected log message type: %s", g_test_log_type_name (msg->log_type)); } g_test_log_msg_free (msg); } g_assert_cmpint (passed, ==, 3); g_assert_cmpint (messages, ==, 3); g_free (argv[1]); g_main_loop_unref (loop); g_test_log_buffer_free (tlb); } static void test_error (void) { gchar* tests[] = { "/glib/testing/protocol/warning", "/glib/testing/protocol/critical", "/glib/testing/protocol/error" }; gint i; int messages = 0; for (i = 0; i < G_N_ELEMENTS (tests); i++) { gchar* argv[] = { (gchar*)argv0, NULL, "--GTestSubprocess", "-p", tests[i], NULL }; GTestLogBuffer* tlb; GTestLogMsg * msg; GIOChannel * channel; GMainLoop * loop; GError * error = NULL; gulong child_source; gulong io_source; GPid pid = 0; int pipes[2]; if (0 > pipe (pipes)) { g_error ("error creating pipe: %s", g_strerror (errno)); } argv[1] = g_strdup_printf ("--GTestLogFD=%u", pipes[1]); if (!g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_LEAVE_DESCRIPTORS_OPEN | G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, &pid, &error)) { g_error ("error spawning the test: %s", error->message); } tlb = g_test_log_buffer_new (); loop = g_main_loop_new (NULL, FALSE); channel = g_io_channel_unix_new (pipes[0]); g_io_channel_set_close_on_unref (channel, TRUE); g_io_channel_set_encoding (channel, NULL, NULL); g_io_channel_set_buffered (channel, FALSE); g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, NULL); io_source = g_io_add_watch (channel, G_IO_IN, test_message_cb1, tlb); child_source = g_child_watch_add (pid, test_message_cb2, loop); g_main_loop_run (loop); test_message_cb1 (channel, G_IO_IN, tlb); g_test_expect_message ("GLib", G_LOG_LEVEL_CRITICAL, "Source ID*"); g_assert (!g_source_remove (child_source)); g_test_assert_expected_messages (); g_assert (g_source_remove (io_source)); g_io_channel_unref (channel); for (msg = g_test_log_buffer_pop (tlb); msg; msg = g_test_log_buffer_pop (tlb)) { switch (msg->log_type) { case G_TEST_LOG_START_BINARY: case G_TEST_LOG_START_CASE: case G_TEST_LOG_START_SUITE: case G_TEST_LOG_STOP_SUITE: /* ignore */ break; case G_TEST_LOG_STOP_CASE: case G_TEST_LOG_MESSAGE: g_assert_not_reached (); break; case G_TEST_LOG_ERROR: { gchar const* known_messages[] = { "GLib-FATAL-WARNING: this is a regular g_warning() from the test suite", "GLib-FATAL-CRITICAL: this is a regular g_critical() from the test suite", "GLib-FATAL-ERROR: this is a regular g_error() from the test suite" }; g_assert_cmpint (messages, <, G_N_ELEMENTS (known_messages)); g_assert_cmpstr (msg->strings[0], ==, known_messages[messages]); messages++; } break; default: g_error ("unexpected log message type: %s", g_test_log_type_name (msg->log_type)); } g_test_log_msg_free (msg); } g_free (argv[1]); g_main_loop_unref (loop); g_test_log_buffer_free (tlb); } g_assert_cmpint (messages, ==, 3); } int main (int argc, char**argv) { argv0 = argv[0]; g_test_init (&argc, &argv, NULL); /* we use ourself as the testcase, these are the ones we need internally */ g_test_add_func ("/glib/testing/protocol/debug", debug); g_test_add_func ("/glib/testing/protocol/info", info); g_test_add_func ("/glib/testing/protocol/message", message); g_test_add_func ("/glib/testing/protocol/warning", warning); g_test_add_func ("/glib/testing/protocol/critical", critical); g_test_add_func ("/glib/testing/protocol/error", error); g_test_add_func ("/glib/testing/protocol/gtest-message", gtest_message); /* these are the real tests */ g_test_add_func ("/glib/testing/protocol/test-message", test_message); g_test_add_func ("/glib/testing/protocol/test-error", test_error); return g_test_run (); } /* vim:set et sw=2 cino=t0,f0,(0,{s,>2s,n-1s,^-1s,e2s: */