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