2005-01-22 Havoc Pennington <hp@redhat.com>
[platform/upstream/dbus.git] / dbus / dbus-message-util.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-message-util.c Would be in dbus-message.c, but only used by bus/tests
3  *
4  * Copyright (C) 2002, 2003, 2004, 2005  Red Hat Inc.
5  * Copyright (C) 2002, 2003  CodeFactory AB
6  *
7  * Licensed under the Academic Free License version 2.1
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  */
24
25 #include "dbus-internals.h"
26 #include "dbus-test.h"
27 #include "dbus-message-private.h"
28 #include "dbus-marshal-recursive.h"
29 #include "dbus-string.h"
30
31 /**
32  * @addtogroup DBusMessage
33  * @{
34  */
35
36 #ifdef DBUS_BUILD_TESTS
37 /**
38  * Reads arguments from a message iterator given a variable argument
39  * list. Only arguments of basic type and arrays of fixed-length
40  * basic type may be read with this function. See
41  * dbus_message_get_args() for more details.
42  *
43  * @todo this is static for now because there's no corresponding
44  * iter_append_args() and I'm not sure we need this function to be
45  * public since dbus_message_get_args() is what you usually want
46  *
47  * @param iter the message iterator
48  * @param error error to be filled in on failure
49  * @param first_arg_type the first argument type
50  * @param ... location for first argument value, then list of type-location pairs
51  * @returns #FALSE if the error was set
52  */
53 static dbus_bool_t
54 dbus_message_iter_get_args (DBusMessageIter *iter,
55                             DBusError       *error,
56                             int              first_arg_type,
57                             ...)
58 {
59   dbus_bool_t retval;
60   va_list var_args;
61
62   _dbus_return_val_if_fail (iter != NULL, FALSE);
63   _dbus_return_val_if_error_is_set (error, FALSE);
64
65   va_start (var_args, first_arg_type);
66   retval = _dbus_message_iter_get_args_valist (iter, error, first_arg_type, var_args);
67   va_end (var_args);
68
69   return retval;
70 }
71 #endif /* DBUS_BUILD_TESTS */
72
73 /** @} */
74
75 #ifdef DBUS_BUILD_TESTS
76 #include "dbus-test.h"
77 #include "dbus-message-factory.h"
78 #include <stdio.h>
79 #include <stdlib.h>
80
81 static dbus_bool_t
82 check_have_valid_message (DBusMessageLoader *loader)
83 {
84   DBusMessage *message;
85   dbus_bool_t retval;
86
87   message = NULL;
88   retval = FALSE;
89
90   if (!_dbus_message_loader_queue_messages (loader))
91     _dbus_assert_not_reached ("no memory to queue messages");
92
93   if (_dbus_message_loader_get_is_corrupted (loader))
94     {
95       _dbus_warn ("loader corrupted on message that was expected to be valid\n");
96       goto failed;
97     }
98
99   message = _dbus_message_loader_pop_message (loader);
100   if (message == NULL)
101     {
102       _dbus_warn ("didn't load message that was expected to be valid (message not popped)\n");
103       goto failed;
104     }
105
106   if (_dbus_string_get_length (&loader->data) > 0)
107     {
108       _dbus_warn ("had leftover bytes from expected-to-be-valid single message\n");
109       goto failed;
110     }
111
112 #if 0
113   /* FIXME */
114   /* Verify that we're able to properly deal with the message.
115    * For example, this would detect improper handling of messages
116    * in nonstandard byte order.
117    */
118   if (!check_message_handling (message))
119     goto failed;
120 #endif
121
122   retval = TRUE;
123
124  failed:
125   if (message)
126     dbus_message_unref (message);
127
128   return retval;
129 }
130
131 static dbus_bool_t
132 check_invalid_message (DBusMessageLoader *loader)
133 {
134   dbus_bool_t retval;
135
136   retval = FALSE;
137
138   if (!_dbus_message_loader_queue_messages (loader))
139     _dbus_assert_not_reached ("no memory to queue messages");
140
141   if (!_dbus_message_loader_get_is_corrupted (loader))
142     {
143       _dbus_warn ("loader not corrupted on message that was expected to be invalid\n");
144       goto failed;
145     }
146
147   retval = TRUE;
148
149  failed:
150   return retval;
151 }
152
153 static dbus_bool_t
154 check_incomplete_message (DBusMessageLoader *loader)
155 {
156   DBusMessage *message;
157   dbus_bool_t retval;
158
159   message = NULL;
160   retval = FALSE;
161
162   if (!_dbus_message_loader_queue_messages (loader))
163     _dbus_assert_not_reached ("no memory to queue messages");
164
165   if (_dbus_message_loader_get_is_corrupted (loader))
166     {
167       _dbus_warn ("loader corrupted on message that was expected to be valid (but incomplete)\n");
168       goto failed;
169     }
170
171   message = _dbus_message_loader_pop_message (loader);
172   if (message != NULL)
173     {
174       _dbus_warn ("loaded message that was expected to be incomplete\n");
175       goto failed;
176     }
177
178   retval = TRUE;
179
180  failed:
181   if (message)
182     dbus_message_unref (message);
183   return retval;
184 }
185
186 static dbus_bool_t
187 check_loader_results (DBusMessageLoader      *loader,
188                       DBusMessageValidity     validity)
189 {
190   if (!_dbus_message_loader_queue_messages (loader))
191     _dbus_assert_not_reached ("no memory to queue messages");
192
193   switch (validity)
194     {
195     case _DBUS_MESSAGE_VALID:
196       return check_have_valid_message (loader);
197     case _DBUS_MESSAGE_INVALID:
198       return check_invalid_message (loader);
199     case _DBUS_MESSAGE_INCOMPLETE:
200       return check_incomplete_message (loader);
201     case _DBUS_MESSAGE_UNKNOWN:
202       return TRUE;
203     }
204
205   _dbus_assert_not_reached ("bad DBusMessageValidity");
206   return FALSE;
207 }
208
209
210 /**
211  * Loads the message in the given message file.
212  *
213  * @param filename filename to load
214  * @param is_raw if #TRUE load as binary data, if #FALSE as message builder language
215  * @param data string to load message into
216  * @returns #TRUE if the message was loaded
217  */
218 dbus_bool_t
219 dbus_internal_do_not_use_load_message_file (const DBusString    *filename,
220                                             dbus_bool_t          is_raw,
221                                             DBusString          *data)
222 {
223   dbus_bool_t retval;
224
225   retval = FALSE;
226
227   if (is_raw)
228     {
229       DBusError error;
230
231       _dbus_verbose ("Loading raw %s\n", _dbus_string_get_const_data (filename));
232       dbus_error_init (&error);
233       if (!_dbus_file_get_contents (data, filename, &error))
234         {
235           _dbus_warn ("Could not load message file %s: %s\n",
236                       _dbus_string_get_const_data (filename),
237                       error.message);
238           dbus_error_free (&error);
239           goto failed;
240         }
241     }
242   else
243     {
244       if (FALSE) /* Message builder disabled, probably permanently,
245                   * I want to do it another way
246                   */
247         {
248           _dbus_warn ("Could not load message file %s\n",
249                       _dbus_string_get_const_data (filename));
250           goto failed;
251         }
252     }
253
254   retval = TRUE;
255
256  failed:
257
258   return retval;
259 }
260
261 /**
262  * Tries loading the message in the given message file
263  * and verifies that DBusMessageLoader can handle it.
264  *
265  * @param filename filename to load
266  * @param is_raw if #TRUE load as binary data, if #FALSE as message builder language
267  * @param expected_validity what the message has to be like to return #TRUE
268  * @returns #TRUE if the message has the expected validity
269  */
270 dbus_bool_t
271 dbus_internal_do_not_use_try_message_file (const DBusString    *filename,
272                                            dbus_bool_t          is_raw,
273                                            DBusMessageValidity  expected_validity)
274 {
275   DBusString data;
276   dbus_bool_t retval;
277
278   retval = FALSE;
279
280   if (!_dbus_string_init (&data))
281     _dbus_assert_not_reached ("could not allocate string\n");
282
283   if (!dbus_internal_do_not_use_load_message_file (filename, is_raw,
284                                                    &data))
285     goto failed;
286
287   retval = dbus_internal_do_not_use_try_message_data (&data, expected_validity);
288
289  failed:
290
291   if (!retval)
292     {
293       if (_dbus_string_get_length (&data) > 0)
294         _dbus_verbose_bytes_of_string (&data, 0,
295                                        _dbus_string_get_length (&data));
296
297       _dbus_warn ("Failed message loader test on %s\n",
298                   _dbus_string_get_const_data (filename));
299     }
300
301   _dbus_string_free (&data);
302
303   return retval;
304 }
305
306 /**
307  * Tries loading the given message data.
308  *
309  *
310  * @param data the message data
311  * @param expected_validity what the message has to be like to return #TRUE
312  * @returns #TRUE if the message has the expected validity
313  */
314 dbus_bool_t
315 dbus_internal_do_not_use_try_message_data (const DBusString    *data,
316                                            DBusMessageValidity  expected_validity)
317 {
318   DBusMessageLoader *loader;
319   dbus_bool_t retval;
320   int len;
321   int i;
322
323   loader = NULL;
324   retval = FALSE;
325
326   /* Write the data one byte at a time */
327
328   loader = _dbus_message_loader_new ();
329
330   /* check some trivial loader functions */
331   _dbus_message_loader_ref (loader);
332   _dbus_message_loader_unref (loader);
333   _dbus_message_loader_get_max_message_size (loader);
334
335   len = _dbus_string_get_length (data);
336   for (i = 0; i < len; i++)
337     {
338       DBusString *buffer;
339
340       _dbus_message_loader_get_buffer (loader, &buffer);
341       _dbus_string_append_byte (buffer,
342                                 _dbus_string_get_byte (data, i));
343       _dbus_message_loader_return_buffer (loader, buffer, 1);
344     }
345
346   if (!check_loader_results (loader, expected_validity))
347     goto failed;
348
349   _dbus_message_loader_unref (loader);
350   loader = NULL;
351
352   /* Write the data all at once */
353
354   loader = _dbus_message_loader_new ();
355
356   {
357     DBusString *buffer;
358
359     _dbus_message_loader_get_buffer (loader, &buffer);
360     _dbus_string_copy (data, 0, buffer,
361                        _dbus_string_get_length (buffer));
362     _dbus_message_loader_return_buffer (loader, buffer, 1);
363   }
364
365   if (!check_loader_results (loader, expected_validity))
366     goto failed;
367
368   _dbus_message_loader_unref (loader);
369   loader = NULL;
370
371   /* Write the data 2 bytes at a time */
372
373   loader = _dbus_message_loader_new ();
374
375   len = _dbus_string_get_length (data);
376   for (i = 0; i < len; i += 2)
377     {
378       DBusString *buffer;
379
380       _dbus_message_loader_get_buffer (loader, &buffer);
381       _dbus_string_append_byte (buffer,
382                                 _dbus_string_get_byte (data, i));
383       if ((i+1) < len)
384         _dbus_string_append_byte (buffer,
385                                   _dbus_string_get_byte (data, i+1));
386       _dbus_message_loader_return_buffer (loader, buffer, 1);
387     }
388
389   if (!check_loader_results (loader, expected_validity))
390     goto failed;
391
392   _dbus_message_loader_unref (loader);
393   loader = NULL;
394
395   retval = TRUE;
396
397  failed:
398
399   if (loader)
400     _dbus_message_loader_unref (loader);
401
402   return retval;
403 }
404
405 static dbus_bool_t
406 process_test_subdir (const DBusString          *test_base_dir,
407                      const char                *subdir,
408                      DBusMessageValidity        validity,
409                      DBusForeachMessageFileFunc function,
410                      void                      *user_data)
411 {
412   DBusString test_directory;
413   DBusString filename;
414   DBusDirIter *dir;
415   dbus_bool_t retval;
416   DBusError error;
417
418   retval = FALSE;
419   dir = NULL;
420
421   if (!_dbus_string_init (&test_directory))
422     _dbus_assert_not_reached ("didn't allocate test_directory\n");
423
424   _dbus_string_init_const (&filename, subdir);
425
426   if (!_dbus_string_copy (test_base_dir, 0,
427                           &test_directory, 0))
428     _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory");
429
430   if (!_dbus_concat_dir_and_file (&test_directory, &filename))
431     _dbus_assert_not_reached ("couldn't allocate full path");
432
433   _dbus_string_free (&filename);
434   if (!_dbus_string_init (&filename))
435     _dbus_assert_not_reached ("didn't allocate filename string\n");
436
437   dbus_error_init (&error);
438   dir = _dbus_directory_open (&test_directory, &error);
439   if (dir == NULL)
440     {
441       _dbus_warn ("Could not open %s: %s\n",
442                   _dbus_string_get_const_data (&test_directory),
443                   error.message);
444       dbus_error_free (&error);
445       goto failed;
446     }
447
448   printf ("Testing %s:\n", subdir);
449
450  next:
451   while (_dbus_directory_get_next_file (dir, &filename, &error))
452     {
453       DBusString full_path;
454       dbus_bool_t is_raw;
455
456       if (!_dbus_string_init (&full_path))
457         _dbus_assert_not_reached ("couldn't init string");
458
459       if (!_dbus_string_copy (&test_directory, 0, &full_path, 0))
460         _dbus_assert_not_reached ("couldn't copy dir to full_path");
461
462       if (!_dbus_concat_dir_and_file (&full_path, &filename))
463         _dbus_assert_not_reached ("couldn't concat file to dir");
464
465       if (_dbus_string_ends_with_c_str (&filename, ".message"))
466         is_raw = FALSE;
467       else if (_dbus_string_ends_with_c_str (&filename, ".message-raw"))
468         is_raw = TRUE;
469       else
470         {
471           _dbus_verbose ("Skipping non-.message file %s\n",
472                          _dbus_string_get_const_data (&filename));
473           _dbus_string_free (&full_path);
474           goto next;
475         }
476
477       printf ("    %s\n",
478               _dbus_string_get_const_data (&filename));
479
480       _dbus_verbose (" expecting %s for %s\n",
481                      validity == _DBUS_MESSAGE_VALID ? "valid" :
482                      (validity == _DBUS_MESSAGE_INVALID ? "invalid" :
483                       (validity == _DBUS_MESSAGE_INCOMPLETE ? "incomplete" : "unknown")),
484                      _dbus_string_get_const_data (&filename));
485
486       if (! (*function) (&full_path, is_raw, validity, user_data))
487         {
488           _dbus_string_free (&full_path);
489           goto failed;
490         }
491       else
492         _dbus_string_free (&full_path);
493     }
494
495   if (dbus_error_is_set (&error))
496     {
497       _dbus_warn ("Could not get next file in %s: %s\n",
498                   _dbus_string_get_const_data (&test_directory),
499                   error.message);
500       dbus_error_free (&error);
501       goto failed;
502     }
503
504   retval = TRUE;
505
506  failed:
507
508   if (dir)
509     _dbus_directory_close (dir);
510   _dbus_string_free (&test_directory);
511   _dbus_string_free (&filename);
512
513   return retval;
514 }
515
516 /**
517  * Runs the given function on every message file in the test suite.
518  * The function should return #FALSE on test failure or fatal error.
519  *
520  * @param test_data_dir root dir of the test suite data files (top_srcdir/test/data)
521  * @param func the function to run
522  * @param user_data data for function
523  * @returns #FALSE if there's a failure
524  */
525 dbus_bool_t
526 dbus_internal_do_not_use_foreach_message_file (const char                *test_data_dir,
527                                                DBusForeachMessageFileFunc func,
528                                                void                      *user_data)
529 {
530   DBusString test_directory;
531   dbus_bool_t retval;
532
533   retval = FALSE;
534
535   _dbus_string_init_const (&test_directory, test_data_dir);
536
537   if (!process_test_subdir (&test_directory, "valid-messages",
538                             _DBUS_MESSAGE_VALID, func, user_data))
539     goto failed;
540
541   if (!process_test_subdir (&test_directory, "invalid-messages",
542                             _DBUS_MESSAGE_INVALID, func, user_data))
543     goto failed;
544
545   if (!process_test_subdir (&test_directory, "incomplete-messages",
546                             _DBUS_MESSAGE_INCOMPLETE, func, user_data))
547     goto failed;
548
549   retval = TRUE;
550
551  failed:
552
553   _dbus_string_free (&test_directory);
554
555   return retval;
556 }
557
558 #if 0
559 #define GET_AND_CHECK(iter, typename, literal)                                  \
560   do {                                                                          \
561     if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_##typename)         \
562       _dbus_assert_not_reached ("got wrong argument type from message iter");   \
563     dbus_message_iter_get_basic (&iter, &v_##typename);                         \
564     if (v_##typename != literal)                                                \
565       _dbus_assert_not_reached ("got wrong value from message iter");           \
566   } while (0)
567
568 #define GET_AND_CHECK_STRCMP(iter, typename, literal)                           \
569   do {                                                                          \
570     if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_##typename)         \
571       _dbus_assert_not_reached ("got wrong argument type from message iter");   \
572     dbus_message_iter_get_basic (&iter, &v_##typename);                         \
573     if (strcmp (v_##typename, literal) != 0)                                    \
574       _dbus_assert_not_reached ("got wrong value from message iter");           \
575   } while (0)
576
577 #define GET_AND_CHECK_AND_NEXT(iter, typename, literal)         \
578   do {                                                          \
579     GET_AND_CHECK(iter, typename, literal);                     \
580     if (!dbus_message_iter_next (&iter))                        \
581       _dbus_assert_not_reached ("failed to move iter to next"); \
582   } while (0)
583
584 #define GET_AND_CHECK_STRCMP_AND_NEXT(iter, typename, literal)  \
585   do {                                                          \
586     GET_AND_CHECK_STRCMP(iter, typename, literal);              \
587     if (!dbus_message_iter_next (&iter))                        \
588       _dbus_assert_not_reached ("failed to move iter to next"); \
589   } while (0)
590
591 static void
592 message_iter_test (DBusMessage *message)
593 {
594   DBusMessageIter iter, array, array2;
595   const char *v_STRING;
596   double v_DOUBLE;
597   dbus_int32_t v_INT32;
598   dbus_uint32_t v_UINT32;
599 #ifdef DBUS_HAVE_INT64
600   dbus_int64_t v_INT64;
601   dbus_uint64_t v_UINT64;
602 #endif
603   unsigned char v_BYTE;
604   dbus_bool_t v_BOOLEAN;
605
606   const dbus_int32_t *our_int_array;
607   int len;
608
609   dbus_message_iter_init (message, &iter);
610
611   GET_AND_CHECK_STRCMP_AND_NEXT (iter, STRING, "Test string");
612   GET_AND_CHECK_AND_NEXT (iter, INT32, -0x12345678);
613   GET_AND_CHECK_AND_NEXT (iter, UINT32, 0xedd1e);
614   GET_AND_CHECK_AND_NEXT (iter, DOUBLE, 3.14159);
615
616   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY)
617     _dbus_assert_not_reached ("Argument type not an array");
618
619   if (dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_DOUBLE)
620     _dbus_assert_not_reached ("Array type not double");
621
622   dbus_message_iter_recurse (&iter, &array);
623
624   GET_AND_CHECK_AND_NEXT (array, DOUBLE, 1.5);
625   GET_AND_CHECK (array, DOUBLE, 2.5);
626
627   if (dbus_message_iter_next (&array))
628     _dbus_assert_not_reached ("Didn't reach end of array");
629
630   if (!dbus_message_iter_next (&iter))
631     _dbus_assert_not_reached ("Reached end of arguments");
632
633   GET_AND_CHECK_AND_NEXT (iter, BYTE, 0xF0);
634
635   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY)
636     _dbus_assert_not_reached ("no array");
637
638   if (dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_INT32)
639     _dbus_assert_not_reached ("Array type not int32");
640
641   /* Empty array */
642   dbus_message_iter_recurse (&iter, &array);
643
644   if (dbus_message_iter_next (&array))
645     _dbus_assert_not_reached ("Didn't reach end of array");
646
647   if (!dbus_message_iter_next (&iter))
648     _dbus_assert_not_reached ("Reached end of arguments");
649
650   GET_AND_CHECK (iter, BYTE, 0xF0);
651
652   if (dbus_message_iter_next (&iter))
653     _dbus_assert_not_reached ("Didn't reach end of arguments");
654 }
655 #endif
656
657 static void
658 verify_test_message (DBusMessage *message)
659 {
660   DBusMessageIter iter;
661   DBusError error;
662   dbus_int32_t our_int;
663   const char *our_str;
664   double our_double;
665   dbus_bool_t our_bool;
666   unsigned char our_byte_1, our_byte_2;
667   dbus_uint32_t our_uint32;
668   const dbus_int32_t *our_uint32_array = (void*)0xdeadbeef;
669   int our_uint32_array_len;
670   dbus_int32_t *our_int32_array = (void*)0xdeadbeef;
671   int our_int32_array_len;
672 #ifdef DBUS_HAVE_INT64
673   dbus_int64_t our_int64;
674   dbus_uint64_t our_uint64;
675   dbus_int64_t *our_uint64_array = (void*)0xdeadbeef;
676   int our_uint64_array_len;
677   const dbus_int64_t *our_int64_array = (void*)0xdeadbeef;
678   int our_int64_array_len;
679 #endif
680   const double *our_double_array = (void*)0xdeadbeef;
681   int our_double_array_len;
682   const unsigned char *our_byte_array = (void*)0xdeadbeef;
683   int our_byte_array_len;
684   const dbus_bool_t *our_boolean_array = (void*)0xdeadbeef;
685   int our_boolean_array_len;
686
687   dbus_message_iter_init (message, &iter);
688
689   dbus_error_init (&error);
690   if (!dbus_message_iter_get_args (&iter, &error,
691                                    DBUS_TYPE_INT32, &our_int,
692 #ifdef DBUS_HAVE_INT64
693                                    DBUS_TYPE_INT64, &our_int64,
694                                    DBUS_TYPE_UINT64, &our_uint64,
695 #endif
696                                    DBUS_TYPE_STRING, &our_str,
697                                    DBUS_TYPE_DOUBLE, &our_double,
698                                    DBUS_TYPE_BOOLEAN, &our_bool,
699                                    DBUS_TYPE_BYTE, &our_byte_1,
700                                    DBUS_TYPE_BYTE, &our_byte_2,
701                                    DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
702                                    &our_uint32_array, &our_uint32_array_len,
703                                    DBUS_TYPE_ARRAY, DBUS_TYPE_INT32,
704                                    &our_int32_array, &our_int32_array_len,
705 #ifdef DBUS_HAVE_INT64
706                                    DBUS_TYPE_ARRAY, DBUS_TYPE_UINT64,
707                                    &our_uint64_array, &our_uint64_array_len,
708                                    DBUS_TYPE_ARRAY, DBUS_TYPE_INT64,
709                                    &our_int64_array, &our_int64_array_len,
710 #endif
711                                    DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE,
712                                    &our_double_array, &our_double_array_len,
713                                    DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
714                                    &our_byte_array, &our_byte_array_len,
715                                    DBUS_TYPE_ARRAY, DBUS_TYPE_BOOLEAN,
716                                    &our_boolean_array, &our_boolean_array_len,
717                                    0))
718     {
719       _dbus_warn ("error: %s - %s\n", error.name,
720                   (error.message != NULL) ? error.message : "no message");
721       _dbus_assert_not_reached ("Could not get arguments");
722     }
723
724   if (our_int != -0x12345678)
725     _dbus_assert_not_reached ("integers differ!");
726
727 #ifdef DBUS_HAVE_INT64
728   if (our_int64 != DBUS_INT64_CONSTANT (-0x123456789abcd))
729     _dbus_assert_not_reached ("64-bit integers differ!");
730   if (our_uint64 != DBUS_UINT64_CONSTANT (0x123456789abcd))
731     _dbus_assert_not_reached ("64-bit unsigned integers differ!");
732 #endif
733
734   if (our_double != 3.14159)
735     _dbus_assert_not_reached ("doubles differ!");
736
737   if (strcmp (our_str, "Test string") != 0)
738     _dbus_assert_not_reached ("strings differ!");
739
740   if (!our_bool)
741     _dbus_assert_not_reached ("booleans differ");
742
743   if (our_byte_1 != 42)
744     _dbus_assert_not_reached ("bytes differ!");
745
746   if (our_byte_2 != 24)
747     _dbus_assert_not_reached ("bytes differ!");
748
749   if (our_uint32_array_len != 4 ||
750       our_uint32_array[0] != 0x12345678 ||
751       our_uint32_array[1] != 0x23456781 ||
752       our_uint32_array[2] != 0x34567812 ||
753       our_uint32_array[3] != 0x45678123)
754     _dbus_assert_not_reached ("uint array differs");
755
756   if (our_int32_array_len != 4 ||
757       our_int32_array[0] != 0x12345678 ||
758       our_int32_array[1] != -0x23456781 ||
759       our_int32_array[2] != 0x34567812 ||
760       our_int32_array[3] != -0x45678123)
761     _dbus_assert_not_reached ("int array differs");
762
763 #ifdef DBUS_HAVE_INT64
764   if (our_uint64_array_len != 4 ||
765       our_uint64_array[0] != 0x12345678 ||
766       our_uint64_array[1] != 0x23456781 ||
767       our_uint64_array[2] != 0x34567812 ||
768       our_uint64_array[3] != 0x45678123)
769     _dbus_assert_not_reached ("uint64 array differs");
770
771   if (our_int64_array_len != 4 ||
772       our_int64_array[0] != 0x12345678 ||
773       our_int64_array[1] != -0x23456781 ||
774       our_int64_array[2] != 0x34567812 ||
775       our_int64_array[3] != -0x45678123)
776     _dbus_assert_not_reached ("int64 array differs");
777 #endif /* DBUS_HAVE_INT64 */
778
779   if (our_double_array_len != 3)
780     _dbus_assert_not_reached ("double array had wrong length");
781
782   /* On all IEEE machines (i.e. everything sane) exact equality
783    * should be preserved over the wire
784    */
785   if (our_double_array[0] != 0.1234 ||
786       our_double_array[1] != 9876.54321 ||
787       our_double_array[2] != -300.0)
788     _dbus_assert_not_reached ("double array had wrong values");
789
790   if (our_byte_array_len != 4)
791     _dbus_assert_not_reached ("byte array had wrong length");
792
793   if (our_byte_array[0] != 'a' ||
794       our_byte_array[1] != 'b' ||
795       our_byte_array[2] != 'c' ||
796       our_byte_array[3] != 234)
797     _dbus_assert_not_reached ("byte array had wrong values");
798
799   if (our_boolean_array_len != 5)
800     _dbus_assert_not_reached ("bool array had wrong length");
801
802   if (our_boolean_array[0] != TRUE ||
803       our_boolean_array[1] != FALSE ||
804       our_boolean_array[2] != TRUE ||
805       our_boolean_array[3] != TRUE ||
806       our_boolean_array[4] != FALSE)
807     _dbus_assert_not_reached ("bool array had wrong values");
808
809   if (dbus_message_iter_next (&iter))
810     _dbus_assert_not_reached ("Didn't reach end of arguments");
811 }
812
813 /**
814  * @ingroup DBusMessageInternals
815  * Unit test for DBusMessage.
816  *
817  * @returns #TRUE on success.
818  */
819 dbus_bool_t
820 _dbus_message_test (const char *test_data_dir)
821 {
822   DBusMessage *message;
823   DBusMessageLoader *loader;
824   DBusMessageIter iter, child_iter, child_iter2, child_iter3;
825   int i;
826   const char *data;
827   DBusMessage *copy;
828   const char *name1;
829   const char *name2;
830   const dbus_uint32_t our_uint32_array[] =
831     { 0x12345678, 0x23456781, 0x34567812, 0x45678123 };
832   const dbus_uint32_t our_int32_array[] =
833     { 0x12345678, -0x23456781, 0x34567812, -0x45678123 };
834   const dbus_uint32_t *v_ARRAY_UINT32 = our_uint32_array;
835   const dbus_int32_t *v_ARRAY_INT32 = our_int32_array;
836 #ifdef DBUS_HAVE_INT64
837   const dbus_uint64_t our_uint64_array[] =
838     { 0x12345678, 0x23456781, 0x34567812, 0x45678123 };
839   const dbus_uint64_t our_int64_array[] =
840     { 0x12345678, -0x23456781, 0x34567812, -0x45678123 };
841   const dbus_uint64_t *v_ARRAY_UINT64 = our_uint64_array;
842   const dbus_int64_t *v_ARRAY_INT64 = our_int64_array;
843 #endif
844   const char *our_string_array[] = { "Foo", "bar", "", "woo woo woo woo" };
845   const char **v_ARRAY_STRING = our_string_array;
846   const double our_double_array[] = { 0.1234, 9876.54321, -300.0 };
847   const double *v_ARRAY_DOUBLE = our_double_array;
848   const unsigned char our_byte_array[] = { 'a', 'b', 'c', 234 };
849   const unsigned char *v_ARRAY_BYTE = our_byte_array;
850   const dbus_bool_t our_boolean_array[] = { TRUE, FALSE, TRUE, TRUE, FALSE };
851   const dbus_bool_t *v_ARRAY_BOOLEAN = our_boolean_array;
852   char sig[64];
853   const char *s;
854   char *t;
855   DBusError error;
856   const char *v_STRING;
857   double v_DOUBLE;
858   dbus_int32_t v_INT32;
859   dbus_uint32_t v_UINT32;
860 #ifdef DBUS_HAVE_INT64
861   dbus_int64_t v_INT64;
862   dbus_uint64_t v_UINT64;
863 #endif
864   unsigned char v_BYTE;
865   unsigned char v2_BYTE;
866   dbus_bool_t v_BOOLEAN;
867
868   message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService",
869                                           "/org/freedesktop/TestPath",
870                                           "Foo.TestInterface",
871                                           "TestMethod");
872   _dbus_assert (dbus_message_has_destination (message, "org.freedesktop.DBus.TestService"));
873   _dbus_assert (dbus_message_is_method_call (message, "Foo.TestInterface",
874                                              "TestMethod"));
875   _dbus_assert (strcmp (dbus_message_get_path (message),
876                         "/org/freedesktop/TestPath") == 0);
877   _dbus_message_set_serial (message, 1234);
878
879   /* string length including nul byte not a multiple of 4 */
880   if (!dbus_message_set_sender (message, "org.foo.bar1"))
881     _dbus_assert_not_reached ("out of memory");
882
883   _dbus_assert (dbus_message_has_sender (message, "org.foo.bar1"));
884   dbus_message_set_reply_serial (message, 5678);
885
886   _dbus_verbose_bytes_of_string (&message->header.data, 0,
887                                  _dbus_string_get_length (&message->header.data));
888   _dbus_verbose_bytes_of_string (&message->body, 0,
889                                  _dbus_string_get_length (&message->body));
890
891   if (!dbus_message_set_sender (message, NULL))
892     _dbus_assert_not_reached ("out of memory");
893
894
895   _dbus_verbose_bytes_of_string (&message->header.data, 0,
896                                  _dbus_string_get_length (&message->header.data));
897   _dbus_verbose_bytes_of_string (&message->body, 0,
898                                  _dbus_string_get_length (&message->body));
899
900
901   _dbus_assert (!dbus_message_has_sender (message, "org.foo.bar1"));
902   _dbus_assert (dbus_message_get_serial (message) == 1234);
903   _dbus_assert (dbus_message_get_reply_serial (message) == 5678);
904   _dbus_assert (dbus_message_has_destination (message, "org.freedesktop.DBus.TestService"));
905
906   _dbus_assert (dbus_message_get_no_reply (message) == FALSE);
907   dbus_message_set_no_reply (message, TRUE);
908   _dbus_assert (dbus_message_get_no_reply (message) == TRUE);
909   dbus_message_set_no_reply (message, FALSE);
910   _dbus_assert (dbus_message_get_no_reply (message) == FALSE);
911
912   /* Set/get some header fields */
913
914   if (!dbus_message_set_path (message, "/foo"))
915     _dbus_assert_not_reached ("out of memory");
916   _dbus_assert (strcmp (dbus_message_get_path (message),
917                         "/foo") == 0);
918
919   if (!dbus_message_set_interface (message, "org.Foo"))
920     _dbus_assert_not_reached ("out of memory");
921   _dbus_assert (strcmp (dbus_message_get_interface (message),
922                         "org.Foo") == 0);
923
924   if (!dbus_message_set_member (message, "Bar"))
925     _dbus_assert_not_reached ("out of memory");
926   _dbus_assert (strcmp (dbus_message_get_member (message),
927                         "Bar") == 0);
928
929   /* Set/get them with longer values */
930   if (!dbus_message_set_path (message, "/foo/bar"))
931     _dbus_assert_not_reached ("out of memory");
932   _dbus_assert (strcmp (dbus_message_get_path (message),
933                         "/foo/bar") == 0);
934
935   if (!dbus_message_set_interface (message, "org.Foo.Bar"))
936     _dbus_assert_not_reached ("out of memory");
937   _dbus_assert (strcmp (dbus_message_get_interface (message),
938                         "org.Foo.Bar") == 0);
939
940   if (!dbus_message_set_member (message, "BarFoo"))
941     _dbus_assert_not_reached ("out of memory");
942   _dbus_assert (strcmp (dbus_message_get_member (message),
943                         "BarFoo") == 0);
944
945   /* Realloc shorter again */
946
947   if (!dbus_message_set_path (message, "/foo"))
948     _dbus_assert_not_reached ("out of memory");
949   _dbus_assert (strcmp (dbus_message_get_path (message),
950                         "/foo") == 0);
951
952   if (!dbus_message_set_interface (message, "org.Foo"))
953     _dbus_assert_not_reached ("out of memory");
954   _dbus_assert (strcmp (dbus_message_get_interface (message),
955                         "org.Foo") == 0);
956
957   if (!dbus_message_set_member (message, "Bar"))
958     _dbus_assert_not_reached ("out of memory");
959   _dbus_assert (strcmp (dbus_message_get_member (message),
960                         "Bar") == 0);
961
962   dbus_message_unref (message);
963
964   /* Test the vararg functions */
965   message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService",
966                                           "/org/freedesktop/TestPath",
967                                           "Foo.TestInterface",
968                                           "TestMethod");
969   _dbus_message_set_serial (message, 1);
970
971   v_INT32 = -0x12345678;
972 #ifdef DBUS_HAVE_INT64
973   v_INT64 = DBUS_INT64_CONSTANT (-0x123456789abcd);
974   v_UINT64 = DBUS_UINT64_CONSTANT (0x123456789abcd);
975 #endif
976   v_STRING = "Test string";
977   v_DOUBLE = 3.14159;
978   v_BOOLEAN = TRUE;
979   v_BYTE = 42;
980   v2_BYTE = 24;
981
982   dbus_message_append_args (message,
983                             DBUS_TYPE_INT32, &v_INT32,
984 #ifdef DBUS_HAVE_INT64
985                             DBUS_TYPE_INT64, &v_INT64,
986                             DBUS_TYPE_UINT64, &v_UINT64,
987 #endif
988                             DBUS_TYPE_STRING, &v_STRING,
989                             DBUS_TYPE_DOUBLE, &v_DOUBLE,
990                             DBUS_TYPE_BOOLEAN, &v_BOOLEAN,
991                             DBUS_TYPE_BYTE, &v_BYTE,
992                             DBUS_TYPE_BYTE, &v2_BYTE,
993                             DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &v_ARRAY_UINT32,
994                             _DBUS_N_ELEMENTS (our_uint32_array),
995                             DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, &v_ARRAY_INT32,
996                             _DBUS_N_ELEMENTS (our_int32_array),
997 #ifdef DBUS_HAVE_INT64
998                             DBUS_TYPE_ARRAY, DBUS_TYPE_UINT64, &v_ARRAY_UINT64,
999                             _DBUS_N_ELEMENTS (our_uint64_array),
1000                             DBUS_TYPE_ARRAY, DBUS_TYPE_INT64, &v_ARRAY_INT64,
1001                             _DBUS_N_ELEMENTS (our_int64_array),
1002 #endif
1003                             DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE, &v_ARRAY_DOUBLE,
1004                             _DBUS_N_ELEMENTS (our_double_array),
1005                             DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &v_ARRAY_BYTE,
1006                             _DBUS_N_ELEMENTS (our_byte_array),
1007                             DBUS_TYPE_ARRAY, DBUS_TYPE_BOOLEAN, &v_ARRAY_BOOLEAN,
1008                             _DBUS_N_ELEMENTS (our_boolean_array),
1009                             DBUS_TYPE_INVALID);
1010
1011   i = 0;
1012   sig[i++] = DBUS_TYPE_INT32;
1013 #ifdef DBUS_HAVE_INT64
1014   sig[i++] = DBUS_TYPE_INT64;
1015   sig[i++] = DBUS_TYPE_UINT64;
1016 #endif
1017   sig[i++] = DBUS_TYPE_STRING;
1018   sig[i++] = DBUS_TYPE_DOUBLE;
1019   sig[i++] = DBUS_TYPE_BOOLEAN;
1020   sig[i++] = DBUS_TYPE_BYTE;
1021   sig[i++] = DBUS_TYPE_BYTE;
1022   sig[i++] = DBUS_TYPE_ARRAY;
1023   sig[i++] = DBUS_TYPE_UINT32;
1024   sig[i++] = DBUS_TYPE_ARRAY;
1025   sig[i++] = DBUS_TYPE_INT32;
1026 #ifdef DBUS_HAVE_INT64
1027   sig[i++] = DBUS_TYPE_ARRAY;
1028   sig[i++] = DBUS_TYPE_UINT64;
1029   sig[i++] = DBUS_TYPE_ARRAY;
1030   sig[i++] = DBUS_TYPE_INT64;
1031 #endif
1032   sig[i++] = DBUS_TYPE_ARRAY;
1033   sig[i++] = DBUS_TYPE_DOUBLE;
1034   sig[i++] = DBUS_TYPE_ARRAY;
1035   sig[i++] = DBUS_TYPE_BYTE;
1036   sig[i++] = DBUS_TYPE_ARRAY;
1037   sig[i++] = DBUS_TYPE_BOOLEAN;
1038   sig[i++] = DBUS_TYPE_INVALID;
1039
1040   _dbus_assert (i < (int) _DBUS_N_ELEMENTS (sig));
1041
1042   _dbus_verbose ("HEADER\n");
1043   _dbus_verbose_bytes_of_string (&message->header.data, 0,
1044                                  _dbus_string_get_length (&message->header.data));
1045   _dbus_verbose ("BODY\n");
1046   _dbus_verbose_bytes_of_string (&message->body, 0,
1047                                  _dbus_string_get_length (&message->body));
1048
1049   _dbus_verbose ("Signature expected \"%s\" actual \"%s\"\n",
1050                  sig, dbus_message_get_signature (message));
1051
1052   s = dbus_message_get_signature (message);
1053
1054   _dbus_assert (dbus_message_has_signature (message, sig));
1055   _dbus_assert (strcmp (s, sig) == 0);
1056
1057   verify_test_message (message);
1058
1059   copy = dbus_message_copy (message);
1060
1061   _dbus_assert (dbus_message_get_reply_serial (message) ==
1062                 dbus_message_get_reply_serial (copy));
1063   _dbus_assert (message->header.padding == copy->header.padding);
1064
1065   _dbus_assert (_dbus_string_get_length (&message->header.data) ==
1066                 _dbus_string_get_length (&copy->header.data));
1067
1068   _dbus_assert (_dbus_string_get_length (&message->body) ==
1069                 _dbus_string_get_length (&copy->body));
1070
1071   verify_test_message (copy);
1072
1073   name1 = dbus_message_get_interface (message);
1074   name2 = dbus_message_get_interface (copy);
1075
1076   _dbus_assert (strcmp (name1, name2) == 0);
1077
1078   name1 = dbus_message_get_member (message);
1079   name2 = dbus_message_get_member (copy);
1080
1081   _dbus_assert (strcmp (name1, name2) == 0);
1082
1083   dbus_message_unref (copy);
1084
1085   /* Message loader test */
1086   _dbus_message_lock (message);
1087   loader = _dbus_message_loader_new ();
1088   
1089   /* check ref/unref */
1090   _dbus_message_loader_ref (loader);
1091   _dbus_message_loader_unref (loader);
1092
1093   /* Write the header data one byte at a time */
1094   data = _dbus_string_get_const_data (&message->header.data);
1095   for (i = 0; i < _dbus_string_get_length (&message->header.data); i++)
1096     {
1097       DBusString *buffer;
1098
1099       _dbus_message_loader_get_buffer (loader, &buffer);
1100       _dbus_string_append_byte (buffer, data[i]);
1101       _dbus_message_loader_return_buffer (loader, buffer, 1);
1102     }
1103
1104   /* Write the body data one byte at a time */
1105   data = _dbus_string_get_const_data (&message->body);
1106   for (i = 0; i < _dbus_string_get_length (&message->body); i++)
1107     {
1108       DBusString *buffer;
1109
1110       _dbus_message_loader_get_buffer (loader, &buffer);
1111       _dbus_string_append_byte (buffer, data[i]);
1112       _dbus_message_loader_return_buffer (loader, buffer, 1);
1113     }
1114
1115   dbus_message_unref (message);
1116
1117   /* Now pop back the message */
1118   if (!_dbus_message_loader_queue_messages (loader))
1119     _dbus_assert_not_reached ("no memory to queue messages");
1120
1121   if (_dbus_message_loader_get_is_corrupted (loader))
1122     _dbus_assert_not_reached ("message loader corrupted");
1123
1124   message = _dbus_message_loader_pop_message (loader);
1125   if (!message)
1126     _dbus_assert_not_reached ("received a NULL message");
1127
1128   if (dbus_message_get_reply_serial (message) != 0x12345678)
1129     _dbus_assert_not_reached ("reply serial fields differ");
1130
1131   verify_test_message (message);
1132
1133   dbus_message_unref (message);
1134   _dbus_message_loader_unref (loader);
1135
1136
1137   /* Now load every message in test_data_dir if we have one */
1138   if (test_data_dir == NULL)
1139     return TRUE;
1140
1141   return dbus_internal_do_not_use_foreach_message_file (test_data_dir,
1142                                                         (DBusForeachMessageFileFunc)
1143                                                         dbus_internal_do_not_use_try_message_file,
1144                                                         NULL);  
1145 }
1146
1147 #endif /* DBUS_BUILD_TESTS */