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