glib/glib/tests/protocol.c
Ignacio Casal Quinteiro 22b3a5ec00 Use win32 io channel on windows for the protocol test
We must use the platform specific method to create an IO channel
out of an fd. The test still does not work on Windows but
this is a step forward in the direction to make it work.
2019-01-24 21:24:44 +01:00

382 lines
11 KiB
C

/* 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.h> /* errno */
#include <glib.h>
#ifdef G_OS_UNIX
#include <unistd.h> /* pipe() */
#endif
#ifdef G_OS_WIN32
#include <io.h>
#include <fcntl.h>
#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))
{
int errsv = errno;
g_error ("error creating pipe: %s", g_strerror (errsv));
}
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);
#ifdef G_OS_WIN32
channel = g_io_channel_win32_new_fd (pipes[0]);
#else
channel = g_io_channel_unix_new (pipes[0]);
#endif
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))
{
int errsv = errno;
g_error ("error creating pipe: %s", g_strerror (errsv));
}
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);
#ifdef G_OS_WIN32
channel = g_io_channel_win32_new_fd (pipes[0]);
#else
channel = g_io_channel_unix_new (pipes[0]);
#endif
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: */