/* --- 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);
/* --- variables --- */
static int test_stdmsg = 1;
static gboolean test_debug_log = FALSE;
/* --- functions --- */
-typedef enum {
- G_TEST_LOG_NONE,
- G_TEST_LOG_ERROR, // s:msg
- G_TEST_LOG_START_BINARY, // s:binaryname s:seed
- G_TEST_LOG_LIST_CASE, // s:testpath
- G_TEST_LOG_START_CASE, // s:testpath
- G_TEST_LOG_STOP_CASE, // d:status d:nforks d:elapsed
- G_TEST_LOG_MIN_RESULT, // s:blurb d:result
- G_TEST_LOG_MAX_RESULT, // s:blurb d:result
-} GTestLogBit;
-
static const char*
-test_log_bit (GTestLogBit lbit)
+test_log_bit (GTestLogType lbit)
{
switch (lbit)
{
}
static void
-g_test_log (GTestLogBit lbit,
+g_test_log_send (guint n_bytes,
+ const guint8 *buffer)
+{
+ if (test_debug_log)
+ {
+ GTestLogBuffer *lbuffer = g_test_log_buffer_new();
+ GTestLogMsg *msg;
+ guint ui;
+ g_test_log_buffer_push (lbuffer, n_bytes, buffer);
+ msg = g_test_log_buffer_pop (lbuffer);
+ g_assert (msg != NULL); // FIXME: should be g_awrn_if_fail
+ g_assert (lbuffer->data->len == 0); // FIXME: should be g_awrn_if_fail
+ g_test_log_buffer_free (lbuffer);
+ /* print message */
+ g_printerr ("{*LOG(%s)", test_log_bit (msg->log_type));
+ for (ui = 0; ui < msg->n_strings; ui++)
+ g_printerr (":{%s}", msg->strings[ui]);
+ if (msg->n_nums)
+ {
+ g_printerr (":(");
+ for (ui = 0; ui < msg->n_nums; ui++)
+ g_printerr ("%s%.16Lg", ui ? ";" : "", msg->nums[ui]);
+ g_printerr (")");
+ }
+ g_printerr (":LOG*}\n");
+ g_test_log_msg_free (msg);
+ }
+}
+
+static void
+g_test_log (GTestLogType lbit,
const gchar *string1,
const gchar *string2,
guint n_args,
long double *largs)
{
gboolean fail = lbit == G_TEST_LOG_STOP_CASE && largs[0] != 0;
- const char *bit = test_log_bit (lbit);
+ GTestLogMsg msg;
+ gchar *astrings[3] = { NULL, NULL, NULL };
+ guint8 *dbuffer;
+ guint32 dbufferlen;
switch (lbit)
{
default: ;
}
- if (test_debug_log)
- g_printerr ("{*LOG(%s)", bit);
- if (test_debug_log && string1)
- g_printerr (":{%s}", string1);
- if (test_debug_log && string2)
- g_printerr (":{%s}", string2);
- if (n_args)
- {
- guint i;
- if (test_debug_log)
- g_printerr (":(");
- for (i = 0; i < n_args; i++)
- {
- if (i && test_debug_log)
- g_printerr (";");
- if (test_debug_log)
- g_printerr ("%.16Lg", largs[i]);
- }
- if (test_debug_log)
- g_printerr (")");
- }
- if (test_debug_log)
- g_printerr (":LOG*}\n");
+ msg.log_type = lbit;
+ msg.n_strings = (string1 != NULL) + (string1 && string2);
+ msg.strings = astrings;
+ astrings[0] = (gchar*) string1;
+ astrings[1] = astrings[0] ? (gchar*) string2 : NULL;
+ msg.n_nums = n_args;
+ msg.nums = largs;
+ dbuffer = g_test_log_dump (&msg, &dbufferlen);
+ g_test_log_send (dbufferlen, dbuffer);
+ g_free (dbuffer);
switch (lbit)
{
g_free (msg);
}
}
+
+static void
+gstring_overwrite_int (GString *gstring,
+ guint pos,
+ guint32 vuint)
+{
+ vuint = g_htonl (vuint);
+ g_string_overwrite_len (gstring, pos, (const gchar*) &vuint, 4);
+}
+
+static void
+gstring_append_int (GString *gstring,
+ guint32 vuint)
+{
+ vuint = g_htonl (vuint);
+ g_string_append_len (gstring, (const gchar*) &vuint, 4);
+}
+
+static void
+gstring_append_double (GString *gstring,
+ double vdouble)
+{
+ union { double vdouble; guint64 vuint64; } u;
+ u.vdouble = vdouble;
+ u.vuint64 = GUINT64_TO_BE (u.vuint64);
+ g_string_append_len (gstring, (const gchar*) &u.vuint64, 8);
+}
+
+static guint8*
+g_test_log_dump (GTestLogMsg *msg,
+ guint *len)
+{
+ GString *gstring = g_string_sized_new (1024);
+ guint ui;
+ gstring_append_int (gstring, 0); /* message length */
+ gstring_append_int (gstring, msg->log_type);
+ gstring_append_int (gstring, msg->n_strings);
+ gstring_append_int (gstring, msg->n_nums);
+ gstring_append_int (gstring, 0); /* reserved */
+ for (ui = 0; ui < msg->n_strings; ui++)
+ {
+ guint l = strlen (msg->strings[ui]);
+ gstring_append_int (gstring, l);
+ g_string_append_len (gstring, msg->strings[ui], l);
+ }
+ for (ui = 0; ui < msg->n_nums; ui++)
+ gstring_append_double (gstring, msg->nums[ui]);
+ *len = gstring->len;
+ gstring_overwrite_int (gstring, 0, *len); /* message length */
+ return (guint8*) g_string_free (gstring, FALSE);
+}
+
+static inline long double
+net_double (const gchar **ipointer)
+{
+ union { guint64 vuint64; double vdouble; } u;
+ guint64 aligned_int64;
+ memcpy (&aligned_int64, *ipointer, 8);
+ *ipointer += 8;
+ u.vuint64 = GUINT64_FROM_BE (aligned_int64);
+ return u.vdouble;
+}
+
+static inline guint32
+net_int (const gchar **ipointer)
+{
+ guint32 aligned_int;
+ memcpy (&aligned_int, *ipointer, 4);
+ *ipointer += 4;
+ return g_ntohl (aligned_int);
+}
+
+static gboolean
+g_test_log_extract (GTestLogBuffer *tbuffer)
+{
+ const gchar *p = tbuffer->data->str;
+ GTestLogMsg msg;
+ guint mlength;
+ if (tbuffer->data->len < 4 * 5)
+ return FALSE;
+ mlength = net_int (&p);
+ if (tbuffer->data->len < mlength)
+ return FALSE;
+ msg.log_type = net_int (&p);
+ msg.n_strings = net_int (&p);
+ msg.n_nums = net_int (&p);
+ if (net_int (&p) == 0)
+ {
+ guint ui;
+ msg.strings = g_new0 (gchar*, msg.n_strings + 1);
+ msg.nums = g_new0 (long double, msg.n_nums);
+ for (ui = 0; ui < msg.n_strings; ui++)
+ {
+ guint sl = net_int (&p);
+ msg.strings[ui] = g_strndup (p, sl);
+ p += sl;
+ }
+ for (ui = 0; ui < msg.n_nums; ui++)
+ msg.nums[ui] = net_double (&p);
+ if (p <= tbuffer->data->str + mlength)
+ {
+ g_string_erase (tbuffer->data, 0, mlength);
+ tbuffer->msgs = g_slist_prepend (tbuffer->msgs, g_memdup (&msg, sizeof (msg)));
+ return TRUE;
+ }
+ }
+ g_free (msg.nums);
+ g_strfreev (msg.strings);
+ g_error ("corrupt log stream from test program");
+ return FALSE;
+}
+
+GTestLogBuffer*
+g_test_log_buffer_new (void)
+{
+ GTestLogBuffer *tb = g_new0 (GTestLogBuffer, 1);
+ tb->data = g_string_sized_new (1024);
+ return tb;
+}
+
+void
+g_test_log_buffer_free (GTestLogBuffer *tbuffer)
+{
+ g_return_if_fail (tbuffer != NULL);
+ while (tbuffer->msgs)
+ g_test_log_msg_free (g_test_log_buffer_pop (tbuffer));
+ g_string_free (tbuffer->data, TRUE);
+ g_free (tbuffer);
+}
+
+void
+g_test_log_buffer_push (GTestLogBuffer *tbuffer,
+ guint n_bytes,
+ const guint8 *bytes)
+{
+ g_return_if_fail (tbuffer != NULL);
+ if (n_bytes)
+ {
+ gboolean more_messages;
+ g_return_if_fail (bytes != NULL);
+ g_string_append_len (tbuffer->data, (const gchar*) bytes, n_bytes);
+ do
+ more_messages = g_test_log_extract (tbuffer);
+ while (more_messages);
+ }
+}
+
+GTestLogMsg*
+g_test_log_buffer_pop (GTestLogBuffer *tbuffer)
+{
+ GTestLogMsg *msg = NULL;
+ g_return_val_if_fail (tbuffer != NULL, NULL);
+ if (tbuffer->msgs)
+ {
+ GSList *slist = g_slist_last (tbuffer->msgs);
+ msg = slist->data;
+ tbuffer->msgs = g_slist_delete_link (tbuffer->msgs, slist);
+ }
+ return msg;
+}
+
+void
+g_test_log_msg_free (GTestLogMsg *tmsg)
+{
+ g_return_if_fail (tmsg != NULL);
+ g_strfreev (tmsg->strings);
+ g_free (tmsg->nums);
+ g_free (tmsg);
+}