mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-24 14:36:13 +01:00
Implemented test log serialization.
* glib/gtestframework.h: added g_test_log*() API. * glib/gtestframework.c: implement test log serialization. svn path=/trunk/; revision=5886
This commit is contained in:
parent
e3c66f03e0
commit
25053dc518
@ -49,6 +49,8 @@ struct GTestSuite
|
||||
/* --- 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;
|
||||
@ -77,19 +79,8 @@ static char *test_trap_last_stderr = NULL;
|
||||
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)
|
||||
{
|
||||
@ -104,14 +95,47 @@ test_log_bit (GTestLogBit 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)
|
||||
{
|
||||
@ -132,29 +156,16 @@ g_test_log (GTestLogBit 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)
|
||||
{
|
||||
@ -1063,3 +1074,172 @@ g_test_trap_assertions (const char *domain,
|
||||
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);
|
||||
}
|
||||
|
@ -167,6 +167,38 @@ void g_test_add_vtable (const char *testpath,
|
||||
void (*data_test) (void),
|
||||
void (*data_teardown) (void));
|
||||
|
||||
/* internal logging API */
|
||||
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
|
||||
} GTestLogType;
|
||||
|
||||
typedef struct {
|
||||
GTestLogType log_type;
|
||||
guint n_strings;
|
||||
gchar **strings; // NULL terminated
|
||||
guint n_nums;
|
||||
long double *nums;
|
||||
} GTestLogMsg;
|
||||
typedef struct {
|
||||
/*< private >*/
|
||||
GString *data;
|
||||
GSList *msgs;
|
||||
} GTestLogBuffer;
|
||||
|
||||
GTestLogBuffer* g_test_log_buffer_new (void);
|
||||
void g_test_log_buffer_free (GTestLogBuffer *tbuffer);
|
||||
void g_test_log_buffer_push (GTestLogBuffer *tbuffer,
|
||||
guint n_bytes,
|
||||
const guint8 *bytes);
|
||||
GTestLogMsg* g_test_log_buffer_pop (GTestLogBuffer *tbuffer);
|
||||
void g_test_log_msg_free (GTestLogMsg *tmsg);
|
||||
|
||||
G_END_DECLS;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user