From 7bf62e31a3c820852271768fafc04ba95c31a19f Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Mon, 17 Jan 2005 03:53:40 +0000 Subject: 2005-01-16 Havoc Pennington This is about it on what can be disabled/deleted from libdbus easily, back below 150K anyhow. Deeper cuts are more work than just turning the code off as I've done here. * dbus/dbus-marshal-basic.c (_dbus_pack_int32): we don't need the signed int convenience funcs * dbus/dbus-internals.c (_dbus_verbose_real): omit when not in verbose mode * dbus/dbus-string-util.c, dbus/dbus-string.c: more breaking things out of libdbus * dbus/dbus-sysdeps.c, dbus/dbus-sysdeps-util.c: same * dbus/dbus-hash.c: purge the TWO_STRINGS crap (well, make it tests-enabled-only, though it should probably be deleted) * dbus/dbus-message-util.c: same stuff * dbus/dbus-auth-util.c: same stuff --- dbus/dbus-message-util.c | 1309 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1309 insertions(+) create mode 100644 dbus/dbus-message-util.c (limited to 'dbus/dbus-message-util.c') diff --git a/dbus/dbus-message-util.c b/dbus/dbus-message-util.c new file mode 100644 index 00000000..47370702 --- /dev/null +++ b/dbus/dbus-message-util.c @@ -0,0 +1,1309 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-message-util.c Would be in dbus-message.c, but only used by bus/tests + * + * Copyright (C) 2002, 2003, 2004, 2005 Red Hat Inc. + * Copyright (C) 2002, 2003 CodeFactory AB + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "dbus-internals.h" +#include "dbus-test.h" +#include "dbus-message-private.h" +#include "dbus-marshal-recursive.h" +#include "dbus-string.h" + +/** + * @addtogroup DBusMessage + * @{ + */ + +#ifdef DBUS_BUILD_TESTS +/** + * Reads arguments from a message iterator given a variable argument + * list. Only arguments of basic type and arrays of fixed-length + * basic type may be read with this function. See + * dbus_message_get_args() for more details. + * + * @todo this is static for now because there's no corresponding + * iter_append_args() and I'm not sure we need this function to be + * public since dbus_message_get_args() is what you usually want + * + * @param iter the message iterator + * @param error error to be filled in on failure + * @param first_arg_type the first argument type + * @param ... location for first argument value, then list of type-location pairs + * @returns #FALSE if the error was set + */ +static dbus_bool_t +dbus_message_iter_get_args (DBusMessageIter *iter, + DBusError *error, + int first_arg_type, + ...) +{ + dbus_bool_t retval; + va_list var_args; + + _dbus_return_val_if_fail (iter != NULL, FALSE); + _dbus_return_val_if_error_is_set (error, FALSE); + + va_start (var_args, first_arg_type); + retval = _dbus_message_iter_get_args_valist (iter, error, first_arg_type, var_args); + va_end (var_args); + + return retval; +} +#endif /* DBUS_BUILD_TESTS */ + +/** @} */ + +#ifdef DBUS_BUILD_TESTS +#include "dbus-test.h" +#include +#include + +static dbus_bool_t +check_have_valid_message (DBusMessageLoader *loader) +{ + DBusMessage *message; + dbus_bool_t retval; + + message = NULL; + retval = FALSE; + + if (!_dbus_message_loader_queue_messages (loader)) + _dbus_assert_not_reached ("no memory to queue messages"); + + if (_dbus_message_loader_get_is_corrupted (loader)) + { + _dbus_warn ("loader corrupted on message that was expected to be valid\n"); + goto failed; + } + + message = _dbus_message_loader_pop_message (loader); + if (message == NULL) + { + _dbus_warn ("didn't load message that was expected to be valid (message not popped)\n"); + goto failed; + } + + if (_dbus_string_get_length (&loader->data) > 0) + { + _dbus_warn ("had leftover bytes from expected-to-be-valid single message\n"); + goto failed; + } + +#if 0 + /* FIXME */ + /* Verify that we're able to properly deal with the message. + * For example, this would detect improper handling of messages + * in nonstandard byte order. + */ + if (!check_message_handling (message)) + goto failed; +#endif + + retval = TRUE; + + failed: + if (message) + dbus_message_unref (message); + + return retval; +} + +static dbus_bool_t +check_invalid_message (DBusMessageLoader *loader) +{ + dbus_bool_t retval; + + retval = FALSE; + + if (!_dbus_message_loader_queue_messages (loader)) + _dbus_assert_not_reached ("no memory to queue messages"); + + if (!_dbus_message_loader_get_is_corrupted (loader)) + { + _dbus_warn ("loader not corrupted on message that was expected to be invalid\n"); + goto failed; + } + + retval = TRUE; + + failed: + return retval; +} + +static dbus_bool_t +check_incomplete_message (DBusMessageLoader *loader) +{ + DBusMessage *message; + dbus_bool_t retval; + + message = NULL; + retval = FALSE; + + if (!_dbus_message_loader_queue_messages (loader)) + _dbus_assert_not_reached ("no memory to queue messages"); + + if (_dbus_message_loader_get_is_corrupted (loader)) + { + _dbus_warn ("loader corrupted on message that was expected to be valid (but incomplete)\n"); + goto failed; + } + + message = _dbus_message_loader_pop_message (loader); + if (message != NULL) + { + _dbus_warn ("loaded message that was expected to be incomplete\n"); + goto failed; + } + + retval = TRUE; + + failed: + if (message) + dbus_message_unref (message); + return retval; +} + +static dbus_bool_t +check_loader_results (DBusMessageLoader *loader, + DBusMessageValidity validity) +{ + if (!_dbus_message_loader_queue_messages (loader)) + _dbus_assert_not_reached ("no memory to queue messages"); + + switch (validity) + { + case _DBUS_MESSAGE_VALID: + return check_have_valid_message (loader); + case _DBUS_MESSAGE_INVALID: + return check_invalid_message (loader); + case _DBUS_MESSAGE_INCOMPLETE: + return check_incomplete_message (loader); + case _DBUS_MESSAGE_UNKNOWN: + return TRUE; + } + + _dbus_assert_not_reached ("bad DBusMessageValidity"); + return FALSE; +} + + +/** + * Loads the message in the given message file. + * + * @param filename filename to load + * @param is_raw if #TRUE load as binary data, if #FALSE as message builder language + * @param data string to load message into + * @returns #TRUE if the message was loaded + */ +dbus_bool_t +dbus_internal_do_not_use_load_message_file (const DBusString *filename, + dbus_bool_t is_raw, + DBusString *data) +{ + dbus_bool_t retval; + + retval = FALSE; + + if (is_raw) + { + DBusError error; + + _dbus_verbose ("Loading raw %s\n", _dbus_string_get_const_data (filename)); + dbus_error_init (&error); + if (!_dbus_file_get_contents (data, filename, &error)) + { + _dbus_warn ("Could not load message file %s: %s\n", + _dbus_string_get_const_data (filename), + error.message); + dbus_error_free (&error); + goto failed; + } + } + else + { + if (FALSE) /* Message builder disabled, probably permanently, + * I want to do it another way + */ + { + _dbus_warn ("Could not load message file %s\n", + _dbus_string_get_const_data (filename)); + goto failed; + } + } + + retval = TRUE; + + failed: + + return retval; +} + +/** + * Tries loading the message in the given message file + * and verifies that DBusMessageLoader can handle it. + * + * @param filename filename to load + * @param is_raw if #TRUE load as binary data, if #FALSE as message builder language + * @param expected_validity what the message has to be like to return #TRUE + * @returns #TRUE if the message has the expected validity + */ +dbus_bool_t +dbus_internal_do_not_use_try_message_file (const DBusString *filename, + dbus_bool_t is_raw, + DBusMessageValidity expected_validity) +{ + DBusString data; + dbus_bool_t retval; + + retval = FALSE; + + if (!_dbus_string_init (&data)) + _dbus_assert_not_reached ("could not allocate string\n"); + + if (!dbus_internal_do_not_use_load_message_file (filename, is_raw, + &data)) + goto failed; + + retval = dbus_internal_do_not_use_try_message_data (&data, expected_validity); + + failed: + + if (!retval) + { + if (_dbus_string_get_length (&data) > 0) + _dbus_verbose_bytes_of_string (&data, 0, + _dbus_string_get_length (&data)); + + _dbus_warn ("Failed message loader test on %s\n", + _dbus_string_get_const_data (filename)); + } + + _dbus_string_free (&data); + + return retval; +} + +/** + * Tries loading the given message data. + * + * + * @param data the message data + * @param expected_validity what the message has to be like to return #TRUE + * @returns #TRUE if the message has the expected validity + */ +dbus_bool_t +dbus_internal_do_not_use_try_message_data (const DBusString *data, + DBusMessageValidity expected_validity) +{ + DBusMessageLoader *loader; + dbus_bool_t retval; + int len; + int i; + + loader = NULL; + retval = FALSE; + + /* Write the data one byte at a time */ + + loader = _dbus_message_loader_new (); + + /* check some trivial loader functions */ + _dbus_message_loader_ref (loader); + _dbus_message_loader_unref (loader); + _dbus_message_loader_get_max_message_size (loader); + + len = _dbus_string_get_length (data); + for (i = 0; i < len; i++) + { + DBusString *buffer; + + _dbus_message_loader_get_buffer (loader, &buffer); + _dbus_string_append_byte (buffer, + _dbus_string_get_byte (data, i)); + _dbus_message_loader_return_buffer (loader, buffer, 1); + } + + if (!check_loader_results (loader, expected_validity)) + goto failed; + + _dbus_message_loader_unref (loader); + loader = NULL; + + /* Write the data all at once */ + + loader = _dbus_message_loader_new (); + + { + DBusString *buffer; + + _dbus_message_loader_get_buffer (loader, &buffer); + _dbus_string_copy (data, 0, buffer, + _dbus_string_get_length (buffer)); + _dbus_message_loader_return_buffer (loader, buffer, 1); + } + + if (!check_loader_results (loader, expected_validity)) + goto failed; + + _dbus_message_loader_unref (loader); + loader = NULL; + + /* Write the data 2 bytes at a time */ + + loader = _dbus_message_loader_new (); + + len = _dbus_string_get_length (data); + for (i = 0; i < len; i += 2) + { + DBusString *buffer; + + _dbus_message_loader_get_buffer (loader, &buffer); + _dbus_string_append_byte (buffer, + _dbus_string_get_byte (data, i)); + if ((i+1) < len) + _dbus_string_append_byte (buffer, + _dbus_string_get_byte (data, i+1)); + _dbus_message_loader_return_buffer (loader, buffer, 1); + } + + if (!check_loader_results (loader, expected_validity)) + goto failed; + + _dbus_message_loader_unref (loader); + loader = NULL; + + retval = TRUE; + + failed: + + if (loader) + _dbus_message_loader_unref (loader); + + return retval; +} + +static dbus_bool_t +process_test_subdir (const DBusString *test_base_dir, + const char *subdir, + DBusMessageValidity validity, + DBusForeachMessageFileFunc function, + void *user_data) +{ + DBusString test_directory; + DBusString filename; + DBusDirIter *dir; + dbus_bool_t retval; + DBusError error; + + retval = FALSE; + dir = NULL; + + if (!_dbus_string_init (&test_directory)) + _dbus_assert_not_reached ("didn't allocate test_directory\n"); + + _dbus_string_init_const (&filename, subdir); + + if (!_dbus_string_copy (test_base_dir, 0, + &test_directory, 0)) + _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory"); + + if (!_dbus_concat_dir_and_file (&test_directory, &filename)) + _dbus_assert_not_reached ("couldn't allocate full path"); + + _dbus_string_free (&filename); + if (!_dbus_string_init (&filename)) + _dbus_assert_not_reached ("didn't allocate filename string\n"); + + dbus_error_init (&error); + dir = _dbus_directory_open (&test_directory, &error); + if (dir == NULL) + { + _dbus_warn ("Could not open %s: %s\n", + _dbus_string_get_const_data (&test_directory), + error.message); + dbus_error_free (&error); + goto failed; + } + + printf ("Testing %s:\n", subdir); + + next: + while (_dbus_directory_get_next_file (dir, &filename, &error)) + { + DBusString full_path; + dbus_bool_t is_raw; + + if (!_dbus_string_init (&full_path)) + _dbus_assert_not_reached ("couldn't init string"); + + if (!_dbus_string_copy (&test_directory, 0, &full_path, 0)) + _dbus_assert_not_reached ("couldn't copy dir to full_path"); + + if (!_dbus_concat_dir_and_file (&full_path, &filename)) + _dbus_assert_not_reached ("couldn't concat file to dir"); + + if (_dbus_string_ends_with_c_str (&filename, ".message")) + is_raw = FALSE; + else if (_dbus_string_ends_with_c_str (&filename, ".message-raw")) + is_raw = TRUE; + else + { + _dbus_verbose ("Skipping non-.message file %s\n", + _dbus_string_get_const_data (&filename)); + _dbus_string_free (&full_path); + goto next; + } + + printf (" %s\n", + _dbus_string_get_const_data (&filename)); + + _dbus_verbose (" expecting %s for %s\n", + validity == _DBUS_MESSAGE_VALID ? "valid" : + (validity == _DBUS_MESSAGE_INVALID ? "invalid" : + (validity == _DBUS_MESSAGE_INCOMPLETE ? "incomplete" : "unknown")), + _dbus_string_get_const_data (&filename)); + + if (! (*function) (&full_path, is_raw, validity, user_data)) + { + _dbus_string_free (&full_path); + goto failed; + } + else + _dbus_string_free (&full_path); + } + + if (dbus_error_is_set (&error)) + { + _dbus_warn ("Could not get next file in %s: %s\n", + _dbus_string_get_const_data (&test_directory), + error.message); + dbus_error_free (&error); + goto failed; + } + + retval = TRUE; + + failed: + + if (dir) + _dbus_directory_close (dir); + _dbus_string_free (&test_directory); + _dbus_string_free (&filename); + + return retval; +} + +/** + * Runs the given function on every message file in the test suite. + * The function should return #FALSE on test failure or fatal error. + * + * @param test_data_dir root dir of the test suite data files (top_srcdir/test/data) + * @param func the function to run + * @param user_data data for function + * @returns #FALSE if there's a failure + */ +dbus_bool_t +dbus_internal_do_not_use_foreach_message_file (const char *test_data_dir, + DBusForeachMessageFileFunc func, + void *user_data) +{ + DBusString test_directory; + dbus_bool_t retval; + + retval = FALSE; + + _dbus_string_init_const (&test_directory, test_data_dir); + + if (!process_test_subdir (&test_directory, "valid-messages", + _DBUS_MESSAGE_VALID, func, user_data)) + goto failed; + + if (!process_test_subdir (&test_directory, "invalid-messages", + _DBUS_MESSAGE_INVALID, func, user_data)) + goto failed; + + if (!process_test_subdir (&test_directory, "incomplete-messages", + _DBUS_MESSAGE_INCOMPLETE, func, user_data)) + goto failed; + + retval = TRUE; + + failed: + + _dbus_string_free (&test_directory); + + return retval; +} + +#define GET_AND_CHECK(iter, typename, literal) \ + do { \ + if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_##typename) \ + _dbus_assert_not_reached ("got wrong argument type from message iter"); \ + dbus_message_iter_get_basic (&iter, &v_##typename); \ + if (v_##typename != literal) \ + _dbus_assert_not_reached ("got wrong value from message iter"); \ + } while (0) + +#define GET_AND_CHECK_STRCMP(iter, typename, literal) \ + do { \ + if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_##typename) \ + _dbus_assert_not_reached ("got wrong argument type from message iter"); \ + dbus_message_iter_get_basic (&iter, &v_##typename); \ + if (strcmp (v_##typename, literal) != 0) \ + _dbus_assert_not_reached ("got wrong value from message iter"); \ + } while (0) + +#define GET_AND_CHECK_AND_NEXT(iter, typename, literal) \ + do { \ + GET_AND_CHECK(iter, typename, literal); \ + if (!dbus_message_iter_next (&iter)) \ + _dbus_assert_not_reached ("failed to move iter to next"); \ + } while (0) + +#define GET_AND_CHECK_STRCMP_AND_NEXT(iter, typename, literal) \ + do { \ + GET_AND_CHECK_STRCMP(iter, typename, literal); \ + if (!dbus_message_iter_next (&iter)) \ + _dbus_assert_not_reached ("failed to move iter to next"); \ + } while (0) + +static void +message_iter_test (DBusMessage *message) +{ + DBusMessageIter iter, array, array2; + const char *v_STRING; + double v_DOUBLE; + dbus_int32_t v_INT32; + dbus_uint32_t v_UINT32; +#ifdef DBUS_HAVE_INT64 + dbus_int64_t v_INT64; + dbus_uint64_t v_UINT64; +#endif + unsigned char v_BYTE; + unsigned char v_BOOLEAN; + + const dbus_int32_t *our_int_array; + int len; + + dbus_message_iter_init (message, &iter); + + GET_AND_CHECK_STRCMP_AND_NEXT (iter, STRING, "Test string"); + GET_AND_CHECK_AND_NEXT (iter, INT32, -0x12345678); + GET_AND_CHECK_AND_NEXT (iter, UINT32, 0xedd1e); + GET_AND_CHECK_AND_NEXT (iter, DOUBLE, 3.14159); + + if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY) + _dbus_assert_not_reached ("Argument type not an array"); + + if (dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_DOUBLE) + _dbus_assert_not_reached ("Array type not double"); + + dbus_message_iter_recurse (&iter, &array); + + GET_AND_CHECK_AND_NEXT (array, DOUBLE, 1.5); + GET_AND_CHECK (array, DOUBLE, 2.5); + + if (dbus_message_iter_next (&array)) + _dbus_assert_not_reached ("Didn't reach end of array"); + + if (!dbus_message_iter_next (&iter)) + _dbus_assert_not_reached ("Reached end of arguments"); + + GET_AND_CHECK_AND_NEXT (iter, BYTE, 0xF0); + + if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY) + _dbus_assert_not_reached ("no array"); + + if (dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_INT32) + _dbus_assert_not_reached ("Array type not int32"); + + /* Empty array */ + dbus_message_iter_recurse (&iter, &array); + + if (dbus_message_iter_next (&array)) + _dbus_assert_not_reached ("Didn't reach end of array"); + + if (!dbus_message_iter_next (&iter)) + _dbus_assert_not_reached ("Reached end of arguments"); + + GET_AND_CHECK (iter, BYTE, 0xF0); + + if (dbus_message_iter_next (&iter)) + _dbus_assert_not_reached ("Didn't reach end of arguments"); +} + +static void +verify_test_message (DBusMessage *message) +{ + DBusMessageIter iter; + DBusError error; + dbus_int32_t our_int; + const char *our_str; + double our_double; + unsigned char our_bool; + unsigned char our_byte_1, our_byte_2; + dbus_uint32_t our_uint32; + const dbus_int32_t *our_uint32_array = (void*)0xdeadbeef; + int our_uint32_array_len; + dbus_int32_t *our_int32_array = (void*)0xdeadbeef; + int our_int32_array_len; +#ifdef DBUS_HAVE_INT64 + dbus_int64_t our_int64; + dbus_uint64_t our_uint64; + dbus_int64_t *our_uint64_array = (void*)0xdeadbeef; + int our_uint64_array_len; + const dbus_int64_t *our_int64_array = (void*)0xdeadbeef; + int our_int64_array_len; +#endif + const double *our_double_array = (void*)0xdeadbeef; + int our_double_array_len; + const unsigned char *our_byte_array = (void*)0xdeadbeef; + int our_byte_array_len; + const unsigned char *our_boolean_array = (void*)0xdeadbeef; + int our_boolean_array_len; + + dbus_message_iter_init (message, &iter); + + dbus_error_init (&error); + if (!dbus_message_iter_get_args (&iter, &error, + DBUS_TYPE_INT32, &our_int, +#ifdef DBUS_HAVE_INT64 + DBUS_TYPE_INT64, &our_int64, + DBUS_TYPE_UINT64, &our_uint64, +#endif + DBUS_TYPE_STRING, &our_str, + DBUS_TYPE_DOUBLE, &our_double, + DBUS_TYPE_BOOLEAN, &our_bool, + DBUS_TYPE_BYTE, &our_byte_1, + DBUS_TYPE_BYTE, &our_byte_2, + DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, + &our_uint32_array, &our_uint32_array_len, + DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, + &our_int32_array, &our_int32_array_len, +#ifdef DBUS_HAVE_INT64 + DBUS_TYPE_ARRAY, DBUS_TYPE_UINT64, + &our_uint64_array, &our_uint64_array_len, + DBUS_TYPE_ARRAY, DBUS_TYPE_INT64, + &our_int64_array, &our_int64_array_len, +#endif + DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE, + &our_double_array, &our_double_array_len, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, + &our_byte_array, &our_byte_array_len, + DBUS_TYPE_ARRAY, DBUS_TYPE_BOOLEAN, + &our_boolean_array, &our_boolean_array_len, + 0)) + { + _dbus_warn ("error: %s - %s\n", error.name, + (error.message != NULL) ? error.message : "no message"); + _dbus_assert_not_reached ("Could not get arguments"); + } + + if (our_int != -0x12345678) + _dbus_assert_not_reached ("integers differ!"); + +#ifdef DBUS_HAVE_INT64 + if (our_int64 != DBUS_INT64_CONSTANT (-0x123456789abcd)) + _dbus_assert_not_reached ("64-bit integers differ!"); + if (our_uint64 != DBUS_UINT64_CONSTANT (0x123456789abcd)) + _dbus_assert_not_reached ("64-bit unsigned integers differ!"); +#endif + + if (our_double != 3.14159) + _dbus_assert_not_reached ("doubles differ!"); + + if (strcmp (our_str, "Test string") != 0) + _dbus_assert_not_reached ("strings differ!"); + + if (!our_bool) + _dbus_assert_not_reached ("booleans differ"); + + if (our_byte_1 != 42) + _dbus_assert_not_reached ("bytes differ!"); + + if (our_byte_2 != 24) + _dbus_assert_not_reached ("bytes differ!"); + + if (our_uint32_array_len != 4 || + our_uint32_array[0] != 0x12345678 || + our_uint32_array[1] != 0x23456781 || + our_uint32_array[2] != 0x34567812 || + our_uint32_array[3] != 0x45678123) + _dbus_assert_not_reached ("uint array differs"); + + if (our_int32_array_len != 4 || + our_int32_array[0] != 0x12345678 || + our_int32_array[1] != -0x23456781 || + our_int32_array[2] != 0x34567812 || + our_int32_array[3] != -0x45678123) + _dbus_assert_not_reached ("int array differs"); + +#ifdef DBUS_HAVE_INT64 + if (our_uint64_array_len != 4 || + our_uint64_array[0] != 0x12345678 || + our_uint64_array[1] != 0x23456781 || + our_uint64_array[2] != 0x34567812 || + our_uint64_array[3] != 0x45678123) + _dbus_assert_not_reached ("uint64 array differs"); + + if (our_int64_array_len != 4 || + our_int64_array[0] != 0x12345678 || + our_int64_array[1] != -0x23456781 || + our_int64_array[2] != 0x34567812 || + our_int64_array[3] != -0x45678123) + _dbus_assert_not_reached ("int64 array differs"); +#endif /* DBUS_HAVE_INT64 */ + + if (our_double_array_len != 3) + _dbus_assert_not_reached ("double array had wrong length"); + + /* On all IEEE machines (i.e. everything sane) exact equality + * should be preserved over the wire + */ + if (our_double_array[0] != 0.1234 || + our_double_array[1] != 9876.54321 || + our_double_array[2] != -300.0) + _dbus_assert_not_reached ("double array had wrong values"); + + if (our_byte_array_len != 4) + _dbus_assert_not_reached ("byte array had wrong length"); + + if (our_byte_array[0] != 'a' || + our_byte_array[1] != 'b' || + our_byte_array[2] != 'c' || + our_byte_array[3] != 234) + _dbus_assert_not_reached ("byte array had wrong values"); + + if (our_boolean_array_len != 5) + _dbus_assert_not_reached ("bool array had wrong length"); + + if (our_boolean_array[0] != TRUE || + our_boolean_array[1] != FALSE || + our_boolean_array[2] != TRUE || + our_boolean_array[3] != TRUE || + our_boolean_array[4] != FALSE) + _dbus_assert_not_reached ("bool array had wrong values"); + + if (dbus_message_iter_next (&iter)) + _dbus_assert_not_reached ("Didn't reach end of arguments"); +} + +/** + * @ingroup DBusMessageInternals + * Unit test for DBusMessage. + * + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_message_test (const char *test_data_dir) +{ + DBusMessage *message; + DBusMessageLoader *loader; + DBusMessageIter iter, child_iter, child_iter2, child_iter3; + int i; + const char *data; + DBusMessage *copy; + const char *name1; + const char *name2; + const dbus_uint32_t our_uint32_array[] = + { 0x12345678, 0x23456781, 0x34567812, 0x45678123 }; + const dbus_uint32_t our_int32_array[] = + { 0x12345678, -0x23456781, 0x34567812, -0x45678123 }; + const dbus_uint32_t *v_ARRAY_UINT32 = our_uint32_array; + const dbus_int32_t *v_ARRAY_INT32 = our_int32_array; +#ifdef DBUS_HAVE_INT64 + const dbus_uint64_t our_uint64_array[] = + { 0x12345678, 0x23456781, 0x34567812, 0x45678123 }; + const dbus_uint64_t our_int64_array[] = + { 0x12345678, -0x23456781, 0x34567812, -0x45678123 }; + const dbus_uint64_t *v_ARRAY_UINT64 = our_uint64_array; + const dbus_int64_t *v_ARRAY_INT64 = our_int64_array; +#endif + const char *our_string_array[] = { "Foo", "bar", "", "woo woo woo woo" }; + const char **v_ARRAY_STRING = our_string_array; + const double our_double_array[] = { 0.1234, 9876.54321, -300.0 }; + const double *v_ARRAY_DOUBLE = our_double_array; + const unsigned char our_byte_array[] = { 'a', 'b', 'c', 234 }; + const unsigned char *v_ARRAY_BYTE = our_byte_array; + const unsigned char our_boolean_array[] = { TRUE, FALSE, TRUE, TRUE, FALSE }; + const unsigned char *v_ARRAY_BOOLEAN = our_boolean_array; + char sig[64]; + const char *s; + char *t; + DBusError error; + const char *v_STRING; + double v_DOUBLE; + dbus_int32_t v_INT32; + dbus_uint32_t v_UINT32; +#ifdef DBUS_HAVE_INT64 + dbus_int64_t v_INT64; + dbus_uint64_t v_UINT64; +#endif + unsigned char v_BYTE; + unsigned char v2_BYTE; + unsigned char v_BOOLEAN; + + message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService", + "/org/freedesktop/TestPath", + "Foo.TestInterface", + "TestMethod"); + _dbus_assert (dbus_message_has_destination (message, "org.freedesktop.DBus.TestService")); + _dbus_assert (dbus_message_is_method_call (message, "Foo.TestInterface", + "TestMethod")); + _dbus_assert (strcmp (dbus_message_get_path (message), + "/org/freedesktop/TestPath") == 0); + _dbus_message_set_serial (message, 1234); + + /* string length including nul byte not a multiple of 4 */ + if (!dbus_message_set_sender (message, "org.foo.bar1")) + _dbus_assert_not_reached ("out of memory"); + + _dbus_assert (dbus_message_has_sender (message, "org.foo.bar1")); + dbus_message_set_reply_serial (message, 5678); + + _dbus_verbose_bytes_of_string (&message->header.data, 0, + _dbus_string_get_length (&message->header.data)); + _dbus_verbose_bytes_of_string (&message->body, 0, + _dbus_string_get_length (&message->body)); + + if (!dbus_message_set_sender (message, NULL)) + _dbus_assert_not_reached ("out of memory"); + + + _dbus_verbose_bytes_of_string (&message->header.data, 0, + _dbus_string_get_length (&message->header.data)); + _dbus_verbose_bytes_of_string (&message->body, 0, + _dbus_string_get_length (&message->body)); + + + _dbus_assert (!dbus_message_has_sender (message, "org.foo.bar1")); + _dbus_assert (dbus_message_get_serial (message) == 1234); + _dbus_assert (dbus_message_get_reply_serial (message) == 5678); + _dbus_assert (dbus_message_has_destination (message, "org.freedesktop.DBus.TestService")); + + _dbus_assert (dbus_message_get_no_reply (message) == FALSE); + dbus_message_set_no_reply (message, TRUE); + _dbus_assert (dbus_message_get_no_reply (message) == TRUE); + dbus_message_set_no_reply (message, FALSE); + _dbus_assert (dbus_message_get_no_reply (message) == FALSE); + + /* Set/get some header fields */ + + if (!dbus_message_set_path (message, "/foo")) + _dbus_assert_not_reached ("out of memory"); + _dbus_assert (strcmp (dbus_message_get_path (message), + "/foo") == 0); + + if (!dbus_message_set_interface (message, "org.Foo")) + _dbus_assert_not_reached ("out of memory"); + _dbus_assert (strcmp (dbus_message_get_interface (message), + "org.Foo") == 0); + + if (!dbus_message_set_member (message, "Bar")) + _dbus_assert_not_reached ("out of memory"); + _dbus_assert (strcmp (dbus_message_get_member (message), + "Bar") == 0); + + /* Set/get them with longer values */ + if (!dbus_message_set_path (message, "/foo/bar")) + _dbus_assert_not_reached ("out of memory"); + _dbus_assert (strcmp (dbus_message_get_path (message), + "/foo/bar") == 0); + + if (!dbus_message_set_interface (message, "org.Foo.Bar")) + _dbus_assert_not_reached ("out of memory"); + _dbus_assert (strcmp (dbus_message_get_interface (message), + "org.Foo.Bar") == 0); + + if (!dbus_message_set_member (message, "BarFoo")) + _dbus_assert_not_reached ("out of memory"); + _dbus_assert (strcmp (dbus_message_get_member (message), + "BarFoo") == 0); + + /* Realloc shorter again */ + + if (!dbus_message_set_path (message, "/foo")) + _dbus_assert_not_reached ("out of memory"); + _dbus_assert (strcmp (dbus_message_get_path (message), + "/foo") == 0); + + if (!dbus_message_set_interface (message, "org.Foo")) + _dbus_assert_not_reached ("out of memory"); + _dbus_assert (strcmp (dbus_message_get_interface (message), + "org.Foo") == 0); + + if (!dbus_message_set_member (message, "Bar")) + _dbus_assert_not_reached ("out of memory"); + _dbus_assert (strcmp (dbus_message_get_member (message), + "Bar") == 0); + + dbus_message_unref (message); + + /* Test the vararg functions */ + message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService", + "/org/freedesktop/TestPath", + "Foo.TestInterface", + "TestMethod"); + _dbus_message_set_serial (message, 1); + + v_INT32 = -0x12345678; +#ifdef DBUS_HAVE_INT64 + v_INT64 = DBUS_INT64_CONSTANT (-0x123456789abcd); + v_UINT64 = DBUS_UINT64_CONSTANT (0x123456789abcd); +#endif + v_STRING = "Test string"; + v_DOUBLE = 3.14159; + v_BOOLEAN = TRUE; + v_BYTE = 42; + v2_BYTE = 24; + + dbus_message_append_args (message, + DBUS_TYPE_INT32, &v_INT32, +#ifdef DBUS_HAVE_INT64 + DBUS_TYPE_INT64, &v_INT64, + DBUS_TYPE_UINT64, &v_UINT64, +#endif + DBUS_TYPE_STRING, &v_STRING, + DBUS_TYPE_DOUBLE, &v_DOUBLE, + DBUS_TYPE_BOOLEAN, &v_BOOLEAN, + DBUS_TYPE_BYTE, &v_BYTE, + DBUS_TYPE_BYTE, &v2_BYTE, + DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &v_ARRAY_UINT32, + _DBUS_N_ELEMENTS (our_uint32_array), + DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, &v_ARRAY_INT32, + _DBUS_N_ELEMENTS (our_int32_array), +#ifdef DBUS_HAVE_INT64 + DBUS_TYPE_ARRAY, DBUS_TYPE_UINT64, &v_ARRAY_UINT64, + _DBUS_N_ELEMENTS (our_uint64_array), + DBUS_TYPE_ARRAY, DBUS_TYPE_INT64, &v_ARRAY_INT64, + _DBUS_N_ELEMENTS (our_int64_array), +#endif + DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE, &v_ARRAY_DOUBLE, + _DBUS_N_ELEMENTS (our_double_array), + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &v_ARRAY_BYTE, + _DBUS_N_ELEMENTS (our_byte_array), + DBUS_TYPE_ARRAY, DBUS_TYPE_BOOLEAN, &v_ARRAY_BOOLEAN, + _DBUS_N_ELEMENTS (our_boolean_array), + DBUS_TYPE_INVALID); + + i = 0; + sig[i++] = DBUS_TYPE_INT32; +#ifdef DBUS_HAVE_INT64 + sig[i++] = DBUS_TYPE_INT64; + sig[i++] = DBUS_TYPE_UINT64; +#endif + sig[i++] = DBUS_TYPE_STRING; + sig[i++] = DBUS_TYPE_DOUBLE; + sig[i++] = DBUS_TYPE_BOOLEAN; + sig[i++] = DBUS_TYPE_BYTE; + sig[i++] = DBUS_TYPE_BYTE; + sig[i++] = DBUS_TYPE_ARRAY; + sig[i++] = DBUS_TYPE_UINT32; + sig[i++] = DBUS_TYPE_ARRAY; + sig[i++] = DBUS_TYPE_INT32; +#ifdef DBUS_HAVE_INT64 + sig[i++] = DBUS_TYPE_ARRAY; + sig[i++] = DBUS_TYPE_UINT64; + sig[i++] = DBUS_TYPE_ARRAY; + sig[i++] = DBUS_TYPE_INT64; +#endif + sig[i++] = DBUS_TYPE_ARRAY; + sig[i++] = DBUS_TYPE_DOUBLE; + sig[i++] = DBUS_TYPE_ARRAY; + sig[i++] = DBUS_TYPE_BYTE; + sig[i++] = DBUS_TYPE_ARRAY; + sig[i++] = DBUS_TYPE_BOOLEAN; + sig[i++] = DBUS_TYPE_INVALID; + + _dbus_assert (i < (int) _DBUS_N_ELEMENTS (sig)); + + _dbus_verbose ("HEADER\n"); + _dbus_verbose_bytes_of_string (&message->header.data, 0, + _dbus_string_get_length (&message->header.data)); + _dbus_verbose ("BODY\n"); + _dbus_verbose_bytes_of_string (&message->body, 0, + _dbus_string_get_length (&message->body)); + + _dbus_verbose ("Signature expected \"%s\" actual \"%s\"\n", + sig, dbus_message_get_signature (message)); + + s = dbus_message_get_signature (message); + + _dbus_assert (dbus_message_has_signature (message, sig)); + _dbus_assert (strcmp (s, sig) == 0); + + verify_test_message (message); + + copy = dbus_message_copy (message); + + _dbus_assert (dbus_message_get_reply_serial (message) == + dbus_message_get_reply_serial (copy)); + _dbus_assert (message->header.padding == copy->header.padding); + + _dbus_assert (_dbus_string_get_length (&message->header.data) == + _dbus_string_get_length (©->header.data)); + + _dbus_assert (_dbus_string_get_length (&message->body) == + _dbus_string_get_length (©->body)); + + verify_test_message (copy); + + name1 = dbus_message_get_interface (message); + name2 = dbus_message_get_interface (copy); + + _dbus_assert (strcmp (name1, name2) == 0); + + name1 = dbus_message_get_member (message); + name2 = dbus_message_get_member (copy); + + _dbus_assert (strcmp (name1, name2) == 0); + + dbus_message_unref (message); + dbus_message_unref (copy); + +#if 0 + /* FIXME */ + message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService", + "/org/freedesktop/TestPath", + "Foo.TestInterface", + "TestMethod"); + + _dbus_message_set_serial (message, 1); + dbus_message_set_reply_serial (message, 0x12345678); + + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_string (&iter, "Test string"); + dbus_message_iter_append_int32 (&iter, -0x12345678); + dbus_message_iter_append_uint32 (&iter, 0xedd1e); + dbus_message_iter_append_double (&iter, 3.14159); + + dbus_message_iter_append_array (&iter, &child_iter, DBUS_TYPE_DOUBLE); + dbus_message_iter_append_double (&child_iter, 1.5); + dbus_message_iter_append_double (&child_iter, 2.5); + + /* dict */ + dbus_message_iter_append_dict (&iter, &child_iter); + dbus_message_iter_append_dict_key (&child_iter, "test"); + dbus_message_iter_append_uint32 (&child_iter, 0xDEADBEEF); + + /* dict (in dict) */ + dbus_message_iter_append_dict_key (&child_iter, "testdict"); + dbus_message_iter_append_dict (&child_iter, &child_iter2); + + dbus_message_iter_append_dict_key (&child_iter2, "dictkey"); + dbus_message_iter_append_string (&child_iter2, "dictvalue"); + + /* array of array of int32 (in dict) */ + dbus_message_iter_append_dict_key (&child_iter, "array"); + dbus_message_iter_append_array (&child_iter, &child_iter2, DBUS_TYPE_ARRAY); + dbus_message_iter_append_array (&child_iter2, &child_iter3, DBUS_TYPE_INT32); + dbus_message_iter_append_int32 (&child_iter3, 0x12345678); + dbus_message_iter_append_int32 (&child_iter3, 0x23456781); + _dbus_warn ("next call expected to fail with wrong array type\n"); + _dbus_assert (!dbus_message_iter_append_array (&child_iter2, &child_iter3, DBUS_TYPE_UINT32)); + dbus_message_iter_append_array (&child_iter2, &child_iter3, DBUS_TYPE_INT32); + dbus_message_iter_append_int32 (&child_iter3, 0x34567812); + dbus_message_iter_append_int32 (&child_iter3, 0x45678123); + dbus_message_iter_append_int32 (&child_iter3, 0x56781234); + + dbus_message_iter_append_byte (&iter, 0xF0); + + dbus_message_iter_append_nil (&iter); + + dbus_message_iter_append_custom (&iter, "MyTypeName", + "data", 5); + + dbus_message_iter_append_byte (&iter, 0xF0); + + dbus_message_iter_append_array (&iter, &child_iter, DBUS_TYPE_INT32); + + dbus_message_iter_append_byte (&iter, 0xF0); + + dbus_message_iter_append_dict (&iter, &child_iter); + + dbus_message_iter_append_byte (&iter, 0xF0); + + message_iter_test (message); + + /* Message loader test */ + _dbus_message_lock (message); + loader = _dbus_message_loader_new (); + + /* check ref/unref */ + _dbus_message_loader_ref (loader); + _dbus_message_loader_unref (loader); + + /* Write the header data one byte at a time */ + data = _dbus_string_get_const_data (&message->header); + for (i = 0; i < _dbus_string_get_length (&message->header); i++) + { + DBusString *buffer; + + _dbus_message_loader_get_buffer (loader, &buffer); + _dbus_string_append_byte (buffer, data[i]); + _dbus_message_loader_return_buffer (loader, buffer, 1); + } + + /* Write the body data one byte at a time */ + data = _dbus_string_get_const_data (&message->body); + for (i = 0; i < _dbus_string_get_length (&message->body); i++) + { + DBusString *buffer; + + _dbus_message_loader_get_buffer (loader, &buffer); + _dbus_string_append_byte (buffer, data[i]); + _dbus_message_loader_return_buffer (loader, buffer, 1); + } + + copy = dbus_message_copy (message); /* save for tests below */ + dbus_message_unref (message); + + /* Now pop back the message */ + if (!_dbus_message_loader_queue_messages (loader)) + _dbus_assert_not_reached ("no memory to queue messages"); + + if (_dbus_message_loader_get_is_corrupted (loader)) + _dbus_assert_not_reached ("message loader corrupted"); + + message = _dbus_message_loader_pop_message (loader); + if (!message) + _dbus_assert_not_reached ("received a NULL message"); + + if (dbus_message_get_reply_serial (message) != 0x12345678) + _dbus_assert_not_reached ("reply serial fields differ"); + + message_iter_test (message); + + dbus_message_unref (message); + _dbus_message_loader_unref (loader); + + message = dbus_message_new_method_return (copy); + if (message == NULL) + _dbus_assert_not_reached ("out of memory\n"); + dbus_message_unref (copy); + + if (!dbus_message_append_args (message, + DBUS_TYPE_STRING, "hello", + DBUS_TYPE_INVALID)) + _dbus_assert_not_reached ("no memory"); + + if (!dbus_message_has_signature (message, "s")) + _dbus_assert_not_reached ("method return has wrong signature"); + + dbus_error_init (&error); + if (!dbus_message_get_args (message, &error, DBUS_TYPE_STRING, + &t, DBUS_TYPE_INVALID)) + + { + _dbus_warn ("Failed to get expected string arg: %s\n", error.message); + exit (1); + } + dbus_free (t); + + dbus_message_unref (message); + + /* This ServiceAcquired message used to trigger a bug in + * setting header fields, adding to regression test. + */ + message = dbus_message_new_signal (DBUS_PATH_ORG_FREEDESKTOP_DBUS, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "ServiceAcquired"); + + if (message == NULL) + _dbus_assert_not_reached ("out of memory"); + + _dbus_verbose ("Bytes after creation\n"); + _dbus_verbose_bytes_of_string (&message->header, 0, + _dbus_string_get_length (&message->header)); + + if (!dbus_message_set_destination (message, ":1.0") || + !dbus_message_append_args (message, + DBUS_TYPE_STRING, ":1.0", + DBUS_TYPE_INVALID)) + _dbus_assert_not_reached ("out of memory"); + + _dbus_verbose ("Bytes after set_destination() and append_args()\n"); + _dbus_verbose_bytes_of_string (&message->header, 0, + _dbus_string_get_length (&message->header)); + + if (!dbus_message_set_sender (message, "org.freedesktop.DBus")) + _dbus_assert_not_reached ("out of memory"); + + _dbus_verbose ("Bytes after set_sender()\n"); + _dbus_verbose_bytes_of_string (&message->header, 0, + _dbus_string_get_length (&message->header)); + + /* When the bug happened the above set_destination() would + * corrupt the signature + */ + if (!dbus_message_has_signature (message, "s")) + { + _dbus_warn ("Signature should be 's' but is '%s'\n", + dbus_message_get_signature (message)); + _dbus_assert_not_reached ("signal has wrong signature"); + } + + /* have to set destination again to reproduce the bug */ + if (!dbus_message_set_destination (message, ":1.0")) + _dbus_assert_not_reached ("out of memory"); + + _dbus_verbose ("Bytes after set_destination()\n"); + _dbus_verbose_bytes_of_string (&message->header, 0, + _dbus_string_get_length (&message->header)); + + /* When the bug happened the above set_destination() would + * corrupt the signature + */ + if (!dbus_message_has_signature (message, "s")) + { + _dbus_warn ("Signature should be 's' but is '%s'\n", + dbus_message_get_signature (message)); + _dbus_assert_not_reached ("signal has wrong signature"); + } + + dbus_error_init (&error); + if (!dbus_message_get_args (message, &error, DBUS_TYPE_STRING, + &t, DBUS_TYPE_INVALID)) + + { + _dbus_warn ("Failed to get expected string arg for signal: %s\n", error.message); + exit (1); + } + dbus_free (t); + + dbus_message_unref (message); + + /* Now load every message in test_data_dir if we have one */ + if (test_data_dir == NULL) + return TRUE; + + return dbus_internal_do_not_use_foreach_message_file (test_data_dir, + (DBusForeachMessageFileFunc) + dbus_internal_do_not_use_try_message_file, + NULL); + +#endif /* Commented out most tests for now */ + + return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ -- cgit