2005-02-10 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 DBusMessage*
319 simple_error (void)
320 {
321   DBusMessage *message;
322   message =  dbus_message_new (DBUS_MESSAGE_TYPE_ERROR);
323   if (message == NULL)
324     _dbus_assert_not_reached ("oom");
325
326   if (!dbus_message_set_error_name (message, "foo.bar"))
327     _dbus_assert_not_reached ("oom");
328   
329   set_reply_serial (message);
330   
331   return message;
332 }
333
334 static dbus_bool_t
335 generate_special (DBusMessageDataIter   *iter,
336                   DBusString            *data,
337                   DBusValidity          *expected_validity)
338 {
339   int item_seq;
340   DBusMessage *message;
341   int pos;
342   dbus_int32_t v_INT32;
343
344   _dbus_assert (_dbus_string_get_length (data) == 0);
345   
346   message = NULL;
347   pos = -1;
348   v_INT32 = 42;
349   item_seq = iter_get_sequence (iter);
350
351   if (item_seq == 0)
352     {
353       message = simple_method_call ();
354       if (!dbus_message_append_args (message,
355                                      DBUS_TYPE_INT32, &v_INT32,
356                                      DBUS_TYPE_INT32, &v_INT32,
357                                      DBUS_TYPE_INT32, &v_INT32,
358                                      DBUS_TYPE_INVALID))
359         _dbus_assert_not_reached ("oom");
360                                      
361       _dbus_header_get_field_raw (&message->header,
362                                   DBUS_HEADER_FIELD_SIGNATURE,
363                                   NULL, &pos);
364       generate_from_message (data, expected_validity, message);
365       
366       /* set an invalid typecode */
367       _dbus_string_set_byte (data, pos + 1, '$');
368
369       *expected_validity = DBUS_INVALID_UNKNOWN_TYPECODE;
370     }
371   else if (item_seq == 1)
372     {
373       char long_sig[DBUS_MAXIMUM_TYPE_RECURSION_DEPTH+2];
374       const char *v_STRING;
375       int i;
376       
377       message = simple_method_call ();
378       if (!dbus_message_append_args (message,
379                                      DBUS_TYPE_INT32, &v_INT32,
380                                      DBUS_TYPE_INT32, &v_INT32,
381                                      DBUS_TYPE_INT32, &v_INT32,
382                                      DBUS_TYPE_INVALID))
383         _dbus_assert_not_reached ("oom");
384
385       i = 0;
386       while (i <= (DBUS_MAXIMUM_TYPE_RECURSION_DEPTH + 1))
387         {
388           long_sig[i] = DBUS_TYPE_ARRAY;
389           ++i;
390         }
391       long_sig[i] = DBUS_TYPE_INVALID;
392
393       v_STRING = long_sig;
394       if (!_dbus_header_set_field_basic (&message->header,
395                                          DBUS_HEADER_FIELD_SIGNATURE,
396                                          DBUS_TYPE_SIGNATURE,
397                                          &v_STRING))
398         _dbus_assert_not_reached ("oom");
399       
400       _dbus_header_get_field_raw (&message->header,
401                                   DBUS_HEADER_FIELD_SIGNATURE,
402                                   NULL, &pos);
403       generate_from_message (data, expected_validity, message);
404       
405       *expected_validity = DBUS_INVALID_EXCEEDED_MAXIMUM_ARRAY_RECURSION;
406     }
407   else if (item_seq == 2)
408     {
409       char long_sig[DBUS_MAXIMUM_TYPE_RECURSION_DEPTH*2+4];
410       const char *v_STRING;
411       int i;
412       
413       message = simple_method_call ();
414       if (!dbus_message_append_args (message,
415                                      DBUS_TYPE_INT32, &v_INT32,
416                                      DBUS_TYPE_INT32, &v_INT32,
417                                      DBUS_TYPE_INT32, &v_INT32,
418                                      DBUS_TYPE_INVALID))
419         _dbus_assert_not_reached ("oom");
420
421       i = 0;
422       while (i <= (DBUS_MAXIMUM_TYPE_RECURSION_DEPTH + 1))
423         {
424           long_sig[i] = DBUS_STRUCT_BEGIN_CHAR;
425           ++i;
426         }
427
428       long_sig[i] = DBUS_TYPE_INT32;
429       ++i;
430
431       while (i <= (DBUS_MAXIMUM_TYPE_RECURSION_DEPTH*2 + 3))
432         {
433           long_sig[i] = DBUS_STRUCT_END_CHAR;
434           ++i;
435         }
436       long_sig[i] = DBUS_TYPE_INVALID;
437       
438       v_STRING = long_sig;
439       if (!_dbus_header_set_field_basic (&message->header,
440                                          DBUS_HEADER_FIELD_SIGNATURE,
441                                          DBUS_TYPE_SIGNATURE,
442                                          &v_STRING))
443         _dbus_assert_not_reached ("oom");
444       
445       _dbus_header_get_field_raw (&message->header,
446                                   DBUS_HEADER_FIELD_SIGNATURE,
447                                   NULL, &pos);
448       generate_from_message (data, expected_validity, message);
449       
450       *expected_validity = DBUS_INVALID_EXCEEDED_MAXIMUM_STRUCT_RECURSION;
451     }
452   else if (item_seq == 3)
453     {
454       message = simple_method_call ();
455       if (!dbus_message_append_args (message,
456                                      DBUS_TYPE_INT32, &v_INT32,
457                                      DBUS_TYPE_INT32, &v_INT32,
458                                      DBUS_TYPE_INT32, &v_INT32,
459                                      DBUS_TYPE_INVALID))
460         _dbus_assert_not_reached ("oom");
461                                      
462       _dbus_header_get_field_raw (&message->header,
463                                   DBUS_HEADER_FIELD_SIGNATURE,
464                                   NULL, &pos);
465       generate_from_message (data, expected_validity, message);
466       
467       _dbus_string_set_byte (data, pos + 1, DBUS_STRUCT_BEGIN_CHAR);
468       
469       *expected_validity = DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED;
470     }
471   else if (item_seq == 4)
472     {
473       message = simple_method_call ();
474       if (!dbus_message_append_args (message,
475                                      DBUS_TYPE_INT32, &v_INT32,
476                                      DBUS_TYPE_INT32, &v_INT32,
477                                      DBUS_TYPE_INT32, &v_INT32,
478                                      DBUS_TYPE_INVALID))
479         _dbus_assert_not_reached ("oom");
480                                      
481       _dbus_header_get_field_raw (&message->header,
482                                   DBUS_HEADER_FIELD_SIGNATURE,
483                                   NULL, &pos);
484       generate_from_message (data, expected_validity, message);
485       
486       _dbus_string_set_byte (data, pos + 1, DBUS_STRUCT_END_CHAR);
487       
488       *expected_validity = DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED;
489     }
490   else if (item_seq == 5)
491     {
492       message = simple_method_call ();
493       if (!dbus_message_append_args (message,
494                                      DBUS_TYPE_INT32, &v_INT32,
495                                      DBUS_TYPE_INT32, &v_INT32,
496                                      DBUS_TYPE_INT32, &v_INT32,
497                                      DBUS_TYPE_INVALID))
498         _dbus_assert_not_reached ("oom");
499                                      
500       _dbus_header_get_field_raw (&message->header,
501                                   DBUS_HEADER_FIELD_SIGNATURE,
502                                   NULL, &pos);
503       generate_from_message (data, expected_validity, message);
504       
505       _dbus_string_set_byte (data, pos + 1, DBUS_STRUCT_BEGIN_CHAR);
506       _dbus_string_set_byte (data, pos + 2, DBUS_STRUCT_END_CHAR);
507       
508       *expected_validity = DBUS_INVALID_STRUCT_HAS_NO_FIELDS;
509     }
510   else if (item_seq == 6)
511     {
512       message = simple_method_call ();
513       generate_from_message (data, expected_validity, message);
514       
515       _dbus_string_set_byte (data, TYPE_OFFSET, DBUS_MESSAGE_TYPE_INVALID);
516       
517       *expected_validity = DBUS_INVALID_BAD_MESSAGE_TYPE;
518     }
519   else if (item_seq == 7)
520     {
521       /* Messages of unknown type are considered valid */
522       message = simple_method_call ();
523       generate_from_message (data, expected_validity, message);
524       
525       _dbus_string_set_byte (data, TYPE_OFFSET, 100);
526       
527       *expected_validity = DBUS_VALID;
528     }
529   else if (item_seq == 8)
530     {
531       message = simple_method_call ();
532       generate_from_message (data, expected_validity, message);
533       
534       _dbus_marshal_set_uint32 (data, BODY_LENGTH_OFFSET,
535                                 DBUS_MAXIMUM_MESSAGE_LENGTH / 2 + 4,
536                                 message->byte_order);
537       _dbus_marshal_set_uint32 (data, FIELDS_ARRAY_LENGTH_OFFSET,
538                                 DBUS_MAXIMUM_MESSAGE_LENGTH / 2 + 4,
539                                 message->byte_order);
540       *expected_validity = DBUS_INVALID_MESSAGE_TOO_LONG;
541     }
542   else if (item_seq == 9)
543     {
544       const char *v_STRING = "not a valid bus name";
545       message = simple_method_call ();
546
547       if (!_dbus_header_set_field_basic (&message->header,
548                                          DBUS_HEADER_FIELD_SENDER,
549                                          DBUS_TYPE_STRING, &v_STRING))
550         _dbus_assert_not_reached ("oom");
551       
552       generate_from_message (data, expected_validity, message);
553
554       *expected_validity = DBUS_INVALID_BAD_SENDER;
555     }
556   else if (item_seq == 10)
557     {
558       message = simple_method_call ();
559
560       if (!dbus_message_set_interface (message, DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL))
561         _dbus_assert_not_reached ("oom");
562       
563       generate_from_message (data, expected_validity, message);
564
565       *expected_validity = DBUS_INVALID_USES_LOCAL_INTERFACE;
566     }
567   else if (item_seq == 11)
568     {
569       message = simple_method_call ();
570
571       if (!dbus_message_set_path (message, DBUS_PATH_ORG_FREEDESKTOP_LOCAL))
572         _dbus_assert_not_reached ("oom");
573       
574       generate_from_message (data, expected_validity, message);
575
576       *expected_validity = DBUS_INVALID_USES_LOCAL_PATH;
577     }
578   else if (item_seq == 12)
579     {
580       /* Method calls don't have to have interface */
581       message = simple_method_call ();
582
583       if (!dbus_message_set_interface (message, NULL))
584         _dbus_assert_not_reached ("oom");
585       
586       generate_from_message (data, expected_validity, message);
587       
588       *expected_validity = DBUS_VALID;
589     }
590   else if (item_seq == 13)
591     {
592       /* Signals require an interface */
593       message = simple_signal ();
594
595       if (!dbus_message_set_interface (message, NULL))
596         _dbus_assert_not_reached ("oom");
597       
598       generate_from_message (data, expected_validity, message);
599       
600       *expected_validity = DBUS_INVALID_MISSING_INTERFACE;
601     }
602   else if (item_seq == 14)
603     {
604       message = simple_method_return ();
605
606       if (!_dbus_header_delete_field (&message->header, DBUS_HEADER_FIELD_REPLY_SERIAL))
607         _dbus_assert_not_reached ("oom");
608       
609       generate_from_message (data, expected_validity, message);
610       
611       *expected_validity = DBUS_INVALID_MISSING_REPLY_SERIAL;
612     }
613   else if (item_seq == 15)
614     {
615       message = simple_error ();
616
617       if (!dbus_message_set_error_name (message, NULL))
618         _dbus_assert_not_reached ("oom");
619       
620       generate_from_message (data, expected_validity, message);
621       
622       *expected_validity = DBUS_INVALID_MISSING_ERROR_NAME;
623     }
624   else if (item_seq == 16)
625     {
626       char long_sig[DBUS_MAXIMUM_TYPE_RECURSION_DEPTH*4+8];
627       const char *v_STRING;
628       int i;
629       int n_begins;
630       
631       message = simple_method_call ();
632       if (!dbus_message_append_args (message,
633                                      DBUS_TYPE_INT32, &v_INT32,
634                                      DBUS_TYPE_INT32, &v_INT32,
635                                      DBUS_TYPE_INT32, &v_INT32,
636                                      DBUS_TYPE_INVALID))
637         _dbus_assert_not_reached ("oom");
638
639       i = 0;
640       while (i <= (DBUS_MAXIMUM_TYPE_RECURSION_DEPTH*3 + 3))
641         {
642           long_sig[i] = DBUS_TYPE_ARRAY;
643           ++i;
644           long_sig[i] = DBUS_DICT_ENTRY_BEGIN_CHAR;
645           ++i;
646           long_sig[i] = DBUS_TYPE_INT32;
647           ++i;
648         }
649       n_begins = i / 3;
650
651       long_sig[i] = DBUS_TYPE_INT32;
652       ++i;
653       
654       while (n_begins > 0)
655         {
656           long_sig[i] = DBUS_DICT_ENTRY_END_CHAR;
657           ++i;
658           n_begins -= 1;
659         }
660       long_sig[i] = DBUS_TYPE_INVALID;
661       
662       v_STRING = long_sig;
663       if (!_dbus_header_set_field_basic (&message->header,
664                                          DBUS_HEADER_FIELD_SIGNATURE,
665                                          DBUS_TYPE_SIGNATURE,
666                                          &v_STRING))
667         _dbus_assert_not_reached ("oom");
668       
669       _dbus_header_get_field_raw (&message->header,
670                                   DBUS_HEADER_FIELD_SIGNATURE,
671                                   NULL, &pos);
672       generate_from_message (data, expected_validity, message);
673       
674       *expected_validity = DBUS_INVALID_EXCEEDED_MAXIMUM_DICT_ENTRY_RECURSION;
675     }
676   else if (item_seq == 17)
677     {
678       message = simple_method_call ();
679       if (!dbus_message_append_args (message,
680                                      DBUS_TYPE_INT32, &v_INT32,
681                                      DBUS_TYPE_INT32, &v_INT32,
682                                      DBUS_TYPE_INT32, &v_INT32,
683                                      DBUS_TYPE_INVALID))
684         _dbus_assert_not_reached ("oom");
685                                      
686       _dbus_header_get_field_raw (&message->header,
687                                   DBUS_HEADER_FIELD_SIGNATURE,
688                                   NULL, &pos);
689       generate_from_message (data, expected_validity, message);
690
691       _dbus_string_set_byte (data, pos + 1, DBUS_TYPE_ARRAY);
692       _dbus_string_set_byte (data, pos + 2, DBUS_DICT_ENTRY_BEGIN_CHAR);
693       
694       *expected_validity = DBUS_INVALID_DICT_ENTRY_STARTED_BUT_NOT_ENDED;
695     }
696   else if (item_seq == 18)
697     {
698       message = simple_method_call ();
699       if (!dbus_message_append_args (message,
700                                      DBUS_TYPE_INT32, &v_INT32,
701                                      DBUS_TYPE_INT32, &v_INT32,
702                                      DBUS_TYPE_INT32, &v_INT32,
703                                      DBUS_TYPE_INVALID))
704         _dbus_assert_not_reached ("oom");
705                                      
706       _dbus_header_get_field_raw (&message->header,
707                                   DBUS_HEADER_FIELD_SIGNATURE,
708                                   NULL, &pos);
709       generate_from_message (data, expected_validity, message);
710       
711       _dbus_string_set_byte (data, pos + 1, DBUS_DICT_ENTRY_END_CHAR);
712       
713       *expected_validity = DBUS_INVALID_DICT_ENTRY_ENDED_BUT_NOT_STARTED;
714     }
715   else if (item_seq == 19)
716     {
717       message = simple_method_call ();
718       if (!dbus_message_append_args (message,
719                                      DBUS_TYPE_INT32, &v_INT32,
720                                      DBUS_TYPE_INT32, &v_INT32,
721                                      DBUS_TYPE_INT32, &v_INT32,
722                                      DBUS_TYPE_INVALID))
723         _dbus_assert_not_reached ("oom");
724                                      
725       _dbus_header_get_field_raw (&message->header,
726                                   DBUS_HEADER_FIELD_SIGNATURE,
727                                   NULL, &pos);
728       generate_from_message (data, expected_validity, message);
729
730       _dbus_string_set_byte (data, pos + 1, DBUS_TYPE_ARRAY);
731       _dbus_string_set_byte (data, pos + 2, DBUS_DICT_ENTRY_BEGIN_CHAR);
732       _dbus_string_set_byte (data, pos + 3, DBUS_DICT_ENTRY_END_CHAR);
733       
734       *expected_validity = DBUS_INVALID_DICT_ENTRY_HAS_NO_FIELDS;
735     }
736   else
737     {
738       return FALSE;
739     }
740
741   if (message)
742     dbus_message_unref (message);
743
744   iter_next (iter);
745   return TRUE;
746 }
747
748 static dbus_bool_t
749 generate_wrong_length (DBusMessageDataIter *iter,
750                        DBusString          *data,
751                        DBusValidity        *expected_validity)
752 {
753   int lengths[] = { -42, -17, -16, -15, -9, -8, -7, -6, -5, -4, -3, -2, -1,
754                     1, 2, 3, 4, 5, 6, 7, 8, 9, 15, 16, 30 };
755   int adjust;
756   int len_seq;
757
758  restart:
759   len_seq = iter_get_sequence (iter);
760   if (len_seq == _DBUS_N_ELEMENTS (lengths))
761     return FALSE;
762
763   _dbus_assert (len_seq < _DBUS_N_ELEMENTS (lengths));
764   
765   iter_recurse (iter);
766   if (!generate_many_bodies (iter, data, expected_validity))
767     {
768       iter_set_sequence (iter, 0); /* reset to first body */
769       iter_unrecurse (iter);
770       iter_next (iter);            /* next length adjustment */
771       goto restart;
772     }
773   iter_unrecurse (iter);
774
775   adjust = lengths[len_seq];
776
777   if (adjust < 0)
778     {
779       if ((_dbus_string_get_length (data) + adjust) < DBUS_MINIMUM_HEADER_SIZE)
780         _dbus_string_set_length (data, DBUS_MINIMUM_HEADER_SIZE);
781       else
782         _dbus_string_shorten (data, - adjust);
783       *expected_validity = DBUS_INVALID_FOR_UNKNOWN_REASON;
784     }
785   else
786     {      
787       if (!_dbus_string_lengthen (data, adjust))
788         _dbus_assert_not_reached ("oom");
789       *expected_validity = DBUS_INVALID_TOO_MUCH_DATA;
790     }
791
792   /* Fixup lengths */
793   {
794     int old_body_len;
795     int new_body_len;
796     int byte_order;
797     
798     _dbus_assert (_dbus_string_get_length (data) >= DBUS_MINIMUM_HEADER_SIZE);
799     
800     byte_order = _dbus_string_get_byte (data, BYTE_ORDER_OFFSET);
801     old_body_len = _dbus_marshal_read_uint32 (data,
802                                               BODY_LENGTH_OFFSET,
803                                               byte_order,
804                                               NULL);
805     _dbus_assert (old_body_len < _dbus_string_get_length (data));
806     new_body_len = old_body_len + adjust;
807     if (new_body_len < 0)
808       {
809         new_body_len = 0;
810         /* we just munged the header, and aren't sure how */
811         *expected_validity = DBUS_VALIDITY_UNKNOWN;
812       }
813
814     _dbus_verbose ("changing body len from %u to %u by adjust %d\n",
815                    old_body_len, new_body_len, adjust);
816     
817     _dbus_marshal_set_uint32 (data, BODY_LENGTH_OFFSET,
818                               new_body_len,
819                               byte_order);
820   }
821
822   return TRUE;
823 }
824
825 static dbus_bool_t
826 generate_byte_changed (DBusMessageDataIter *iter,
827                        DBusString          *data,
828                        DBusValidity        *expected_validity)
829 {
830   int byte_seq;
831   int v_BYTE;
832
833   /* This is a little convoluted to make the bodies the
834    * outer loop and each byte of each body the inner
835    * loop
836    */
837
838  restart:
839   if (!generate_many_bodies (iter, data, expected_validity))
840     return FALSE;
841
842   iter_recurse (iter);
843   byte_seq = iter_get_sequence (iter);
844   iter_next (iter);
845   iter_unrecurse (iter);
846   
847   if (byte_seq == _dbus_string_get_length (data))
848     {
849       _dbus_string_set_length (data, 0);
850       /* reset byte count */
851       iter_recurse (iter);
852       iter_set_sequence (iter, 0);
853       iter_unrecurse (iter);
854       goto restart;
855     }
856   else
857     {
858       /* Undo the "next" in generate_many_bodies */
859       iter_set_sequence (iter, iter_get_sequence (iter) - 1);
860     }
861
862   _dbus_assert (byte_seq < _dbus_string_get_length (data));
863   v_BYTE = _dbus_string_get_byte (data, byte_seq);
864   v_BYTE += byte_seq; /* arbitrary but deterministic change to the byte */
865   _dbus_string_set_byte (data, byte_seq, v_BYTE);
866   *expected_validity = DBUS_VALIDITY_UNKNOWN;
867
868   return TRUE;
869 }
870
871 static dbus_bool_t
872 find_next_typecode (DBusMessageDataIter *iter,
873                     DBusString          *data,
874                     DBusValidity        *expected_validity)
875 {
876   int body_seq;
877   int byte_seq;
878   int base_depth;
879
880   base_depth = iter->depth;
881
882  restart:
883   _dbus_assert (iter->depth == (base_depth + 0));
884   _dbus_string_set_length (data, 0);
885
886   body_seq = iter_get_sequence (iter);
887   
888   if (!generate_many_bodies (iter, data, expected_validity))
889     return FALSE;
890   /* Undo the "next" in generate_many_bodies */
891   iter_set_sequence (iter, body_seq);
892   
893   iter_recurse (iter);
894   while (TRUE)
895     {
896       _dbus_assert (iter->depth == (base_depth + 1));
897       
898       byte_seq = iter_get_sequence (iter);
899
900       _dbus_assert (byte_seq <= _dbus_string_get_length (data));
901       
902       if (byte_seq == _dbus_string_get_length (data))
903         {
904           /* reset byte count */
905           iter_set_sequence (iter, 0);
906           iter_unrecurse (iter);
907           _dbus_assert (iter->depth == (base_depth + 0));
908           iter_next (iter); /* go to the next body */
909           goto restart;
910         }
911
912       _dbus_assert (byte_seq < _dbus_string_get_length (data));
913
914       if (_dbus_type_is_valid (_dbus_string_get_byte (data, byte_seq)))
915         break;
916       else
917         iter_next (iter);
918     }
919
920   _dbus_assert (byte_seq == iter_get_sequence (iter));
921   _dbus_assert (byte_seq < _dbus_string_get_length (data));
922
923   iter_unrecurse (iter);
924
925   _dbus_assert (iter->depth == (base_depth + 0));
926   
927   return TRUE;
928 }
929
930 static const int typecodes[] = {
931   DBUS_TYPE_INVALID,
932   DBUS_TYPE_BYTE,
933   DBUS_TYPE_BOOLEAN,
934   DBUS_TYPE_INT16,
935   DBUS_TYPE_UINT16,
936   DBUS_TYPE_INT32,
937   DBUS_TYPE_UINT32,
938   DBUS_TYPE_INT64,
939   DBUS_TYPE_UINT64,
940   DBUS_TYPE_DOUBLE,
941   DBUS_TYPE_STRING,
942   DBUS_TYPE_OBJECT_PATH,
943   DBUS_TYPE_SIGNATURE,
944   DBUS_TYPE_ARRAY,
945   DBUS_TYPE_VARIANT,
946   DBUS_STRUCT_BEGIN_CHAR,
947   DBUS_STRUCT_END_CHAR,
948   DBUS_DICT_ENTRY_BEGIN_CHAR,
949   DBUS_DICT_ENTRY_END_CHAR,
950   255 /* random invalid typecode */
951 };
952   
953 static dbus_bool_t
954 generate_typecode_changed (DBusMessageDataIter *iter,
955                            DBusString          *data,
956                            DBusValidity        *expected_validity)
957 {
958   int byte_seq;
959   int typecode_seq;
960   int base_depth;
961
962   base_depth = iter->depth;
963
964  restart:
965   _dbus_assert (iter->depth == (base_depth + 0));
966   _dbus_string_set_length (data, 0);
967   
968   if (!find_next_typecode (iter, data, expected_validity))
969     return FALSE;
970
971   iter_recurse (iter);
972   byte_seq = iter_get_sequence (iter);
973
974   _dbus_assert (byte_seq < _dbus_string_get_length (data));
975   
976   iter_recurse (iter);
977   typecode_seq = iter_get_sequence (iter);
978   iter_next (iter);
979
980   _dbus_assert (typecode_seq <= _DBUS_N_ELEMENTS (typecodes));
981   
982   if (typecode_seq == _DBUS_N_ELEMENTS (typecodes))
983     {
984       _dbus_assert (iter->depth == (base_depth + 2));
985       iter_set_sequence (iter, 0); /* reset typecode sequence */
986       iter_unrecurse (iter);
987       _dbus_assert (iter->depth == (base_depth + 1));
988       iter_next (iter); /* go to the next byte_seq */
989       iter_unrecurse (iter);
990       _dbus_assert (iter->depth == (base_depth + 0));
991       goto restart;
992     }
993
994   _dbus_assert (iter->depth == (base_depth + 2));
995   iter_unrecurse (iter);
996   _dbus_assert (iter->depth == (base_depth + 1));
997   iter_unrecurse (iter);
998   _dbus_assert (iter->depth == (base_depth + 0));
999
1000 #if 0
1001   printf ("Changing byte %d in message %d to %c\n",
1002           byte_seq, iter_get_sequence (iter), typecodes[typecode_seq]);
1003 #endif
1004   
1005   _dbus_string_set_byte (data, byte_seq, typecodes[typecode_seq]);
1006   *expected_validity = DBUS_VALIDITY_UNKNOWN;
1007   return TRUE;
1008 }
1009
1010 typedef struct
1011 {
1012   ChangeType type;
1013   dbus_uint32_t value; /* cast to signed for adjusts */
1014 } UIntChange;
1015
1016 static const UIntChange uint32_changes[] = {
1017   { CHANGE_TYPE_ADJUST, (dbus_uint32_t) -1 },
1018   { CHANGE_TYPE_ADJUST, (dbus_uint32_t) -2 },
1019   { CHANGE_TYPE_ADJUST, (dbus_uint32_t) -3 },
1020   { CHANGE_TYPE_ADJUST, (dbus_uint32_t) 1 },
1021   { CHANGE_TYPE_ADJUST, (dbus_uint32_t) 2 },
1022   { CHANGE_TYPE_ADJUST, (dbus_uint32_t) 3 },
1023   { CHANGE_TYPE_ABSOLUTE, _DBUS_UINT32_MAX },
1024   { CHANGE_TYPE_ABSOLUTE, 0 },
1025   { CHANGE_TYPE_ABSOLUTE, 1 },
1026   { CHANGE_TYPE_ABSOLUTE, _DBUS_UINT32_MAX - 1 },
1027   { CHANGE_TYPE_ABSOLUTE, _DBUS_UINT32_MAX - 5 }
1028 };
1029
1030 static dbus_bool_t
1031 generate_uint32_changed (DBusMessageDataIter *iter,
1032                          DBusString          *data,
1033                          DBusValidity        *expected_validity)
1034 {
1035   int body_seq;
1036   int byte_seq;
1037   int change_seq;
1038   dbus_uint32_t v_UINT32;
1039   int byte_order;
1040   const UIntChange *change;
1041   int base_depth;
1042
1043   /* Outer loop is each body, next loop is each change,
1044    * inner loop is each change location
1045    */
1046
1047   base_depth = iter->depth;
1048   
1049  next_body:
1050   _dbus_assert (iter->depth == (base_depth + 0));
1051   _dbus_string_set_length (data, 0);
1052   body_seq = iter_get_sequence (iter);
1053   
1054   if (!generate_many_bodies (iter, data, expected_validity))
1055     return FALSE;
1056
1057   _dbus_assert (iter->depth == (base_depth + 0));
1058
1059   iter_set_sequence (iter, body_seq); /* undo the "next" from generate_many_bodies */
1060   iter_recurse (iter);
1061  next_change:
1062   _dbus_assert (iter->depth == (base_depth + 1));
1063   change_seq = iter_get_sequence (iter);
1064   
1065   if (change_seq == _DBUS_N_ELEMENTS (uint32_changes))
1066     {
1067       /* Reset change count */
1068       iter_set_sequence (iter, 0);
1069       iter_unrecurse (iter);
1070       iter_next (iter);
1071       goto next_body;
1072     }
1073
1074   _dbus_assert (iter->depth == (base_depth + 1));
1075   
1076   iter_recurse (iter);
1077   _dbus_assert (iter->depth == (base_depth + 2));
1078   byte_seq = iter_get_sequence (iter);
1079   /* skip 4 bytes at a time */
1080   iter_next (iter);
1081   iter_next (iter);
1082   iter_next (iter);
1083   iter_next (iter);
1084   iter_unrecurse (iter);
1085
1086   _dbus_assert (_DBUS_ALIGN_VALUE (byte_seq, 4) == (unsigned) byte_seq);
1087   if (byte_seq >= (_dbus_string_get_length (data) - 4))
1088     {
1089       /* reset byte count */
1090       _dbus_assert (iter->depth == (base_depth + 1));
1091       iter_recurse (iter);
1092       _dbus_assert (iter->depth == (base_depth + 2));
1093       iter_set_sequence (iter, 0);
1094       iter_unrecurse (iter);
1095       _dbus_assert (iter->depth == (base_depth + 1));
1096       iter_next (iter);
1097       goto next_change;
1098     }
1099   
1100   _dbus_assert (byte_seq <= (_dbus_string_get_length (data) - 4));
1101
1102   byte_order = _dbus_string_get_byte (data, BYTE_ORDER_OFFSET);
1103   
1104   v_UINT32 = _dbus_marshal_read_uint32 (data, byte_seq, byte_order, NULL);
1105
1106   change = &uint32_changes[change_seq];
1107
1108   if (change->type == CHANGE_TYPE_ADJUST)
1109     {
1110       v_UINT32 += (int) change->value;
1111     }
1112   else
1113     {
1114       v_UINT32 = change->value;
1115     }
1116
1117 #if 0
1118   printf ("body %d change %d pos %d ",
1119           body_seq, change_seq, byte_seq);
1120
1121   if (change->type == CHANGE_TYPE_ADJUST)
1122     printf ("adjust by %d", (int) change->value);
1123   else
1124     printf ("set to %u", change->value);
1125   
1126   printf (" \t%u -> %u\n",
1127           _dbus_marshal_read_uint32 (data, byte_seq, byte_order, NULL),
1128           v_UINT32);
1129 #endif
1130   
1131   _dbus_marshal_set_uint32 (data, byte_seq, v_UINT32, byte_order);
1132   *expected_validity = DBUS_VALIDITY_UNKNOWN;
1133
1134   _dbus_assert (iter->depth == (base_depth + 1));
1135   iter_unrecurse (iter);
1136   _dbus_assert (iter->depth == (base_depth + 0));
1137           
1138   return TRUE;
1139 }
1140
1141 typedef struct
1142 {
1143   const char *name;
1144   DBusMessageGeneratorFunc func;  
1145 } DBusMessageGenerator;
1146
1147 static const DBusMessageGenerator generators[] = {
1148   { "trivial example of each message type", generate_trivial },
1149   { "assorted arguments", generate_many_bodies },
1150   { "assorted special cases", generate_special },
1151   { "each uint32 modified", generate_uint32_changed },
1152   { "wrong body lengths", generate_wrong_length },
1153   { "each byte modified", generate_byte_changed },
1154 #if 0
1155   /* This is really expensive and doesn't add too much coverage */
1156   { "change each typecode", generate_typecode_changed }
1157 #endif
1158 };
1159
1160 void
1161 _dbus_message_data_free (DBusMessageData *data)
1162 {
1163   _dbus_string_free (&data->data);
1164 }
1165
1166 void
1167 _dbus_message_data_iter_init (DBusMessageDataIter *iter)
1168 {
1169   int i;
1170   
1171   iter->depth = 0;
1172   i = 0;
1173   while (i < _DBUS_MESSAGE_DATA_MAX_NESTING)
1174     {
1175       iter->sequence_nos[i] = 0;
1176       ++i;
1177     }
1178   iter->count = 0;
1179 }
1180
1181 dbus_bool_t
1182 _dbus_message_data_iter_get_and_next (DBusMessageDataIter *iter,
1183                                       DBusMessageData     *data)
1184 {
1185   DBusMessageGeneratorFunc func;
1186   int generator;
1187
1188  restart:
1189   generator = iter_get_sequence (iter);
1190   
1191   if (generator == _DBUS_N_ELEMENTS (generators))
1192     return FALSE;
1193
1194   iter_recurse (iter);
1195   
1196   if (iter_first_in_series (iter))
1197     {
1198       printf (" testing message loading: %s ", generators[generator].name);
1199       fflush (stdout);
1200     }
1201   
1202   func = generators[generator].func;
1203
1204   if (!_dbus_string_init (&data->data))
1205     _dbus_assert_not_reached ("oom");
1206   
1207   if ((*func)(iter, &data->data, &data->expected_validity))
1208     ;
1209   else
1210     {
1211       iter_set_sequence (iter, 0);
1212       iter_unrecurse (iter);
1213       iter_next (iter); /* next generator */
1214       _dbus_string_free (&data->data);
1215       printf ("%d test loads cumulative\n", iter->count);
1216       goto restart;
1217     }
1218   iter_unrecurse (iter);
1219
1220   iter->count += 1;
1221   return TRUE;
1222 }
1223
1224 #endif /* DBUS_BUILD_TESTS */