test: Add infrastructure to parse valid raw message blobs

Signed-off-by: Simon McVittie <smcv@collabora.com>
(cherry picked from commit 7a2c13d21b)
[backport to 1.14.x: discard Meson build system updates]
(cherry picked from commit 7a8f3c2af9)
[backport to 1.12.x: resolve conflicts in build system; adjust signature
of test function for absence of 39ef65d0 in this branch]
This commit is contained in:
Simon McVittie 2022-09-30 14:00:08 +01:00
parent 51a5bbf907
commit 5d2b764d1f
4 changed files with 185 additions and 0 deletions

View file

@ -552,6 +552,8 @@ static_data = \
data/valid-messages/dict.message \
data/valid-messages/emptiness.message \
data/valid-messages/lots-of-arguments.message \
data/valid-messages/minimal.message-raw \
data/valid-messages/minimal.message-raw.hex \
data/valid-messages/no-padding.message \
data/valid-messages/opposite-endian.message \
data/valid-messages/recursive-types.message \

Binary file not shown.

View file

@ -0,0 +1,25 @@
# Copyright 2022 Collabora Ltd.
# SPDX-License-Identifier: MIT
#
# To output as binary:
# sed -e 's/#.*//' test/data/valid-messages/minimal.message-raw.hex |
# xxd -p -r - test/data/valid-messages/minimal.message-raw
#
# This is a minimal valid message.
# Offset % 0x10:
# 0001 0203 0405 0607 0809 0a0b 0c0d 0e0f
6c # little-endian
02 # method call reply
00 # no flags
01 # major protocol version 1
0000 0000 # message body is 0 bytes
0200 0000 # serial number 2
0800 0000 # header is an array of 8 bytes of struct (yv)
05 # in reply to
01 # signature is 1 byte
7500 # "u" \0
0100 0000 # in reply to serial number 1
#sha1 06942854add9c4346a8b1c76a2b02e2e73abe72a

View file

@ -28,6 +28,7 @@
#include <string.h>
#include <glib.h>
#include <glib/gstdio.h>
#include <dbus/dbus.h>
#include "dbus/dbus-internals.h"
@ -179,6 +180,150 @@ out:
return !g_test_failed ();
}
static void iterate_fully (DBusMessageIter *iter,
int n_elements);
/* Iterate over @iter. If n_elements >= 0, then @iter is
* expected to yield exactly @n_elements elements. */
static void
iterate_fully (DBusMessageIter *iter,
int n_elements)
{
int i = 0;
while (TRUE)
{
int arg_type = dbus_message_iter_get_arg_type (iter);
dbus_bool_t should_have_next;
dbus_bool_t had_next;
if (arg_type == DBUS_TYPE_INVALID)
return; /* end of iteration */
if (dbus_type_is_container (arg_type))
{
DBusMessageIter sub = DBUS_MESSAGE_ITER_INIT_CLOSED;
int n_contained = -1;
switch (arg_type)
{
case DBUS_TYPE_ARRAY:
/* This is only allowed for arrays */
n_contained = dbus_message_iter_get_element_count (iter);
g_assert_cmpint (n_contained, >=, 0);
break;
case DBUS_TYPE_VARIANT:
n_contained = 1;
break;
case DBUS_TYPE_STRUCT:
break;
case DBUS_TYPE_DICT_ENTRY:
n_contained = 2;
break;
default:
g_assert_not_reached ();
}
dbus_message_iter_recurse (iter, &sub);
iterate_fully (&sub, n_contained);
}
else
{
DBusBasicValue value;
dbus_message_iter_get_basic (iter, &value);
if (arg_type == DBUS_TYPE_UNIX_FD && value.fd >= 0)
{
GError *error = NULL;
g_close (value.fd, &error);
g_assert_no_error (error);
}
}
should_have_next = dbus_message_iter_has_next (iter);
had_next = dbus_message_iter_next (iter);
g_assert_cmpint (had_next, ==, should_have_next);
g_assert_cmpint (had_next, ==,
(dbus_message_iter_get_arg_type (iter) != DBUS_TYPE_INVALID));
i += 1;
}
if (n_elements >= 0)
g_assert_cmpuint (n_elements, ==, i);
}
/* Return TRUE if the right thing happens, but the right thing might include
* OOM. */
static dbus_bool_t
test_valid_message_blobs (void *message_name)
{
gchar *path = NULL;
gchar *contents = NULL;
gsize len = 0;
DBusMessage *m = NULL;
DBusMessageIter iter = DBUS_MESSAGE_ITER_INIT_CLOSED;
GError *error = NULL;
DBusError e = DBUS_ERROR_INIT;
dbus_bool_t ok = TRUE;
gchar *filename = NULL;
filename = g_strdup_printf ("%s.message-raw", (const char *) message_name);
path = g_test_build_filename (G_TEST_DIST, "data", "valid-messages",
filename, NULL);
g_file_get_contents (path, &contents, &len, &error);
g_assert_no_error (error);
g_assert_cmpuint (len, <, (gsize) INT_MAX);
m = dbus_message_demarshal (contents, (int) len, &e);
if (m == NULL)
{
if (dbus_error_has_name (&e, DBUS_ERROR_NO_MEMORY))
{
g_test_message ("Out of memory (not a problem)");
goto out;
}
/* TODO: Validity checking sometimes returns InvalidArgs for OOM */
if (dbus_error_has_name (&e, DBUS_ERROR_INVALID_ARGS) &&
strstr (e.message, "Out of memory") != NULL)
{
g_test_message ("Out of memory (not a problem)");
goto out;
}
g_test_message ("Parsing %s reported unexpected error %s: %s",
path, e.name, e.message);
g_test_fail ();
ok = FALSE;
goto out;
}
g_test_message ("Successfully parsed %s", path);
test_assert_no_error (&e);
if (dbus_message_iter_init (m, &iter))
g_assert_cmpint (dbus_message_iter_get_arg_type (&iter), !=, DBUS_TYPE_INVALID);
else
g_assert_cmpint (dbus_message_iter_get_arg_type (&iter), ==, DBUS_TYPE_INVALID);
iterate_fully (&iter, -1);
out:
dbus_clear_message (&m);
dbus_error_free (&e);
g_free (path);
g_free (contents);
g_free (filename);
return ok;
}
/* Return TRUE if the right thing happens, but the right thing might include
* OOM. */
static dbus_bool_t
@ -365,6 +510,11 @@ add_oom_test (const gchar *name,
g_queue_push_tail (test_cases_to_free, test_case);
}
static const char *valid_messages[] =
{
"minimal",
};
static const char *invalid_messages[] =
{
"boolean-has-no-value",
@ -391,6 +541,14 @@ main (int argc,
add_oom_test ("/message/fd", test_fd, NULL);
add_oom_test ("/message/zero-iter", test_zero_iter, NULL);
for (i = 0; i < G_N_ELEMENTS (valid_messages); i++)
{
gchar *path = g_strdup_printf ("/message/valid/%s", valid_messages[i]);
add_oom_test (path, test_valid_message_blobs, valid_messages[i]);
g_free (path);
}
for (i = 0; i < G_N_ELEMENTS (invalid_messages); i++)
{
gchar *path = g_strdup_printf ("/message/invalid/%s", invalid_messages[i]);