1 /* GLib testing framework examples and tests
3 * Copyright (C) 2008-2010 Red Hat, Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18 * Boston, MA 02111-1307, USA.
20 * Author: David Zeuthen <davidz@redhat.com>
27 #include <dbus/dbus.h>
29 /* ---------------------------------------------------------------------------------------------------- */
32 hexdump (const guchar *str, gsize len)
34 const guchar *data = (const guchar *) str;
37 for (n = 0; n < len; n += 16)
39 g_printerr ("%04x: ", n);
41 for (m = n; m < n + 16; m++)
43 if (m > n && (m%4) == 0)
46 g_printerr ("%02x ", data[m]);
53 for (m = n; m < len && m < n + 16; m++)
54 g_printerr ("%c", g_ascii_isprint (data[m]) ? data[m] : '.');
60 /* ---------------------------------------------------------------------------------------------------- */
63 append_gv_to_dbus_iter (DBusMessageIter *iter,
67 const GVariantType *type;
69 type = g_variant_get_type (value);
70 if (g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN))
72 dbus_bool_t v = g_variant_get_boolean (value);
73 dbus_message_iter_append_basic (iter, DBUS_TYPE_BOOLEAN, &v);
75 else if (g_variant_type_equal (type, G_VARIANT_TYPE_BYTE))
77 guint8 v = g_variant_get_byte (value);
78 dbus_message_iter_append_basic (iter, DBUS_TYPE_BYTE, &v);
80 else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT16))
82 gint16 v = g_variant_get_int16 (value);
83 dbus_message_iter_append_basic (iter, DBUS_TYPE_INT16, &v);
85 else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT16))
87 guint16 v = g_variant_get_uint16 (value);
88 dbus_message_iter_append_basic (iter, DBUS_TYPE_UINT16, &v);
90 else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32))
92 gint32 v = g_variant_get_int32 (value);
93 dbus_message_iter_append_basic (iter, DBUS_TYPE_INT32, &v);
95 else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT32))
97 guint32 v = g_variant_get_uint32 (value);
98 dbus_message_iter_append_basic (iter, DBUS_TYPE_UINT32, &v);
100 else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT64))
102 gint64 v = g_variant_get_int64 (value);
103 dbus_message_iter_append_basic (iter, DBUS_TYPE_INT64, &v);
105 else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT64))
107 guint64 v = g_variant_get_uint64 (value);
108 dbus_message_iter_append_basic (iter, DBUS_TYPE_UINT64, &v);
110 else if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE))
112 gdouble v = g_variant_get_double (value);
113 dbus_message_iter_append_basic (iter, DBUS_TYPE_DOUBLE, &v);
115 else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING))
117 const gchar *v = g_variant_get_string (value, NULL);
118 dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &v);
120 else if (g_variant_type_equal (type, G_VARIANT_TYPE_OBJECT_PATH))
122 const gchar *v = g_variant_get_string (value, NULL);
123 dbus_message_iter_append_basic (iter, DBUS_TYPE_OBJECT_PATH, &v);
125 else if (g_variant_type_equal (type, G_VARIANT_TYPE_SIGNATURE))
127 const gchar *v = g_variant_get_string (value, NULL);
128 dbus_message_iter_append_basic (iter, DBUS_TYPE_SIGNATURE, &v);
130 else if (g_variant_type_is_variant (type))
135 child = g_variant_get_child_value (value, 0);
136 dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT,
137 g_variant_get_type_string (child),
139 if (!append_gv_to_dbus_iter (&sub, child, error))
141 g_variant_unref (child);
144 dbus_message_iter_close_container (iter, &sub);
145 g_variant_unref (child);
147 else if (g_variant_type_is_array (type))
149 DBusMessageIter dbus_iter;
150 const gchar *type_string;
151 GVariantIter gv_iter;
154 type_string = g_variant_get_type_string (value);
155 type_string++; /* skip the 'a' */
157 dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY,
158 type_string, &dbus_iter);
159 g_variant_iter_init (&gv_iter, value);
161 while ((item = g_variant_iter_next_value (&gv_iter)))
163 if (!append_gv_to_dbus_iter (&dbus_iter, item, error))
169 dbus_message_iter_close_container (iter, &dbus_iter);
171 else if (g_variant_type_is_tuple (type))
173 DBusMessageIter dbus_iter;
174 GVariantIter gv_iter;
177 dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT,
179 g_variant_iter_init (&gv_iter, value);
181 while ((item = g_variant_iter_next_value (&gv_iter)))
183 if (!append_gv_to_dbus_iter (&dbus_iter, item, error))
187 dbus_message_iter_close_container (iter, &dbus_iter);
189 else if (g_variant_type_is_dict_entry (type))
191 DBusMessageIter dbus_iter;
194 dbus_message_iter_open_container (iter, DBUS_TYPE_DICT_ENTRY,
196 key = g_variant_get_child_value (value, 0);
197 if (!append_gv_to_dbus_iter (&dbus_iter, key, error))
199 g_variant_unref (key);
202 g_variant_unref (key);
204 val = g_variant_get_child_value (value, 1);
205 if (!append_gv_to_dbus_iter (&dbus_iter, val, error))
207 g_variant_unref (val);
210 g_variant_unref (val);
212 dbus_message_iter_close_container (iter, &dbus_iter);
218 G_IO_ERROR_INVALID_ARGUMENT,
219 "Error serializing GVariant with type-string `%s' to a D-Bus message",
220 g_variant_get_type_string (value));
231 append_gv_to_dbus_message (DBusMessage *message,
242 DBusMessageIter iter;
243 GVariantIter gv_iter;
246 dbus_message_iter_init_append (message, &iter);
248 g_variant_iter_init (&gv_iter, value);
250 while ((item = g_variant_iter_next_value (&gv_iter)))
252 if (!append_gv_to_dbus_iter (&iter, item, error))
254 g_prefix_error (error,
255 "Error encoding in-arg %d: ",
270 print_gv_dbus_message (GVariant *value)
272 DBusMessage *message;
277 message = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_CALL);
278 dbus_message_set_serial (message, 0x41);
279 dbus_message_set_path (message, "/foo/bar");
280 dbus_message_set_member (message, "Member");
283 if (!append_gv_to_dbus_message (message, value, &error))
285 g_printerr ("Error printing GVariant as DBusMessage: %s", error->message);
286 g_error_free (error);
290 dbus_message_marshal (message, &blob, &blob_len);
292 hexdump ((guchar *) blob, blob_len);
294 dbus_message_unref (message);
297 /* ---------------------------------------------------------------------------------------------------- */
300 dbus_1_message_append (GString *s,
302 DBusMessageIter *iter)
307 g_string_append_printf (s, "%*s", indent, "");
309 arg_type = dbus_message_iter_get_arg_type (iter);
312 case DBUS_TYPE_BOOLEAN:
315 dbus_message_iter_get_basic (iter, &value);
316 g_string_append_printf (s, "bool: %s\n", value ? "true" : "false");
323 dbus_message_iter_get_basic (iter, &value);
324 g_string_append_printf (s, "byte: 0x%02x\n", (guint) value);
328 case DBUS_TYPE_INT16:
331 dbus_message_iter_get_basic (iter, &value);
332 g_string_append_printf (s, "int16: %" G_GINT16_FORMAT "\n", value);
336 case DBUS_TYPE_UINT16:
339 dbus_message_iter_get_basic (iter, &value);
340 g_string_append_printf (s, "uint16: %" G_GUINT16_FORMAT "\n", value);
344 case DBUS_TYPE_INT32:
347 dbus_message_iter_get_basic (iter, &value);
348 g_string_append_printf (s, "int32: %" G_GINT32_FORMAT "\n", value);
352 case DBUS_TYPE_UINT32:
355 dbus_message_iter_get_basic (iter, &value);
356 g_string_append_printf (s, "uint32: %" G_GUINT32_FORMAT "\n", value);
360 case DBUS_TYPE_INT64:
363 dbus_message_iter_get_basic (iter, &value);
364 g_string_append_printf (s, "int64: %" G_GINT64_FORMAT "\n", value);
368 case DBUS_TYPE_UINT64:
371 dbus_message_iter_get_basic (iter, &value);
372 g_string_append_printf (s, "uint64: %" G_GUINT64_FORMAT "\n", value);
376 case DBUS_TYPE_DOUBLE:
379 dbus_message_iter_get_basic (iter, &value);
380 g_string_append_printf (s, "double: %f\n", value);
384 case DBUS_TYPE_STRING:
387 dbus_message_iter_get_basic (iter, &value);
388 g_string_append_printf (s, "string: `%s'\n", value);
392 case DBUS_TYPE_OBJECT_PATH:
395 dbus_message_iter_get_basic (iter, &value);
396 g_string_append_printf (s, "object_path: `%s'\n", value);
400 case DBUS_TYPE_SIGNATURE:
403 dbus_message_iter_get_basic (iter, &value);
404 g_string_append_printf (s, "signature: `%s'\n", value);
408 #ifdef DBUS_TYPE_UNIX_FD
409 case DBUS_TYPE_UNIX_FD:
411 /* unfortunately there's currently no way to get just the
412 * protocol value, since dbus_message_iter_get_basic() wants
413 * to be 'helpful' and dup the fd for the user...
415 g_string_append (s, "unix-fd: (not extracted)\n");
420 case DBUS_TYPE_VARIANT:
421 g_string_append_printf (s, "variant:\n");
422 dbus_message_iter_recurse (iter, &sub);
423 while (dbus_message_iter_get_arg_type (&sub))
425 dbus_1_message_append (s, indent + 2, &sub);
426 dbus_message_iter_next (&sub);
430 case DBUS_TYPE_ARRAY:
431 g_string_append_printf (s, "array:\n");
432 dbus_message_iter_recurse (iter, &sub);
433 while (dbus_message_iter_get_arg_type (&sub))
435 dbus_1_message_append (s, indent + 2, &sub);
436 dbus_message_iter_next (&sub);
440 case DBUS_TYPE_STRUCT:
441 g_string_append_printf (s, "struct:\n");
442 dbus_message_iter_recurse (iter, &sub);
443 while (dbus_message_iter_get_arg_type (&sub))
445 dbus_1_message_append (s, indent + 2, &sub);
446 dbus_message_iter_next (&sub);
450 case DBUS_TYPE_DICT_ENTRY:
451 g_string_append_printf (s, "dict_entry:\n");
452 dbus_message_iter_recurse (iter, &sub);
453 while (dbus_message_iter_get_arg_type (&sub))
455 dbus_1_message_append (s, indent + 2, &sub);
456 dbus_message_iter_next (&sub);
461 g_printerr ("Error serializing D-Bus message to GVariant. Unsupported arg type `%c' (%d)",
464 g_assert_not_reached ();
470 dbus_1_message_print (DBusMessage *message)
474 DBusMessageIter iter;
476 s = g_string_new (NULL);
478 dbus_message_iter_init (message, &iter);
479 while (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_INVALID)
481 g_string_append_printf (s, "value %d: ", n);
482 dbus_1_message_append (s, 2, &iter);
483 dbus_message_iter_next (&iter);
487 return g_string_free (s, FALSE);
490 /* ---------------------------------------------------------------------------------------------------- */
493 get_body_signature (GVariant *value)
505 s = g_variant_get_type_string (value);
509 ret = g_strndup (s + 1, len - 2);
516 check_serialization (GVariant *value,
517 const gchar *expected_dbus_1_output)
521 DBusMessage *dbus_1_message;
522 GDBusMessage *message;
523 GDBusMessage *recovered_message;
525 DBusError dbus_error;
529 message = g_dbus_message_new ();
530 g_dbus_message_set_body (message, value);
531 g_dbus_message_set_message_type (message, G_DBUS_MESSAGE_TYPE_METHOD_CALL);
532 g_dbus_message_set_serial (message, 0x41);
533 s = get_body_signature (value);
534 g_dbus_message_set_header (message, G_DBUS_MESSAGE_HEADER_FIELD_PATH, g_variant_new_object_path ("/foo/bar"));
535 g_dbus_message_set_header (message, G_DBUS_MESSAGE_HEADER_FIELD_MEMBER, g_variant_new_string ("Member"));
536 g_dbus_message_set_header (message, G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE, g_variant_new_signature (s));
539 /* First check that the serialization to the D-Bus wire format is correct */
542 blob = g_dbus_message_to_blob (message,
544 G_DBUS_CAPABILITY_FLAGS_NONE,
546 g_assert_no_error (error);
547 g_assert (blob != NULL);
549 dbus_error_init (&dbus_error);
550 dbus_1_message = dbus_message_demarshal ((char *) blob, blob_size, &dbus_error);
551 if (dbus_error_is_set (&dbus_error))
553 g_printerr ("Error calling dbus_message_demarshal() on this blob: %s: %s\n",
556 hexdump (blob, blob_size);
557 dbus_error_free (&dbus_error);
559 s = g_variant_print (value, TRUE);
560 g_printerr ("\nThe blob was generated from the following GVariant value:\n%s\n\n", s);
563 g_printerr ("If the blob was encoded using DBusMessageIter, the payload would have been:\n");
564 print_gv_dbus_message (value);
566 g_assert_not_reached ();
569 s = dbus_1_message_print (dbus_1_message);
570 dbus_message_unref (dbus_1_message);
572 g_assert_cmpstr (s, ==, expected_dbus_1_output);
575 /* Then serialize back and check that the body is identical */
578 recovered_message = g_dbus_message_new_from_blob (blob,
580 G_DBUS_CAPABILITY_FLAGS_NONE,
582 g_assert (recovered_message != NULL);
583 g_assert_no_error (error);
587 g_assert (g_dbus_message_get_body (recovered_message) == NULL);
591 g_assert (g_dbus_message_get_body (recovered_message) != NULL);
592 if (!g_variant_equal (g_dbus_message_get_body (recovered_message), value))
594 s = g_variant_print (g_dbus_message_get_body (recovered_message), TRUE);
595 s1 = g_variant_print (value, TRUE);
596 g_printerr ("Recovered value:\n%s\ndoes not match given value\n%s\n",
601 g_assert_not_reached ();
604 g_object_unref (message);
605 g_object_unref (recovered_message);
609 message_serialize_basic (void)
611 check_serialization (NULL, "");
613 check_serialization (g_variant_new ("(sogybnqiuxtd)",
623 -G_GINT64_CONSTANT(2)<<34,
624 G_GUINT64_CONSTANT(0xffffffffffffffff),
626 "value 0: string: `this is a string'\n"
627 "value 1: object_path: `/this/is/a/path'\n"
628 "value 2: signature: `sad'\n"
629 "value 3: byte: 0x2a\n"
630 "value 4: bool: true\n"
631 "value 5: int16: -42\n"
632 "value 6: uint16: 60000\n"
633 "value 7: int32: -44\n"
634 "value 8: uint32: 100000\n"
635 "value 9: int64: -34359738368\n"
636 "value 10: uint64: 18446744073709551615\n"
637 "value 11: double: 42.500000\n");
640 /* ---------------------------------------------------------------------------------------------------- */
643 message_serialize_complex (void)
650 value = g_variant_parse (G_VARIANT_TYPE ("(aia{ss})"),
651 "([1, 2, 3], {'one': 'white', 'two': 'black'})",
653 g_assert_no_error (error);
654 g_assert (value != NULL);
655 check_serialization (value,
666 " string: `black'\n");
668 value = g_variant_parse (G_VARIANT_TYPE ("(sa{sv}as)"),
669 "('01234567890123456', {}, ['Something'])",
671 g_assert_no_error (error);
672 g_assert (value != NULL);
673 check_serialization (value,
674 "value 0: string: `01234567890123456'\n"
677 " string: `Something'\n");
679 /* https://bugzilla.gnome.org/show_bug.cgi?id=621838 */
680 check_serialization (g_variant_new_parsed ("(@aay [], {'cwd': <'/home/davidz/Hacking/glib/gio/tests'>})"),
686 " string: `/home/davidz/Hacking/glib/gio/tests'\n");
688 #ifdef DBUS_TYPE_UNIX_FD
689 value = g_variant_parse (G_VARIANT_TYPE ("(hah)"),
692 g_assert_no_error (error);
693 g_assert (value != NULL);
694 /* about (not extracted), see comment in DBUS_TYPE_UNIX_FD case in
695 * dbus_1_message_append() above.
697 check_serialization (value,
698 "value 0: unix-fd: (not extracted)\n"
700 " unix-fd: (not extracted)\n"
701 " unix-fd: (not extracted)\n");
706 /* ---------------------------------------------------------------------------------------------------- */
713 g_test_init (&argc, &argv, NULL);
715 g_test_add_func ("/gdbus/message-serialize-basic", message_serialize_basic);
716 g_test_add_func ("/gdbus/message-serialize-complex", message_serialize_complex);