2006-10-21 Havoc Pennington <hp@redhat.com>
[platform/upstream/dbus.git] / dbus / dbus-message-factory.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-message-factory.c Generator of valid and invalid message data for test suite
3  *
4  * Copyright (C) 2005 Red Hat Inc.
5  *
6  * Licensed under the Academic Free License version 2.1
7  * 
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  * 
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23 #include <config.h>
24
25 #ifndef DOXYGEN_SHOULD_SKIP_THIS
26
27 #ifdef DBUS_BUILD_TESTS
28 #include "dbus-message-factory.h"
29 #include "dbus-message-private.h"
30 #include "dbus-test.h"
31 #include <stdio.h>
32
33 typedef enum
34   {
35     CHANGE_TYPE_ADJUST,
36     CHANGE_TYPE_ABSOLUTE
37   } ChangeType;
38
39 #define BYTE_ORDER_OFFSET  0
40 #define TYPE_OFFSET        1
41 #define BODY_LENGTH_OFFSET 4
42 #define FIELDS_ARRAY_LENGTH_OFFSET 12
43
44 static void
45 iter_recurse (DBusMessageDataIter *iter)
46 {
47   iter->depth += 1;
48   _dbus_assert (iter->depth < _DBUS_MESSAGE_DATA_MAX_NESTING);
49   _dbus_assert (iter->sequence_nos[iter->depth] >= 0);
50 }
51
52 static int
53 iter_get_sequence (DBusMessageDataIter *iter)
54 {
55   _dbus_assert (iter->sequence_nos[iter->depth] >= 0);
56   return iter->sequence_nos[iter->depth];
57 }
58
59 static void
60 iter_set_sequence (DBusMessageDataIter *iter,
61                    int                  sequence)
62 {
63   _dbus_assert (sequence >= 0);
64   iter->sequence_nos[iter->depth] = sequence;
65 }
66
67 static void
68 iter_unrecurse (DBusMessageDataIter *iter)
69 {
70   iter->depth -= 1;
71   _dbus_assert (iter->depth >= 0);
72 }
73
74 static void
75 iter_next (DBusMessageDataIter *iter)
76 {
77   iter->sequence_nos[iter->depth] += 1;
78 }
79
80 static dbus_bool_t
81 iter_first_in_series (DBusMessageDataIter *iter)
82 {
83   int i;
84
85   i = iter->depth;
86   while (i < _DBUS_MESSAGE_DATA_MAX_NESTING)
87     {
88       if (iter->sequence_nos[i] != 0)
89         return FALSE;
90       ++i;
91     }
92   return TRUE;
93 }
94
95 typedef dbus_bool_t (* DBusInnerGeneratorFunc)   (DBusMessageDataIter *iter,
96                                                   DBusMessage        **message_p);
97 typedef dbus_bool_t (* DBusMessageGeneratorFunc) (DBusMessageDataIter *iter,
98                                                   DBusString          *data,
99                                                   DBusValidity        *expected_validity);
100
101 static void
102 set_reply_serial (DBusMessage *message)
103 {
104   if (message == NULL)
105     _dbus_assert_not_reached ("oom");
106   if (!dbus_message_set_reply_serial (message, 100))
107     _dbus_assert_not_reached ("oom");
108 }
109
110 static dbus_bool_t
111 generate_trivial_inner (DBusMessageDataIter *iter,
112                         DBusMessage        **message_p)
113 {
114   DBusMessage *message;
115
116   switch (iter_get_sequence (iter))
117     {
118     case 0:
119       message = dbus_message_new_method_call ("org.freedesktop.TextEditor",
120                                               "/foo/bar",
121                                               "org.freedesktop.DocumentFactory",
122                                               "Create");
123       break;
124     case 1:
125       message = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_RETURN);
126       set_reply_serial (message);
127       break;
128     case 2:
129       message = dbus_message_new_signal ("/foo/bar",
130                                          "org.freedesktop.DocumentFactory",
131                                          "Created");
132       break;
133     case 3:
134       message = dbus_message_new (DBUS_MESSAGE_TYPE_ERROR);
135
136       if (!dbus_message_set_error_name (message,
137                                         "org.freedesktop.TestErrorName"))
138         _dbus_assert_not_reached ("oom");
139       
140       {
141         DBusMessageIter iter;
142         const char *v_STRING = "This is an error";
143         
144         dbus_message_iter_init_append (message, &iter);
145         if (!dbus_message_iter_append_basic (&iter,
146                                              DBUS_TYPE_STRING,
147                                              &v_STRING))
148           _dbus_assert_not_reached ("oom");
149       }
150       
151       set_reply_serial (message);
152       break;
153     default:
154       return FALSE;
155     }
156   
157   if (message == NULL)
158     _dbus_assert_not_reached ("oom");
159
160   *message_p = message;
161   
162   return TRUE;
163 }
164
165 static dbus_bool_t
166 generate_many_bodies_inner (DBusMessageDataIter *iter,
167                             DBusMessage        **message_p)
168 {
169   DBusMessage *message;
170   DBusString signature;
171   DBusString body;
172
173   /* Keeping this small makes things go faster */
174   message = dbus_message_new_method_call ("o.z.F",
175                                           "/",
176                                           "o.z.B",
177                                           "Nah");
178   if (message == NULL)
179     _dbus_assert_not_reached ("oom");
180
181   set_reply_serial (message);
182
183   if (!_dbus_string_init (&signature) || !_dbus_string_init (&body))
184     _dbus_assert_not_reached ("oom");
185   
186   if (dbus_internal_do_not_use_generate_bodies (iter_get_sequence (iter),
187                                                 message->byte_order,
188                                                 &signature, &body))
189     {
190       const char *v_SIGNATURE;
191
192       v_SIGNATURE = _dbus_string_get_const_data (&signature);
193       if (!_dbus_header_set_field_basic (&message->header,
194                                          DBUS_HEADER_FIELD_SIGNATURE,
195                                          DBUS_TYPE_SIGNATURE,
196                                          &v_SIGNATURE))
197         _dbus_assert_not_reached ("oom");
198
199       if (!_dbus_string_move (&body, 0, &message->body, 0))
200         _dbus_assert_not_reached ("oom");
201
202       _dbus_marshal_set_uint32 (&message->header.data, BODY_LENGTH_OFFSET,
203                                 _dbus_string_get_length (&message->body),
204                                 message->byte_order);
205       
206       *message_p = message;
207     }
208   else
209     {
210       dbus_message_unref (message);
211       *message_p = NULL;
212     }
213   
214   _dbus_string_free (&signature);
215   _dbus_string_free (&body);
216
217   return *message_p != NULL;
218 }
219
220 static void
221 generate_from_message (DBusString            *data,
222                        DBusValidity          *expected_validity,
223                        DBusMessage           *message)
224 {
225   _dbus_message_set_serial (message, 1);
226   _dbus_message_lock (message);
227
228   *expected_validity = DBUS_VALID;
229   
230   /* move for efficiency, since we'll nuke the message anyway */
231   if (!_dbus_string_move (&message->header.data, 0,
232                           data, 0))
233     _dbus_assert_not_reached ("oom");
234
235   if (!_dbus_string_copy (&message->body, 0,
236                           data, _dbus_string_get_length (data)))
237     _dbus_assert_not_reached ("oom");
238 }
239
240 static dbus_bool_t
241 generate_outer (DBusMessageDataIter   *iter,
242                 DBusString            *data,
243                 DBusValidity          *expected_validity,
244                 DBusInnerGeneratorFunc func)
245 {
246   DBusMessage *message;
247
248   message = NULL;
249   if (!(*func)(iter, &message))
250     return FALSE;
251
252   iter_next (iter);
253   
254   _dbus_assert (message != NULL);
255
256   generate_from_message (data, expected_validity, message);
257
258   dbus_message_unref (message);
259
260   return TRUE;
261 }
262
263 static dbus_bool_t
264 generate_trivial (DBusMessageDataIter   *iter,
265                   DBusString            *data,
266                   DBusValidity          *expected_validity)
267 {
268   return generate_outer (iter, data, expected_validity,
269                          generate_trivial_inner);
270 }
271
272 static dbus_bool_t
273 generate_many_bodies (DBusMessageDataIter   *iter,
274                       DBusString            *data,
275                       DBusValidity          *expected_validity)
276 {
277   return generate_outer (iter, data, expected_validity,
278                          generate_many_bodies_inner);
279 }
280
281 static DBusMessage*
282 simple_method_call (void)
283 {
284   DBusMessage *message;
285   /* Keeping this small makes stuff go faster */
286   message = dbus_message_new_method_call ("o.b.Q",
287                                           "/f/b",
288                                           "o.b.Z",
289                                           "Fro");
290   if (message == NULL)
291     _dbus_assert_not_reached ("oom");
292   return message;
293 }
294
295 static DBusMessage*
296 simple_signal (void)
297 {
298   DBusMessage *message;
299   message = dbus_message_new_signal ("/f/b",
300                                      "o.b.Z",
301                                      "Fro");
302   if (message == NULL)
303     _dbus_assert_not_reached ("oom");
304   return message;
305 }
306
307 static DBusMessage*
308 simple_method_return (void)
309 {
310   DBusMessage *message;
311   message =  dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_RETURN);
312   if (message == NULL)
313     _dbus_assert_not_reached ("oom");
314
315   set_reply_serial (message);
316   
317   return message;
318 }
319
320 static DBusMessage*
321 simple_error (void)
322 {
323   DBusMessage *message;
324   message =  dbus_message_new (DBUS_MESSAGE_TYPE_ERROR);
325   if (message == NULL)
326     _dbus_assert_not_reached ("oom");
327
328   if (!dbus_message_set_error_name (message, "foo.bar"))
329     _dbus_assert_not_reached ("oom");
330   
331   set_reply_serial (message);
332   
333   return message;
334 }
335
336 static dbus_bool_t
337 generate_special (DBusMessageDataIter   *iter,
338                   DBusString            *data,
339                   DBusValidity          *expected_validity)
340 {
341   int item_seq;
342   DBusMessage *message;
343   int pos;
344   dbus_int32_t v_INT32;
345
346   _dbus_assert (_dbus_string_get_length (data) == 0);
347   
348   message = NULL;
349   pos = -1;
350   v_INT32 = 42;
351   item_seq = iter_get_sequence (iter);
352
353   if (item_seq == 0)
354     {
355       message = simple_method_call ();
356       if (!dbus_message_append_args (message,
357                                      DBUS_TYPE_INT32, &v_INT32,
358                                      DBUS_TYPE_INT32, &v_INT32,
359                                      DBUS_TYPE_INT32, &v_INT32,
360                                      DBUS_TYPE_INVALID))
361         _dbus_assert_not_reached ("oom");
362                                      
363       _dbus_header_get_field_raw (&message->header,
364                                   DBUS_HEADER_FIELD_SIGNATURE,
365                                   NULL, &pos);
366       generate_from_message (data, expected_validity, message);
367       
368       /* set an invalid typecode */
369       _dbus_string_set_byte (data, pos + 1, '$');
370
371       *expected_validity = DBUS_INVALID_UNKNOWN_TYPECODE;
372     }
373   else if (item_seq == 1)
374     {
375       char long_sig[DBUS_MAXIMUM_TYPE_RECURSION_DEPTH+2];
376       const char *v_STRING;
377       int i;
378       
379       message = simple_method_call ();
380       if (!dbus_message_append_args (message,
381                                      DBUS_TYPE_INT32, &v_INT32,
382                                      DBUS_TYPE_INT32, &v_INT32,
383                                      DBUS_TYPE_INT32, &v_INT32,
384                                      DBUS_TYPE_INVALID))
385         _dbus_assert_not_reached ("oom");
386
387       i = 0;
388       while (i < (DBUS_MAXIMUM_TYPE_RECURSION_DEPTH + 1))
389         {
390           long_sig[i] = DBUS_TYPE_ARRAY;
391           ++i;
392         }
393       long_sig[i] = DBUS_TYPE_INVALID;
394
395       v_STRING = long_sig;
396       if (!_dbus_header_set_field_basic (&message->header,
397                                          DBUS_HEADER_FIELD_SIGNATURE,
398                                          DBUS_TYPE_SIGNATURE,
399                                          &v_STRING))
400         _dbus_assert_not_reached ("oom");
401       
402       _dbus_header_get_field_raw (&message->header,
403                                   DBUS_HEADER_FIELD_SIGNATURE,
404                                   NULL, &pos);
405       generate_from_message (data, expected_validity, message);
406       
407       *expected_validity = DBUS_INVALID_EXCEEDED_MAXIMUM_ARRAY_RECURSION;
408     }
409   else if (item_seq == 2)
410     {
411       char long_sig[DBUS_MAXIMUM_TYPE_RECURSION_DEPTH*2+4];
412       const char *v_STRING;
413       int i;
414       
415       message = simple_method_call ();
416       if (!dbus_message_append_args (message,
417                                      DBUS_TYPE_INT32, &v_INT32,
418                                      DBUS_TYPE_INT32, &v_INT32,
419                                      DBUS_TYPE_INT32, &v_INT32,
420                                      DBUS_TYPE_INVALID))
421         _dbus_assert_not_reached ("oom");
422
423       i = 0;
424       while (i <= (DBUS_MAXIMUM_TYPE_RECURSION_DEPTH + 1))
425         {
426           long_sig[i] = DBUS_STRUCT_BEGIN_CHAR;
427           ++i;
428         }
429
430       long_sig[i] = DBUS_TYPE_INT32;
431       ++i;
432
433       while (i < (DBUS_MAXIMUM_TYPE_RECURSION_DEPTH*2 + 3))
434         {
435           long_sig[i] = DBUS_STRUCT_END_CHAR;
436           ++i;
437         }
438       long_sig[i] = DBUS_TYPE_INVALID;
439       
440       v_STRING = long_sig;
441       if (!_dbus_header_set_field_basic (&message->header,
442                                          DBUS_HEADER_FIELD_SIGNATURE,
443                                          DBUS_TYPE_SIGNATURE,
444                                          &v_STRING))
445         _dbus_assert_not_reached ("oom");
446       
447       _dbus_header_get_field_raw (&message->header,
448                                   DBUS_HEADER_FIELD_SIGNATURE,
449                                   NULL, &pos);
450       generate_from_message (data, expected_validity, message);
451       
452       *expected_validity = DBUS_INVALID_EXCEEDED_MAXIMUM_STRUCT_RECURSION;
453     }
454   else if (item_seq == 3)
455     {
456       message = simple_method_call ();
457       if (!dbus_message_append_args (message,
458                                      DBUS_TYPE_INT32, &v_INT32,
459                                      DBUS_TYPE_INT32, &v_INT32,
460                                      DBUS_TYPE_INT32, &v_INT32,
461                                      DBUS_TYPE_INVALID))
462         _dbus_assert_not_reached ("oom");
463                                      
464       _dbus_header_get_field_raw (&message->header,
465                                   DBUS_HEADER_FIELD_SIGNATURE,
466                                   NULL, &pos);
467       generate_from_message (data, expected_validity, message);
468       
469       _dbus_string_set_byte (data, pos + 1, DBUS_STRUCT_BEGIN_CHAR);
470       
471       *expected_validity = DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED;
472     }
473   else if (item_seq == 4)
474     {
475       message = simple_method_call ();
476       if (!dbus_message_append_args (message,
477                                      DBUS_TYPE_INT32, &v_INT32,
478                                      DBUS_TYPE_INT32, &v_INT32,
479                                      DBUS_TYPE_INT32, &v_INT32,
480                                      DBUS_TYPE_INVALID))
481         _dbus_assert_not_reached ("oom");
482                                      
483       _dbus_header_get_field_raw (&message->header,
484                                   DBUS_HEADER_FIELD_SIGNATURE,
485                                   NULL, &pos);
486       generate_from_message (data, expected_validity, message);
487       
488       _dbus_string_set_byte (data, pos + 1, DBUS_STRUCT_END_CHAR);
489       
490       *expected_validity = DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED;
491     }
492   else if (item_seq == 5)
493     {
494       message = simple_method_call ();
495       if (!dbus_message_append_args (message,
496                                      DBUS_TYPE_INT32, &v_INT32,
497                                      DBUS_TYPE_INT32, &v_INT32,
498                                      DBUS_TYPE_INT32, &v_INT32,
499                                      DBUS_TYPE_INVALID))
500         _dbus_assert_not_reached ("oom");
501                                      
502       _dbus_header_get_field_raw (&message->header,
503                                   DBUS_HEADER_FIELD_SIGNATURE,
504                                   NULL, &pos);
505       generate_from_message (data, expected_validity, message);
506       
507       _dbus_string_set_byte (data, pos + 1, DBUS_STRUCT_BEGIN_CHAR);
508       _dbus_string_set_byte (data, pos + 2, DBUS_STRUCT_END_CHAR);
509       
510       *expected_validity = DBUS_INVALID_STRUCT_HAS_NO_FIELDS;
511     }
512   else if (item_seq == 6)
513     {
514       message = simple_method_call ();
515       generate_from_message (data, expected_validity, message);
516       
517       _dbus_string_set_byte (data, TYPE_OFFSET, DBUS_MESSAGE_TYPE_INVALID);
518       
519       *expected_validity = DBUS_INVALID_BAD_MESSAGE_TYPE;
520     }
521   else if (item_seq == 7)
522     {
523       /* Messages of unknown type are considered valid */
524       message = simple_method_call ();
525       generate_from_message (data, expected_validity, message);
526       
527       _dbus_string_set_byte (data, TYPE_OFFSET, 100);
528       
529       *expected_validity = DBUS_VALID;
530     }
531   else if (item_seq == 8)
532     {
533       message = simple_method_call ();
534       generate_from_message (data, expected_validity, message);
535       
536       _dbus_marshal_set_uint32 (data, BODY_LENGTH_OFFSET,
537                                 DBUS_MAXIMUM_MESSAGE_LENGTH / 2 + 4,
538                                 message->byte_order);
539       _dbus_marshal_set_uint32 (data, FIELDS_ARRAY_LENGTH_OFFSET,
540                                 DBUS_MAXIMUM_MESSAGE_LENGTH / 2 + 4,
541                                 message->byte_order);
542       *expected_validity = DBUS_INVALID_MESSAGE_TOO_LONG;
543     }
544   else if (item_seq == 9)
545     {
546       const char *v_STRING = "not a valid bus name";
547       message = simple_method_call ();
548
549       if (!_dbus_header_set_field_basic (&message->header,
550                                          DBUS_HEADER_FIELD_SENDER,
551                                          DBUS_TYPE_STRING, &v_STRING))
552         _dbus_assert_not_reached ("oom");
553       
554       generate_from_message (data, expected_validity, message);
555
556       *expected_validity = DBUS_INVALID_BAD_SENDER;
557     }
558   else if (item_seq == 10)
559     {
560       message = simple_method_call ();
561
562       if (!dbus_message_set_interface (message, DBUS_INTERFACE_LOCAL))
563         _dbus_assert_not_reached ("oom");
564       
565       generate_from_message (data, expected_validity, message);
566
567       *expected_validity = DBUS_INVALID_USES_LOCAL_INTERFACE;
568     }
569   else if (item_seq == 11)
570     {
571       message = simple_method_call ();
572
573       if (!dbus_message_set_path (message, DBUS_PATH_LOCAL))
574         _dbus_assert_not_reached ("oom");
575       
576       generate_from_message (data, expected_validity, message);
577
578       *expected_validity = DBUS_INVALID_USES_LOCAL_PATH;
579     }
580   else if (item_seq == 12)
581     {
582       /* Method calls don't have to have interface */
583       message = simple_method_call ();
584
585       if (!dbus_message_set_interface (message, NULL))
586         _dbus_assert_not_reached ("oom");
587       
588       generate_from_message (data, expected_validity, message);
589       
590       *expected_validity = DBUS_VALID;
591     }
592   else if (item_seq == 13)
593     {
594       /* Signals require an interface */
595       message = simple_signal ();
596
597       if (!dbus_message_set_interface (message, NULL))
598         _dbus_assert_not_reached ("oom");
599       
600       generate_from_message (data, expected_validity, message);
601       
602       *expected_validity = DBUS_INVALID_MISSING_INTERFACE;
603     }
604   else if (item_seq == 14)
605     {
606       message = simple_method_return ();
607
608       if (!_dbus_header_delete_field (&message->header, DBUS_HEADER_FIELD_REPLY_SERIAL))
609         _dbus_assert_not_reached ("oom");
610       
611       generate_from_message (data, expected_validity, message);
612       
613       *expected_validity = DBUS_INVALID_MISSING_REPLY_SERIAL;
614     }
615   else if (item_seq == 15)
616     {
617       message = simple_error ();
618
619       if (!dbus_message_set_error_name (message, NULL))
620         _dbus_assert_not_reached ("oom");
621       
622       generate_from_message (data, expected_validity, message);
623       
624       *expected_validity = DBUS_INVALID_MISSING_ERROR_NAME;
625     }
626   else if (item_seq == 16)
627     {
628       char long_sig[DBUS_MAXIMUM_TYPE_RECURSION_DEPTH*4+10];
629       const char *v_STRING;
630       int i;
631       int n_begins;
632       
633       message = simple_method_call ();
634       if (!dbus_message_append_args (message,
635                                      DBUS_TYPE_INT32, &v_INT32,
636                                      DBUS_TYPE_INT32, &v_INT32,
637                                      DBUS_TYPE_INT32, &v_INT32,
638                                      DBUS_TYPE_INVALID))
639         _dbus_assert_not_reached ("oom");
640
641       i = 0;
642       while (i <= (DBUS_MAXIMUM_TYPE_RECURSION_DEPTH*3 + 3))
643         {
644           long_sig[i] = DBUS_TYPE_ARRAY;
645           ++i;
646           long_sig[i] = DBUS_DICT_ENTRY_BEGIN_CHAR;
647           ++i;
648           long_sig[i] = DBUS_TYPE_INT32;
649           ++i;
650         }
651       n_begins = i / 3;
652
653       long_sig[i] = DBUS_TYPE_INT32;
654       ++i;
655       
656       while (n_begins > 0)
657         {
658           long_sig[i] = DBUS_DICT_ENTRY_END_CHAR;
659           ++i;
660           n_begins -= 1;
661         }
662       long_sig[i] = DBUS_TYPE_INVALID;
663       
664       v_STRING = long_sig;
665       if (!_dbus_header_set_field_basic (&message->header,
666                                          DBUS_HEADER_FIELD_SIGNATURE,
667                                          DBUS_TYPE_SIGNATURE,
668                                          &v_STRING))
669         _dbus_assert_not_reached ("oom");
670       
671       _dbus_header_get_field_raw (&message->header,
672                                   DBUS_HEADER_FIELD_SIGNATURE,
673                                   NULL, &pos);
674       generate_from_message (data, expected_validity, message);
675       
676       *expected_validity = DBUS_INVALID_EXCEEDED_MAXIMUM_DICT_ENTRY_RECURSION;
677     }
678   else if (item_seq == 17)
679     {
680       message = simple_method_call ();
681       if (!dbus_message_append_args (message,
682                                      DBUS_TYPE_INT32, &v_INT32,
683                                      DBUS_TYPE_INT32, &v_INT32,
684                                      DBUS_TYPE_INT32, &v_INT32,
685                                      DBUS_TYPE_INVALID))
686         _dbus_assert_not_reached ("oom");
687                                      
688       _dbus_header_get_field_raw (&message->header,
689                                   DBUS_HEADER_FIELD_SIGNATURE,
690                                   NULL, &pos);
691       generate_from_message (data, expected_validity, message);
692
693       _dbus_string_set_byte (data, pos + 1, DBUS_TYPE_ARRAY);
694       _dbus_string_set_byte (data, pos + 2, DBUS_DICT_ENTRY_BEGIN_CHAR);
695       
696       *expected_validity = DBUS_INVALID_DICT_ENTRY_STARTED_BUT_NOT_ENDED;
697     }
698   else if (item_seq == 18)
699     {
700       message = simple_method_call ();
701       if (!dbus_message_append_args (message,
702                                      DBUS_TYPE_INT32, &v_INT32,
703                                      DBUS_TYPE_INT32, &v_INT32,
704                                      DBUS_TYPE_INT32, &v_INT32,
705                                      DBUS_TYPE_INVALID))
706         _dbus_assert_not_reached ("oom");
707                                      
708       _dbus_header_get_field_raw (&message->header,
709                                   DBUS_HEADER_FIELD_SIGNATURE,
710                                   NULL, &pos);
711       generate_from_message (data, expected_validity, message);
712       
713       _dbus_string_set_byte (data, pos + 1, DBUS_DICT_ENTRY_END_CHAR);
714       
715       *expected_validity = DBUS_INVALID_DICT_ENTRY_ENDED_BUT_NOT_STARTED;
716     }
717   else if (item_seq == 19)
718     {
719       message = simple_method_call ();
720       if (!dbus_message_append_args (message,
721                                      DBUS_TYPE_INT32, &v_INT32,
722                                      DBUS_TYPE_INT32, &v_INT32,
723                                      DBUS_TYPE_INT32, &v_INT32,
724                                      DBUS_TYPE_INVALID))
725         _dbus_assert_not_reached ("oom");
726                                      
727       _dbus_header_get_field_raw (&message->header,
728                                   DBUS_HEADER_FIELD_SIGNATURE,
729                                   NULL, &pos);
730       generate_from_message (data, expected_validity, message);
731
732       _dbus_string_set_byte (data, pos + 1, DBUS_TYPE_ARRAY);
733       _dbus_string_set_byte (data, pos + 2, DBUS_DICT_ENTRY_BEGIN_CHAR);
734       _dbus_string_set_byte (data, pos + 3, DBUS_DICT_ENTRY_END_CHAR);
735       
736       *expected_validity = DBUS_INVALID_DICT_ENTRY_HAS_NO_FIELDS;
737     }
738   else
739     {
740       return FALSE;
741     }
742
743   if (message)
744     dbus_message_unref (message);
745
746   iter_next (iter);
747   return TRUE;
748 }
749
750 static dbus_bool_t
751 generate_wrong_length (DBusMessageDataIter *iter,
752                        DBusString          *data,
753                        DBusValidity        *expected_validity)
754 {
755   int lengths[] = { -42, -17, -16, -15, -9, -8, -7, -6, -5, -4, -3, -2, -1,
756                     1, 2, 3, 4, 5, 6, 7, 8, 9, 15, 16, 30 };
757   int adjust;
758   int len_seq;
759
760  restart:
761   len_seq = iter_get_sequence (iter);
762   if (len_seq == _DBUS_N_ELEMENTS (lengths))
763     return FALSE;
764
765   _dbus_assert (len_seq < _DBUS_N_ELEMENTS (lengths));
766   
767   iter_recurse (iter);
768   if (!generate_many_bodies (iter, data, expected_validity))
769     {
770       iter_set_sequence (iter, 0); /* reset to first body */
771       iter_unrecurse (iter);
772       iter_next (iter);            /* next length adjustment */
773       goto restart;
774     }
775   iter_unrecurse (iter);
776
777   adjust = lengths[len_seq];
778
779   if (adjust < 0)
780     {
781       if ((_dbus_string_get_length (data) + adjust) < DBUS_MINIMUM_HEADER_SIZE)
782         _dbus_string_set_length (data, DBUS_MINIMUM_HEADER_SIZE);
783       else
784         _dbus_string_shorten (data, - adjust);
785       *expected_validity = DBUS_INVALID_FOR_UNKNOWN_REASON;
786     }
787   else
788     {      
789       if (!_dbus_string_lengthen (data, adjust))
790         _dbus_assert_not_reached ("oom");
791       *expected_validity = DBUS_INVALID_TOO_MUCH_DATA;
792     }
793
794   /* Fixup lengths */
795   {
796     int old_body_len;
797     int new_body_len;
798     int byte_order;
799     
800     _dbus_assert (_dbus_string_get_length (data) >= DBUS_MINIMUM_HEADER_SIZE);
801     
802     byte_order = _dbus_string_get_byte (data, BYTE_ORDER_OFFSET);
803     old_body_len = _dbus_marshal_read_uint32 (data,
804                                               BODY_LENGTH_OFFSET,
805                                               byte_order,
806                                               NULL);
807     _dbus_assert (old_body_len < _dbus_string_get_length (data));
808     new_body_len = old_body_len + adjust;
809     if (new_body_len < 0)
810       {
811         new_body_len = 0;
812         /* we just munged the header, and aren't sure how */
813         *expected_validity = DBUS_VALIDITY_UNKNOWN;
814       }
815
816     _dbus_verbose ("changing body len from %u to %u by adjust %d\n",
817                    old_body_len, new_body_len, adjust);
818     
819     _dbus_marshal_set_uint32 (data, BODY_LENGTH_OFFSET,
820                               new_body_len,
821                               byte_order);
822   }
823
824   return TRUE;
825 }
826
827 static dbus_bool_t
828 generate_byte_changed (DBusMessageDataIter *iter,
829                        DBusString          *data,
830                        DBusValidity        *expected_validity)
831 {
832   int byte_seq;
833   int v_BYTE;
834
835   /* This is a little convoluted to make the bodies the
836    * outer loop and each byte of each body the inner
837    * loop
838    */
839
840  restart:
841   if (!generate_many_bodies (iter, data, expected_validity))
842     return FALSE;
843
844   iter_recurse (iter);
845   byte_seq = iter_get_sequence (iter);
846   iter_next (iter);
847   iter_unrecurse (iter);
848   
849   if (byte_seq == _dbus_string_get_length (data))
850     {
851       _dbus_string_set_length (data, 0);
852       /* reset byte count */
853       iter_recurse (iter);
854       iter_set_sequence (iter, 0);
855       iter_unrecurse (iter);
856       goto restart;
857     }
858   else
859     {
860       /* Undo the "next" in generate_many_bodies */
861       iter_set_sequence (iter, iter_get_sequence (iter) - 1);
862     }
863
864   _dbus_assert (byte_seq < _dbus_string_get_length (data));
865   v_BYTE = _dbus_string_get_byte (data, byte_seq);
866   v_BYTE += byte_seq; /* arbitrary but deterministic change to the byte */
867   _dbus_string_set_byte (data, byte_seq, v_BYTE);
868   *expected_validity = DBUS_VALIDITY_UNKNOWN;
869
870   return TRUE;
871 }
872
873 static dbus_bool_t
874 find_next_typecode (DBusMessageDataIter *iter,
875                     DBusString          *data,
876                     DBusValidity        *expected_validity)
877 {
878   int body_seq;
879   int byte_seq;
880   int base_depth;
881
882   base_depth = iter->depth;
883
884  restart:
885   _dbus_assert (iter->depth == (base_depth + 0));
886   _dbus_string_set_length (data, 0);
887
888   body_seq = iter_get_sequence (iter);
889   
890   if (!generate_many_bodies (iter, data, expected_validity))
891     return FALSE;
892   /* Undo the "next" in generate_many_bodies */
893   iter_set_sequence (iter, body_seq);
894   
895   iter_recurse (iter);
896   while (TRUE)
897     {
898       _dbus_assert (iter->depth == (base_depth + 1));
899       
900       byte_seq = iter_get_sequence (iter);
901
902       _dbus_assert (byte_seq <= _dbus_string_get_length (data));
903       
904       if (byte_seq == _dbus_string_get_length (data))
905         {
906           /* reset byte count */
907           iter_set_sequence (iter, 0);
908           iter_unrecurse (iter);
909           _dbus_assert (iter->depth == (base_depth + 0));
910           iter_next (iter); /* go to the next body */
911           goto restart;
912         }
913
914       _dbus_assert (byte_seq < _dbus_string_get_length (data));
915
916       if (_dbus_type_is_valid (_dbus_string_get_byte (data, byte_seq)))
917         break;
918       else
919         iter_next (iter);
920     }
921
922   _dbus_assert (byte_seq == iter_get_sequence (iter));
923   _dbus_assert (byte_seq < _dbus_string_get_length (data));
924
925   iter_unrecurse (iter);
926
927   _dbus_assert (iter->depth == (base_depth + 0));
928   
929   return TRUE;
930 }
931
932 static const int typecodes[] = {
933   DBUS_TYPE_INVALID,
934   DBUS_TYPE_BYTE,
935   DBUS_TYPE_BOOLEAN,
936   DBUS_TYPE_INT16,
937   DBUS_TYPE_UINT16,
938   DBUS_TYPE_INT32,
939   DBUS_TYPE_UINT32,
940   DBUS_TYPE_INT64,
941   DBUS_TYPE_UINT64,
942   DBUS_TYPE_DOUBLE,
943   DBUS_TYPE_STRING,
944   DBUS_TYPE_OBJECT_PATH,
945   DBUS_TYPE_SIGNATURE,
946   DBUS_TYPE_ARRAY,
947   DBUS_TYPE_VARIANT,
948   DBUS_STRUCT_BEGIN_CHAR,
949   DBUS_STRUCT_END_CHAR,
950   DBUS_DICT_ENTRY_BEGIN_CHAR,
951   DBUS_DICT_ENTRY_END_CHAR,
952   255 /* random invalid typecode */
953 };
954   
955 static dbus_bool_t
956 generate_typecode_changed (DBusMessageDataIter *iter,
957                            DBusString          *data,
958                            DBusValidity        *expected_validity)
959 {
960   int byte_seq;
961   int typecode_seq;
962   int base_depth;
963
964   base_depth = iter->depth;
965
966  restart:
967   _dbus_assert (iter->depth == (base_depth + 0));
968   _dbus_string_set_length (data, 0);
969   
970   if (!find_next_typecode (iter, data, expected_validity))
971     return FALSE;
972
973   iter_recurse (iter);
974   byte_seq = iter_get_sequence (iter);
975
976   _dbus_assert (byte_seq < _dbus_string_get_length (data));
977   
978   iter_recurse (iter);
979   typecode_seq = iter_get_sequence (iter);
980   iter_next (iter);
981
982   _dbus_assert (typecode_seq <= _DBUS_N_ELEMENTS (typecodes));
983   
984   if (typecode_seq == _DBUS_N_ELEMENTS (typecodes))
985     {
986       _dbus_assert (iter->depth == (base_depth + 2));
987       iter_set_sequence (iter, 0); /* reset typecode sequence */
988       iter_unrecurse (iter);
989       _dbus_assert (iter->depth == (base_depth + 1));
990       iter_next (iter); /* go to the next byte_seq */
991       iter_unrecurse (iter);
992       _dbus_assert (iter->depth == (base_depth + 0));
993       goto restart;
994     }
995
996   _dbus_assert (iter->depth == (base_depth + 2));
997   iter_unrecurse (iter);
998   _dbus_assert (iter->depth == (base_depth + 1));
999   iter_unrecurse (iter);
1000   _dbus_assert (iter->depth == (base_depth + 0));
1001
1002 #if 0
1003   printf ("Changing byte %d in message %d to %c\n",
1004           byte_seq, iter_get_sequence (iter), typecodes[typecode_seq]);
1005 #endif
1006   
1007   _dbus_string_set_byte (data, byte_seq, typecodes[typecode_seq]);
1008   *expected_validity = DBUS_VALIDITY_UNKNOWN;
1009   return TRUE;
1010 }
1011
1012 typedef struct
1013 {
1014   ChangeType type;
1015   dbus_uint32_t value; /* cast to signed for adjusts */
1016 } UIntChange;
1017
1018 static const UIntChange uint32_changes[] = {
1019   { CHANGE_TYPE_ADJUST, (dbus_uint32_t) -1 },
1020   { CHANGE_TYPE_ADJUST, (dbus_uint32_t) -2 },
1021   { CHANGE_TYPE_ADJUST, (dbus_uint32_t) -3 },
1022   { CHANGE_TYPE_ADJUST, (dbus_uint32_t) 1 },
1023   { CHANGE_TYPE_ADJUST, (dbus_uint32_t) 2 },
1024   { CHANGE_TYPE_ADJUST, (dbus_uint32_t) 3 },
1025   { CHANGE_TYPE_ABSOLUTE, _DBUS_UINT32_MAX },
1026   { CHANGE_TYPE_ABSOLUTE, 0 },
1027   { CHANGE_TYPE_ABSOLUTE, 1 },
1028   { CHANGE_TYPE_ABSOLUTE, _DBUS_UINT32_MAX - 1 },
1029   { CHANGE_TYPE_ABSOLUTE, _DBUS_UINT32_MAX - 5 }
1030 };
1031
1032 static dbus_bool_t
1033 generate_uint32_changed (DBusMessageDataIter *iter,
1034                          DBusString          *data,
1035                          DBusValidity        *expected_validity)
1036 {
1037   int body_seq;
1038   int byte_seq;
1039   int change_seq;
1040   dbus_uint32_t v_UINT32;
1041   int byte_order;
1042   const UIntChange *change;
1043   int base_depth;
1044
1045   /* Outer loop is each body, next loop is each change,
1046    * inner loop is each change location
1047    */
1048
1049   base_depth = iter->depth;
1050   
1051  next_body:
1052   _dbus_assert (iter->depth == (base_depth + 0));
1053   _dbus_string_set_length (data, 0);
1054   body_seq = iter_get_sequence (iter);
1055   
1056   if (!generate_many_bodies (iter, data, expected_validity))
1057     return FALSE;
1058
1059   _dbus_assert (iter->depth == (base_depth + 0));
1060
1061   iter_set_sequence (iter, body_seq); /* undo the "next" from generate_many_bodies */
1062   iter_recurse (iter);
1063  next_change:
1064   _dbus_assert (iter->depth == (base_depth + 1));
1065   change_seq = iter_get_sequence (iter);
1066   
1067   if (change_seq == _DBUS_N_ELEMENTS (uint32_changes))
1068     {
1069       /* Reset change count */
1070       iter_set_sequence (iter, 0);
1071       iter_unrecurse (iter);
1072       iter_next (iter);
1073       goto next_body;
1074     }
1075
1076   _dbus_assert (iter->depth == (base_depth + 1));
1077   
1078   iter_recurse (iter);
1079   _dbus_assert (iter->depth == (base_depth + 2));
1080   byte_seq = iter_get_sequence (iter);
1081   /* skip 4 bytes at a time */
1082   iter_next (iter);
1083   iter_next (iter);
1084   iter_next (iter);
1085   iter_next (iter);
1086   iter_unrecurse (iter);
1087
1088   _dbus_assert (_DBUS_ALIGN_VALUE (byte_seq, 4) == (unsigned) byte_seq);
1089   if (byte_seq >= (_dbus_string_get_length (data) - 4))
1090     {
1091       /* reset byte count */
1092       _dbus_assert (iter->depth == (base_depth + 1));
1093       iter_recurse (iter);
1094       _dbus_assert (iter->depth == (base_depth + 2));
1095       iter_set_sequence (iter, 0);
1096       iter_unrecurse (iter);
1097       _dbus_assert (iter->depth == (base_depth + 1));
1098       iter_next (iter);
1099       goto next_change;
1100     }
1101   
1102   _dbus_assert (byte_seq <= (_dbus_string_get_length (data) - 4));
1103
1104   byte_order = _dbus_string_get_byte (data, BYTE_ORDER_OFFSET);
1105   
1106   v_UINT32 = _dbus_marshal_read_uint32 (data, byte_seq, byte_order, NULL);
1107
1108   change = &uint32_changes[change_seq];
1109
1110   if (change->type == CHANGE_TYPE_ADJUST)
1111     {
1112       v_UINT32 += (int) change->value;
1113     }
1114   else
1115     {
1116       v_UINT32 = change->value;
1117     }
1118
1119 #if 0
1120   printf ("body %d change %d pos %d ",
1121           body_seq, change_seq, byte_seq);
1122
1123   if (change->type == CHANGE_TYPE_ADJUST)
1124     printf ("adjust by %d", (int) change->value);
1125   else
1126     printf ("set to %u", change->value);
1127   
1128   printf (" \t%u -> %u\n",
1129           _dbus_marshal_read_uint32 (data, byte_seq, byte_order, NULL),
1130           v_UINT32);
1131 #endif
1132   
1133   _dbus_marshal_set_uint32 (data, byte_seq, v_UINT32, byte_order);
1134   *expected_validity = DBUS_VALIDITY_UNKNOWN;
1135
1136   _dbus_assert (iter->depth == (base_depth + 1));
1137   iter_unrecurse (iter);
1138   _dbus_assert (iter->depth == (base_depth + 0));
1139           
1140   return TRUE;
1141 }
1142
1143 typedef struct
1144 {
1145   const char *name;
1146   DBusMessageGeneratorFunc func;  
1147 } DBusMessageGenerator;
1148
1149 static const DBusMessageGenerator generators[] = {
1150   { "trivial example of each message type", generate_trivial },
1151   { "assorted arguments", generate_many_bodies },
1152   { "assorted special cases", generate_special },
1153   { "each uint32 modified", generate_uint32_changed },
1154   { "wrong body lengths", generate_wrong_length },
1155   { "each byte modified", generate_byte_changed },
1156 #if 0
1157   /* This is really expensive and doesn't add too much coverage */
1158   { "change each typecode", generate_typecode_changed }
1159 #endif
1160 };
1161
1162 void
1163 _dbus_message_data_free (DBusMessageData *data)
1164 {
1165   _dbus_string_free (&data->data);
1166 }
1167
1168 void
1169 _dbus_message_data_iter_init (DBusMessageDataIter *iter)
1170 {
1171   int i;
1172   
1173   iter->depth = 0;
1174   i = 0;
1175   while (i < _DBUS_MESSAGE_DATA_MAX_NESTING)
1176     {
1177       iter->sequence_nos[i] = 0;
1178       ++i;
1179     }
1180   iter->count = 0;
1181 }
1182
1183 dbus_bool_t
1184 _dbus_message_data_iter_get_and_next (DBusMessageDataIter *iter,
1185                                       DBusMessageData     *data)
1186 {
1187   DBusMessageGeneratorFunc func;
1188   int generator;
1189
1190  restart:
1191   generator = iter_get_sequence (iter);
1192   
1193   if (generator == _DBUS_N_ELEMENTS (generators))
1194     return FALSE;
1195
1196   iter_recurse (iter);
1197   
1198   if (iter_first_in_series (iter))
1199     {
1200       printf (" testing message loading: %s ", generators[generator].name);
1201       fflush (stdout);
1202     }
1203   
1204   func = generators[generator].func;
1205
1206   if (!_dbus_string_init (&data->data))
1207     _dbus_assert_not_reached ("oom");
1208   
1209   if ((*func)(iter, &data->data, &data->expected_validity))
1210     ;
1211   else
1212     {
1213       iter_set_sequence (iter, 0);
1214       iter_unrecurse (iter);
1215       iter_next (iter); /* next generator */
1216       _dbus_string_free (&data->data);
1217       printf ("%d test loads cumulative\n", iter->count);
1218       goto restart;
1219     }
1220   iter_unrecurse (iter);
1221
1222   iter->count += 1;
1223   return TRUE;
1224 }
1225
1226 #endif /* !DOXYGEN_SHOULD_SKIP_THIS */
1227
1228 #endif /* DBUS_BUILD_TESTS */