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