1 #include <gio/gio.h> 2 #include <gio/gunixsocketaddress.h> 3 #include <glib/gstdio.h> 4 #include <string.h> 5 6 #include "gdbus-sessionbus.h" test_multi_mass_spring_damper_inputs()7 8 #include "glib/glib-private.h" 9 10 static gboolean 11 time_out (gpointer unused G_GNUC_UNUSED) 12 { 13 g_error ("Timed out"); 14 /* not reached */ 15 return FALSE; 16 } 17 18 static guint 19 add_timeout (guint seconds) 20 { 21 #ifdef G_OS_UNIX 22 /* Safety-catch against the main loop having blocked */ 23 alarm (seconds + 5); 24 #endif 25 return g_timeout_add_seconds (seconds, time_out, NULL); 26 } 27 28 static void 29 cancel_timeout (guint timeout_id) 30 { 31 #ifdef G_OS_UNIX 32 alarm (0); 33 #endif 34 g_source_remove (timeout_id); 35 } 36 37 /* Markup printing {{{1 */ test_multi_mass_spring_damper_higher_order()38 39 /* This used to be part of GLib, but it was removed before the stable 40 * release because it wasn't generally useful. We want it here, though. 41 */ 42 static void 43 indent_string (GString *string, 44 gint indent) 45 { 46 while (indent--) 47 g_string_append_c (string, ' '); 48 } 49 50 static GString * 51 g_menu_markup_print_string (GString *string, 52 GMenuModel *model, 53 gint indent, 54 gint tabstop) 55 { 56 gboolean need_nl = FALSE; test_n_link_pendulum_on_cart_inputs()57 gint i, n; 58 59 if G_UNLIKELY (string == NULL) 60 string = g_string_new (NULL); 61 62 n = g_menu_model_get_n_items (model); 63 64 for (i = 0; i < n; i++) 65 { 66 GMenuAttributeIter *attr_iter; 67 GMenuLinkIter *link_iter; 68 GString *contents; 69 GString *attrs; 70 71 attr_iter = g_menu_model_iterate_item_attributes (model, i); 72 link_iter = g_menu_model_iterate_item_links (model, i); 73 contents = g_string_new (NULL); 74 attrs = g_string_new (NULL); 75 76 while (g_menu_attribute_iter_next (attr_iter)) 77 { 78 const char *name = g_menu_attribute_iter_get_name (attr_iter); 79 GVariant *value = g_menu_attribute_iter_get_value (attr_iter); 80 81 if (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING)) 82 { 83 gchar *str; 84 str = g_markup_printf_escaped (" %s='%s'", name, g_variant_get_string (value, NULL)); 85 g_string_append (attrs, str); 86 g_free (str); 87 } 88 89 else 90 { 91 gchar *printed; 92 gchar *str; test_n_link_pendulum_on_cart_higher_order()93 const gchar *type; 94 95 printed = g_variant_print (value, TRUE); 96 type = g_variant_type_peek_string (g_variant_get_type (value)); 97 str = g_markup_printf_escaped ("<attribute name='%s' type='%s'>%s</attribute>\n", name, type, printed); 98 indent_string (contents, indent + tabstop); 99 g_string_append (contents, str); 100 g_free (printed); 101 g_free (str); 102 } 103 104 g_variant_unref (value); 105 } 106 g_object_unref (attr_iter); 107 108 while (g_menu_link_iter_next (link_iter)) 109 { 110 const gchar *name = g_menu_link_iter_get_name (link_iter); 111 GMenuModel *menu = g_menu_link_iter_get_value (link_iter); 112 gchar *str; 113 114 if (contents->str[0]) 115 g_string_append_c (contents, '\n'); 116 117 str = g_markup_printf_escaped ("<link name='%s'>\n", name); 118 indent_string (contents, indent + tabstop); 119 g_string_append (contents, str); 120 g_free (str); 121 122 g_menu_markup_print_string (contents, menu, indent + 2 * tabstop, tabstop); 123 124 indent_string (contents, indent + tabstop); 125 g_string_append (contents, "</link>\n"); 126 g_object_unref (menu); 127 } 128 g_object_unref (link_iter); 129 130 if (contents->str[0]) 131 { 132 indent_string (string, indent); 133 g_string_append_printf (string, "<item%s>\n", attrs->str); 134 g_string_append (string, contents->str); 135 indent_string (string, indent); 136 g_string_append (string, "</item>\n"); 137 need_nl = TRUE; 138 } 139 140 else 141 { 142 if (need_nl) 143 g_string_append_c (string, '\n'); 144 145 indent_string (string, indent); 146 g_string_append_printf (string, "<item%s/>\n", attrs->str); 147 need_nl = FALSE; 148 } 149 150 g_string_free (contents, TRUE); 151 g_string_free (attrs, TRUE); 152 } 153 154 return string; 155 } 156 157 /* TestItem {{{1 */ 158 159 /* This utility struct is used by both the RandomMenu and MirrorMenu 160 * class implementations below. 161 */ 162 typedef struct { 163 GHashTable *attributes; 164 GHashTable *links; 165 } TestItem; 166 167 static TestItem * 168 test_item_new (GHashTable *attributes, 169 GHashTable *links) 170 { 171 TestItem *item; 172 173 item = g_slice_new (TestItem); 174 item->attributes = g_hash_table_ref (attributes); 175 item->links = g_hash_table_ref (links); 176 177 return item; 178 } 179 180 static void 181 test_item_free (gpointer data) 182 { 183 TestItem *item = data; 184 185 g_hash_table_unref (item->attributes); 186 g_hash_table_unref (item->links); 187 188 g_slice_free (TestItem, item); 189 } 190 191 /* RandomMenu {{{1 */ 192 #define MAX_ITEMS 5 193 #define TOP_ORDER 4 194 195 typedef struct { 196 GMenuModel parent_instance; 197 198 GSequence *items; 199 gint order; 200 } RandomMenu; 201 202 typedef GMenuModelClass RandomMenuClass; 203 204 static GType random_menu_get_type (void); 205 G_DEFINE_TYPE (RandomMenu, random_menu, G_TYPE_MENU_MODEL) 206 207 static gboolean 208 random_menu_is_mutable (GMenuModel *model) 209 { 210 return TRUE; 211 } 212 213 static gint 214 random_menu_get_n_items (GMenuModel *model) 215 { 216 RandomMenu *menu = (RandomMenu *) model; 217 218 return g_sequence_get_length (menu->items); 219 } 220 221 static void 222 random_menu_get_item_attributes (GMenuModel *model, 223 gint position, 224 GHashTable **table) 225 { 226 RandomMenu *menu = (RandomMenu *) model; 227 TestItem *item; 228 229 item = g_sequence_get (g_sequence_get_iter_at_pos (menu->items, position)); 230 *table = g_hash_table_ref (item->attributes); 231 } 232 233 static void 234 random_menu_get_item_links (GMenuModel *model, 235 gint position, 236 GHashTable **table) 237 { 238 RandomMenu *menu = (RandomMenu *) model; 239 TestItem *item; 240 241 item = g_sequence_get (g_sequence_get_iter_at_pos (menu->items, position)); 242 *table = g_hash_table_ref (item->links); 243 } 244 245 static void 246 random_menu_finalize (GObject *object) 247 { 248 RandomMenu *menu = (RandomMenu *) object; 249 250 g_sequence_free (menu->items); 251 252 G_OBJECT_CLASS (random_menu_parent_class) 253 ->finalize (object); 254 } 255 256 static void 257 random_menu_init (RandomMenu *menu) 258 { 259 } 260 261 static void 262 random_menu_class_init (GMenuModelClass *class) 263 { 264 GObjectClass *object_class = G_OBJECT_CLASS (class); 265 266 class->is_mutable = random_menu_is_mutable; 267 class->get_n_items = random_menu_get_n_items; 268 class->get_item_attributes = random_menu_get_item_attributes; 269 class->get_item_links = random_menu_get_item_links; 270 271 object_class->finalize = random_menu_finalize; 272 } 273 274 static RandomMenu * random_menu_new (GRand *rand, gint order); 275 276 static void 277 random_menu_change (RandomMenu *menu, 278 GRand *rand) 279 { 280 gint position, removes, adds; 281 GSequenceIter *point; 282 gint n_items; 283 gint i; 284 285 n_items = g_sequence_get_length (menu->items); 286 287 do 288 { 289 position = g_rand_int_range (rand, 0, n_items + 1); 290 removes = g_rand_int_range (rand, 0, n_items - position + 1); 291 adds = g_rand_int_range (rand, 0, MAX_ITEMS - (n_items - removes) + 1); 292 } 293 while (removes == 0 && adds == 0); 294 295 point = g_sequence_get_iter_at_pos (menu->items, position + removes); 296 297 if (removes) 298 { 299 GSequenceIter *start; 300 301 start = g_sequence_get_iter_at_pos (menu->items, position); 302 g_sequence_remove_range (start, point); 303 } 304 305 for (i = 0; i < adds; i++) 306 { 307 const gchar *label; 308 GHashTable *links; 309 GHashTable *attributes; 310 311 attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref); 312 links = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_object_unref); 313 314 if (menu->order > 0 && g_rand_boolean (rand)) 315 { 316 RandomMenu *child; 317 const gchar *subtype; 318 319 child = random_menu_new (rand, menu->order - 1); 320 321 if (g_rand_boolean (rand)) 322 { 323 subtype = G_MENU_LINK_SECTION; 324 /* label some section headers */ 325 if (g_rand_boolean (rand)) 326 label = "Section"; 327 else 328 label = NULL; 329 } 330 else 331 { 332 /* label all submenus */ 333 subtype = G_MENU_LINK_SUBMENU; 334 label = "Submenu"; 335 } 336 337 g_hash_table_insert (links, g_strdup (subtype), child); 338 } 339 else 340 /* label all terminals */ 341 label = "Menu Item"; 342 343 if (label) 344 g_hash_table_insert (attributes, g_strdup ("label"), g_variant_ref_sink (g_variant_new_string (label))); 345 346 g_sequence_insert_before (point, test_item_new (attributes, links)); 347 g_hash_table_unref (links); 348 g_hash_table_unref (attributes); 349 } 350 351 g_menu_model_items_changed (G_MENU_MODEL (menu), position, removes, adds); 352 } 353 354 static RandomMenu * 355 random_menu_new (GRand *rand, 356 gint order) 357 { 358 RandomMenu *menu; 359 360 menu = g_object_new (random_menu_get_type (), NULL); 361 menu->items = g_sequence_new (test_item_free); 362 menu->order = order; 363 364 random_menu_change (menu, rand); 365 366 return menu; 367 } 368 369 /* MirrorMenu {{{1 */ 370 typedef struct { 371 GMenuModel parent_instance; 372 373 GMenuModel *clone_of; 374 GSequence *items; 375 gulong handler_id; 376 } MirrorMenu; 377 378 typedef GMenuModelClass MirrorMenuClass; 379 380 static GType mirror_menu_get_type (void); 381 G_DEFINE_TYPE (MirrorMenu, mirror_menu, G_TYPE_MENU_MODEL) 382 383 static gboolean 384 mirror_menu_is_mutable (GMenuModel *model) 385 { 386 MirrorMenu *menu = (MirrorMenu *) model; 387 388 return menu->handler_id != 0; 389 } 390 391 static gint 392 mirror_menu_get_n_items (GMenuModel *model) 393 { 394 MirrorMenu *menu = (MirrorMenu *) model; 395 396 return g_sequence_get_length (menu->items); 397 } 398 399 static void 400 mirror_menu_get_item_attributes (GMenuModel *model, 401 gint position, 402 GHashTable **table) 403 { 404 MirrorMenu *menu = (MirrorMenu *) model; 405 TestItem *item; 406 407 item = g_sequence_get (g_sequence_get_iter_at_pos (menu->items, position)); 408 *table = g_hash_table_ref (item->attributes); 409 } 410 411 static void 412 mirror_menu_get_item_links (GMenuModel *model, 413 gint position, 414 GHashTable **table) 415 { 416 MirrorMenu *menu = (MirrorMenu *) model; 417 TestItem *item; 418 419 item = g_sequence_get (g_sequence_get_iter_at_pos (menu->items, position)); 420 *table = g_hash_table_ref (item->links); 421 } 422 423 static void 424 mirror_menu_finalize (GObject *object) 425 { 426 MirrorMenu *menu = (MirrorMenu *) object; 427 428 if (menu->handler_id) 429 g_signal_handler_disconnect (menu->clone_of, menu->handler_id); 430 431 g_sequence_free (menu->items); 432 g_object_unref (menu->clone_of); 433 434 G_OBJECT_CLASS (mirror_menu_parent_class) 435 ->finalize (object); 436 } 437 438 static void 439 mirror_menu_init (MirrorMenu *menu) 440 { 441 } 442 443 static void 444 mirror_menu_class_init (GMenuModelClass *class) 445 { 446 GObjectClass *object_class = G_OBJECT_CLASS (class); 447 448 class->is_mutable = mirror_menu_is_mutable; 449 class->get_n_items = mirror_menu_get_n_items; 450 class->get_item_attributes = mirror_menu_get_item_attributes; 451 class->get_item_links = mirror_menu_get_item_links; 452 453 object_class->finalize = mirror_menu_finalize; 454 } 455 456 static MirrorMenu * mirror_menu_new (GMenuModel *clone_of); 457 458 static void 459 mirror_menu_changed (GMenuModel *model, 460 gint position, 461 gint removed, 462 gint added, 463 gpointer user_data) 464 { 465 MirrorMenu *menu = user_data; 466 GSequenceIter *point; 467 gint i; 468 469 g_assert (model == menu->clone_of); 470 471 point = g_sequence_get_iter_at_pos (menu->items, position + removed); 472 473 if (removed) 474 { 475 GSequenceIter *start; 476 477 start = g_sequence_get_iter_at_pos (menu->items, position); 478 g_sequence_remove_range (start, point); 479 } 480 481 for (i = position; i < position + added; i++) 482 { 483 GMenuAttributeIter *attr_iter; 484 GMenuLinkIter *link_iter; 485 GHashTable *links; 486 GHashTable *attributes; 487 const gchar *name; 488 GMenuModel *child; 489 GVariant *value; 490 491 attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref); 492 links = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_object_unref); 493 494 attr_iter = g_menu_model_iterate_item_attributes (model, i); 495 while (g_menu_attribute_iter_get_next (attr_iter, &name, &value)) 496 { 497 g_hash_table_insert (attributes, g_strdup (name), value); 498 } 499 g_object_unref (attr_iter); 500 501 link_iter = g_menu_model_iterate_item_links (model, i); 502 while (g_menu_link_iter_get_next (link_iter, &name, &child)) 503 { 504 g_hash_table_insert (links, g_strdup (name), mirror_menu_new (child)); 505 g_object_unref (child); 506 } 507 g_object_unref (link_iter); 508 509 g_sequence_insert_before (point, test_item_new (attributes, links)); 510 g_hash_table_unref (attributes); 511 g_hash_table_unref (links); 512 } 513 514 g_menu_model_items_changed (G_MENU_MODEL (menu), position, removed, added); 515 } 516 517 static MirrorMenu * 518 mirror_menu_new (GMenuModel *clone_of) 519 { 520 MirrorMenu *menu; 521 522 menu = g_object_new (mirror_menu_get_type (), NULL); 523 menu->items = g_sequence_new (test_item_free); 524 menu->clone_of = g_object_ref (clone_of); 525 526 if (g_menu_model_is_mutable (clone_of)) 527 menu->handler_id = g_signal_connect (clone_of, "items-changed", G_CALLBACK (mirror_menu_changed), menu); 528 mirror_menu_changed (clone_of, 0, 0, g_menu_model_get_n_items (clone_of), menu); 529 530 return menu; 531 } 532 533 /* check_menus_equal(), assert_menus_equal() {{{1 */ 534 static gboolean 535 check_menus_equal (GMenuModel *a, 536 GMenuModel *b) 537 { 538 gboolean equal = TRUE; 539 gint a_n, b_n; 540 gint i; 541 542 a_n = g_menu_model_get_n_items (a); 543 b_n = g_menu_model_get_n_items (b); 544 545 if (a_n != b_n) 546 return FALSE; 547 548 for (i = 0; i < a_n; i++) 549 { 550 GMenuAttributeIter *attr_iter; 551 GVariant *a_value, *b_value; 552 GMenuLinkIter *link_iter; 553 GMenuModel *a_menu, *b_menu; 554 const gchar *name; 555 556 attr_iter = g_menu_model_iterate_item_attributes (a, i); 557 while (g_menu_attribute_iter_get_next (attr_iter, &name, &a_value)) 558 { 559 b_value = g_menu_model_get_item_attribute_value (b, i, name, NULL); 560 equal &= b_value && g_variant_equal (a_value, b_value); 561 if (b_value) 562 g_variant_unref (b_value); 563 g_variant_unref (a_value); 564 } 565 g_object_unref (attr_iter); 566 567 attr_iter = g_menu_model_iterate_item_attributes (b, i); 568 while (g_menu_attribute_iter_get_next (attr_iter, &name, &b_value)) 569 { 570 a_value = g_menu_model_get_item_attribute_value (a, i, name, NULL); 571 equal &= a_value && g_variant_equal (a_value, b_value); 572 if (a_value) 573 g_variant_unref (a_value); 574 g_variant_unref (b_value); 575 } 576 g_object_unref (attr_iter); 577 578 link_iter = g_menu_model_iterate_item_links (a, i); 579 while (g_menu_link_iter_get_next (link_iter, &name, &a_menu)) 580 { 581 b_menu = g_menu_model_get_item_link (b, i, name); 582 equal &= b_menu && check_menus_equal (a_menu, b_menu); 583 if (b_menu) 584 g_object_unref (b_menu); 585 g_object_unref (a_menu); 586 } 587 g_object_unref (link_iter); 588 589 link_iter = g_menu_model_iterate_item_links (b, i); 590 while (g_menu_link_iter_get_next (link_iter, &name, &b_menu)) 591 { 592 a_menu = g_menu_model_get_item_link (a, i, name); 593 equal &= a_menu && check_menus_equal (a_menu, b_menu); 594 if (a_menu) 595 g_object_unref (a_menu); 596 g_object_unref (b_menu); 597 } 598 g_object_unref (link_iter); 599 } 600 601 return equal; 602 } 603 604 static void 605 assert_menus_equal (GMenuModel *a, 606 GMenuModel *b) 607 { 608 if (!check_menus_equal (a, b)) 609 { 610 GString *string; 611 612 string = g_string_new ("\n <a>\n"); 613 g_menu_markup_print_string (string, G_MENU_MODEL (a), 4, 2); 614 g_string_append (string, " </a>\n\n-------------\n <b>\n"); 615 g_menu_markup_print_string (string, G_MENU_MODEL (b), 4, 2); 616 g_string_append (string, " </b>\n"); 617 g_error ("%s", string->str); 618 } 619 } 620 621 static void 622 assert_menuitem_equal (GMenuItem *item, 623 GMenuModel *model, 624 gint index) 625 { 626 GMenuAttributeIter *attr_iter; 627 GMenuLinkIter *link_iter; 628 const gchar *name; 629 GVariant *value; 630 GMenuModel *linked_model; 631 632 /* NOTE we can't yet test whether item has attributes or links that 633 * are not in the model, because there's no iterator API for menu 634 * items */ 635 636 attr_iter = g_menu_model_iterate_item_attributes (model, index); 637 while (g_menu_attribute_iter_get_next (attr_iter, &name, &value)) 638 { 639 GVariant *item_value; 640 641 item_value = g_menu_item_get_attribute_value (item, name, g_variant_get_type (value)); 642 g_assert (item_value && g_variant_equal (item_value, value)); 643 644 g_variant_unref (item_value); 645 g_variant_unref (value); 646 } 647 648 link_iter = g_menu_model_iterate_item_links (model, index); 649 while (g_menu_link_iter_get_next (link_iter, &name, &linked_model)) 650 { 651 GMenuModel *item_linked_model; 652 653 item_linked_model = g_menu_item_get_link (item, name); 654 g_assert (linked_model == item_linked_model); 655 656 g_object_unref (item_linked_model); 657 g_object_unref (linked_model); 658 } 659 660 g_object_unref (attr_iter); 661 g_object_unref (link_iter); 662 } 663 664 /* Test cases {{{1 */ 665 static void 666 test_equality (void) 667 { 668 GRand *randa, *randb; 669 guint32 seed; 670 gint i; 671 672 seed = g_test_rand_int (); 673 674 randa = g_rand_new_with_seed (seed); 675 randb = g_rand_new_with_seed (seed); 676 677 for (i = 0; i < 500; i++) 678 { 679 RandomMenu *a, *b; 680 681 a = random_menu_new (randa, TOP_ORDER); 682 b = random_menu_new (randb, TOP_ORDER); 683 assert_menus_equal (G_MENU_MODEL (a), G_MENU_MODEL (b)); 684 g_object_unref (b); 685 g_object_unref (a); 686 } 687 688 g_rand_int (randa); 689 690 for (i = 0; i < 500;) 691 { 692 RandomMenu *a, *b; 693 694 a = random_menu_new (randa, TOP_ORDER); 695 b = random_menu_new (randb, TOP_ORDER); 696 if (check_menus_equal (G_MENU_MODEL (a), G_MENU_MODEL (b))) 697 { 698 /* by chance, they may really be equal. double check. */ 699 GString *as, *bs; 700 701 as = g_menu_markup_print_string (NULL, G_MENU_MODEL (a), 4, 2); 702 bs = g_menu_markup_print_string (NULL, G_MENU_MODEL (b), 4, 2); 703 g_assert_cmpstr (as->str, ==, bs->str); 704 g_string_free (bs, TRUE); 705 g_string_free (as, TRUE); 706 707 /* we're here because randa and randb just generated equal 708 * menus. they may do it again, so throw away randb and make 709 * a fresh one. 710 */ 711 g_rand_free (randb); 712 randb = g_rand_new_with_seed (g_rand_int (randa)); 713 } 714 else 715 /* make sure we get enough unequals (ie: no GRand failure) */ 716 i++; 717 718 g_object_unref (b); 719 g_object_unref (a); 720 } 721 722 g_rand_free (randb); 723 g_rand_free (randa); 724 } 725 726 static void 727 test_random (void) 728 { 729 RandomMenu *random; 730 MirrorMenu *mirror; 731 GRand *rand; 732 gint i; 733 734 rand = g_rand_new_with_seed (g_test_rand_int ()); 735 random = random_menu_new (rand, TOP_ORDER); 736 mirror = mirror_menu_new (G_MENU_MODEL (random)); 737 738 for (i = 0; i < 500; i++) 739 { 740 assert_menus_equal (G_MENU_MODEL (random), G_MENU_MODEL (mirror)); 741 random_menu_change (random, rand); 742 } 743 744 g_object_unref (mirror); 745 g_object_unref (random); 746 747 g_rand_free (rand); 748 } 749 750 typedef struct 751 { 752 GDBusConnection *client_connection; 753 GDBusConnection *server_connection; 754 GDBusServer *server; 755 756 GThread *service_thread; 757 /* Protects server_connection and service_loop. */ 758 GMutex service_loop_lock; 759 GCond service_loop_cond; 760 761 GMainLoop *service_loop; 762 } PeerConnection; 763 764 static gboolean 765 on_new_connection (GDBusServer *server, 766 GDBusConnection *connection, 767 gpointer user_data) 768 { 769 PeerConnection *data = user_data; 770 771 g_mutex_lock (&data->service_loop_lock); 772 data->server_connection = g_object_ref (connection); 773 g_cond_broadcast (&data->service_loop_cond); 774 g_mutex_unlock (&data->service_loop_lock); 775 776 return TRUE; 777 } 778 779 static void 780 create_service_loop (GMainContext *service_context, 781 PeerConnection *data) 782 { 783 g_assert (data->service_loop == NULL); 784 g_mutex_lock (&data->service_loop_lock); 785 data->service_loop = g_main_loop_new (service_context, FALSE); 786 g_cond_broadcast (&data->service_loop_cond); 787 g_mutex_unlock (&data->service_loop_lock); 788 } 789 790 static void 791 teardown_service_loop (PeerConnection *data) 792 { 793 g_mutex_lock (&data->service_loop_lock); 794 g_clear_pointer (&data->service_loop, g_main_loop_unref); 795 g_mutex_unlock (&data->service_loop_lock); 796 } 797 798 static void 799 await_service_loop (PeerConnection *data) 800 { 801 g_mutex_lock (&data->service_loop_lock); 802 while (data->service_loop == NULL) 803 g_cond_wait (&data->service_loop_cond, &data->service_loop_lock); 804 g_mutex_unlock (&data->service_loop_lock); 805 } 806 807 static void 808 await_server_connection (PeerConnection *data) 809 { 810 g_mutex_lock (&data->service_loop_lock); 811 while (data->server_connection == NULL) 812 g_cond_wait (&data->service_loop_cond, &data->service_loop_lock); 813 g_mutex_unlock (&data->service_loop_lock); 814 } 815 816 static gpointer 817 service_thread_func (gpointer user_data) 818 { 819 PeerConnection *data = user_data; 820 GMainContext *service_context; 821 GError *error; 822 gchar *address; 823 gchar *tmpdir; 824 GDBusServerFlags flags; 825 gchar *guid; 826 827 service_context = g_main_context_new (); 828 g_main_context_push_thread_default (service_context); 829 830 tmpdir = NULL; 831 flags = G_DBUS_SERVER_FLAGS_NONE; 832 833 #ifdef G_OS_UNIX 834 if (g_unix_socket_address_abstract_names_supported ()) 835 address = g_strdup ("unix:tmpdir=/tmp/test-dbus-peer"); 836 else 837 { 838 tmpdir = g_dir_make_tmp ("test-dbus-peer-XXXXXX", NULL); 839 address = g_strdup_printf ("unix:tmpdir=%s", tmpdir); 840 } 841 #else 842 address = g_strdup ("nonce-tcp:"); 843 flags |= G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS; 844 #endif 845 846 guid = g_dbus_generate_guid (); 847 848 error = NULL; 849 data->server = g_dbus_server_new_sync (address, 850 flags, 851 guid, 852 NULL, 853 NULL, 854 &error); 855 g_assert_no_error (error); 856 g_free (address); 857 g_free (guid); 858 859 g_signal_connect (data->server, 860 "new-connection", 861 G_CALLBACK (on_new_connection), 862 data); 863 864 g_dbus_server_start (data->server); 865 866 create_service_loop (service_context, data); 867 g_main_loop_run (data->service_loop); 868 869 g_main_context_pop_thread_default (service_context); 870 871 teardown_service_loop (data); 872 g_main_context_unref (service_context); 873 874 if (tmpdir) 875 { 876 g_rmdir (tmpdir); 877 g_free (tmpdir); 878 } 879 880 return NULL; 881 } 882 883 static void 884 peer_connection_up (PeerConnection *data) 885 { 886 GError *error; 887 888 memset (data, '\0', sizeof (PeerConnection)); 889 890 g_mutex_init (&data->service_loop_lock); 891 g_cond_init (&data->service_loop_cond); 892 893 /* bring up a server - we run the server in a different thread to 894 avoid deadlocks */ 895 data->service_thread = g_thread_new ("test_dbus_peer", 896 service_thread_func, 897 data); 898 await_service_loop (data); 899 g_assert (data->server != NULL); 900 901 /* bring up a connection and accept it */ 902 error = NULL; 903 data->client_connection = 904 g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (data->server), 905 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT, 906 NULL, /* GDBusAuthObserver */ 907 NULL, /* cancellable */ 908 &error); 909 g_assert_no_error (error); 910 g_assert (data->client_connection != NULL); 911 await_server_connection (data); 912 } 913 914 static void 915 peer_connection_down (PeerConnection *data) 916 { 917 g_object_unref (data->client_connection); 918 g_object_unref (data->server_connection); 919 920 g_dbus_server_stop (data->server); 921 g_object_unref (data->server); 922 923 g_main_loop_quit (data->service_loop); 924 g_thread_join (data->service_thread); 925 926 g_mutex_clear (&data->service_loop_lock); 927 g_cond_clear (&data->service_loop_cond); 928 } 929 930 struct roundtrip_state 931 { 932 RandomMenu *random; 933 MirrorMenu *proxy_mirror; 934 GDBusMenuModel *proxy; 935 GMainLoop *loop; 936 GRand *rand; 937 gint success; 938 gint count; 939 }; 940 941 static gboolean 942 roundtrip_step (gpointer data) 943 { 944 struct roundtrip_state *state = data; 945 946 if (check_menus_equal (G_MENU_MODEL (state->random), G_MENU_MODEL (state->proxy)) && 947 check_menus_equal (G_MENU_MODEL (state->random), G_MENU_MODEL (state->proxy_mirror))) 948 { 949 state->success++; 950 state->count = 0; 951 952 if (state->success < 100) 953 random_menu_change (state->random, state->rand); 954 else 955 g_main_loop_quit (state->loop); 956 } 957 else if (state->count == 100) 958 { 959 assert_menus_equal (G_MENU_MODEL (state->random), G_MENU_MODEL (state->proxy)); 960 g_assert_not_reached (); 961 } 962 else 963 state->count++; 964 965 return G_SOURCE_CONTINUE; 966 } 967 968 static void 969 do_roundtrip (GDBusConnection *exporter_connection, 970 GDBusConnection *proxy_connection) 971 { 972 struct roundtrip_state state; 973 guint export_id; 974 guint id; 975 976 state.rand = g_rand_new_with_seed (g_test_rand_int ()); 977 978 state.random = random_menu_new (state.rand, 2); 979 export_id = g_dbus_connection_export_menu_model (exporter_connection, 980 "/", 981 G_MENU_MODEL (state.random), 982 NULL); 983 state.proxy = g_dbus_menu_model_get (proxy_connection, 984 g_dbus_connection_get_unique_name (proxy_connection), 985 "/"); 986 state.proxy_mirror = mirror_menu_new (G_MENU_MODEL (state.proxy)); 987 state.count = 0; 988 state.success = 0; 989 990 id = g_timeout_add (10, roundtrip_step, &state); 991 992 state.loop = g_main_loop_new (NULL, FALSE); 993 g_main_loop_run (state.loop); 994 995 g_main_loop_unref (state.loop); 996 g_source_remove (id); 997 g_object_unref (state.proxy); 998 g_dbus_connection_unexport_menu_model (exporter_connection, export_id); 999 g_object_unref (state.random); 1000 g_object_unref (state.proxy_mirror); 1001 g_rand_free (state.rand); 1002 } 1003 1004 static void 1005 test_dbus_roundtrip (void) 1006 { 1007 GDBusConnection *bus; 1008 1009 bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL); 1010 do_roundtrip (bus, bus); 1011 g_object_unref (bus); 1012 } 1013 1014 static void 1015 test_dbus_peer_roundtrip (void) 1016 { 1017 #ifdef _GLIB_ADDRESS_SANITIZER 1018 g_test_incomplete ("FIXME: Leaks a GCancellableSource, see glib#2313"); 1019 (void) peer_connection_up; 1020 (void) peer_connection_down; 1021 #else 1022 PeerConnection peer; 1023 1024 peer_connection_up (&peer); 1025 do_roundtrip (peer.server_connection, peer.client_connection); 1026 peer_connection_down (&peer); 1027 #endif 1028 } 1029 1030 static gint items_changed_count; 1031 1032 static void 1033 items_changed (GMenuModel *model, 1034 gint position, 1035 gint removed, 1036 gint added, 1037 gpointer data) 1038 { 1039 items_changed_count++; 1040 } 1041 1042 static gboolean 1043 stop_loop (gpointer data) 1044 { 1045 GMainLoop *loop = data; 1046 1047 g_main_loop_quit (loop); 1048 1049 return G_SOURCE_REMOVE; 1050 } 1051 1052 static void 1053 do_subscriptions (GDBusConnection *exporter_connection, 1054 GDBusConnection *proxy_connection) 1055 { 1056 GMenu *menu; 1057 GDBusMenuModel *proxy; 1058 GMainLoop *loop; 1059 GError *error = NULL; 1060 guint export_id; 1061 guint timeout_id; 1062 1063 timeout_id = add_timeout (60); 1064 loop = g_main_loop_new (NULL, FALSE); 1065 1066 menu = g_menu_new (); 1067 1068 export_id = g_dbus_connection_export_menu_model (exporter_connection, 1069 "/", 1070 G_MENU_MODEL (menu), 1071 &error); 1072 g_assert_no_error (error); 1073 1074 proxy = g_dbus_menu_model_get (proxy_connection, 1075 g_dbus_connection_get_unique_name (proxy_connection), 1076 "/"); 1077 items_changed_count = 0; 1078 g_signal_connect (proxy, "items-changed", 1079 G_CALLBACK (items_changed), NULL); 1080 1081 g_menu_append (menu, "item1", NULL); 1082 g_menu_append (menu, "item2", NULL); 1083 g_menu_append (menu, "item3", NULL); 1084 1085 g_assert_cmpint (items_changed_count, ==, 0); 1086 1087 /* We don't subscribe to change-notification until we look at the items */ 1088 g_timeout_add (100, stop_loop, loop); 1089 g_main_loop_run (loop); 1090 1091 /* Looking at the items triggers subscription */ 1092 g_menu_model_get_n_items (G_MENU_MODEL (proxy)); 1093 1094 while (items_changed_count < 1) 1095 g_main_context_iteration (NULL, TRUE); 1096 1097 /* We get all three items in one batch */ 1098 g_assert_cmpint (items_changed_count, ==, 1); 1099 g_assert_cmpint (g_menu_model_get_n_items (G_MENU_MODEL (proxy)), ==, 3); 1100 1101 /* If we wait, we don't get any more */ 1102 g_timeout_add (100, stop_loop, loop); 1103 g_main_loop_run (loop); 1104 g_assert_cmpint (items_changed_count, ==, 1); 1105 g_assert_cmpint (g_menu_model_get_n_items (G_MENU_MODEL (proxy)), ==, 3); 1106 1107 /* Now we're subscribed, we get changes individually */ 1108 g_menu_append (menu, "item4", NULL); 1109 g_menu_append (menu, "item5", NULL); 1110 g_menu_append (menu, "item6", NULL); 1111 g_menu_remove (menu, 0); 1112 g_menu_remove (menu, 0); 1113 1114 while (items_changed_count < 6) 1115 g_main_context_iteration (NULL, TRUE); 1116 1117 g_assert_cmpint (items_changed_count, ==, 6); 1118 1119 g_assert_cmpint (g_menu_model_get_n_items (G_MENU_MODEL (proxy)), ==, 4); 1120 1121 /* After destroying the proxy and waiting a bit, we don't get any more 1122 * items-changed signals */ 1123 g_object_unref (proxy); 1124 1125 g_timeout_add (100, stop_loop, loop); 1126 g_main_loop_run (loop); 1127 1128 g_menu_remove (menu, 0); 1129 g_menu_remove (menu, 0); 1130 1131 g_timeout_add (100, stop_loop, loop); 1132 g_main_loop_run (loop); 1133 1134 g_assert_cmpint (items_changed_count, ==, 6); 1135 1136 g_dbus_connection_unexport_menu_model (exporter_connection, export_id); 1137 g_object_unref (menu); 1138 1139 g_main_loop_unref (loop); 1140 cancel_timeout (timeout_id); 1141 } 1142 1143 static void 1144 test_dbus_subscriptions (void) 1145 { 1146 GDBusConnection *bus; 1147 1148 bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL); 1149 do_subscriptions (bus, bus); 1150 g_object_unref (bus); 1151 } 1152 1153 static void 1154 test_dbus_peer_subscriptions (void) 1155 { 1156 #ifdef _GLIB_ADDRESS_SANITIZER 1157 g_test_incomplete ("FIXME: Leaks a GCancellableSource, see glib#2313"); 1158 (void) peer_connection_up; 1159 (void) peer_connection_down; 1160 #else 1161 PeerConnection peer; 1162 1163 peer_connection_up (&peer); 1164 do_subscriptions (peer.server_connection, peer.client_connection); 1165 peer_connection_down (&peer); 1166 #endif 1167 } 1168 1169 static gpointer 1170 do_modify (gpointer data) 1171 { 1172 RandomMenu *menu = data; 1173 GRand *rand; 1174 gint i; 1175 1176 rand = g_rand_new_with_seed (g_test_rand_int ()); 1177 1178 for (i = 0; i < 10000; i++) 1179 { 1180 random_menu_change (menu, rand); 1181 } 1182 1183 g_rand_free (rand); 1184 1185 return NULL; 1186 } 1187 1188 static gpointer 1189 do_export (gpointer data) 1190 { 1191 GMenuModel *menu = data; 1192 gint i; 1193 GDBusConnection *bus; 1194 gchar *path; 1195 GError *error = NULL; 1196 guint id; 1197 1198 bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL); 1199 path = g_strdup_printf ("/%p", data); 1200 1201 for (i = 0; i < 10000; i++) 1202 { 1203 id = g_dbus_connection_export_menu_model (bus, path, menu, &error); 1204 g_assert_no_error (error); 1205 g_dbus_connection_unexport_menu_model (bus, id); 1206 while (g_main_context_iteration (NULL, FALSE)); 1207 } 1208 1209 g_free (path); 1210 1211 g_object_unref (bus); 1212 1213 return NULL; 1214 } 1215 1216 static void 1217 test_dbus_threaded (void) 1218 { 1219 RandomMenu *menu[10]; 1220 GThread *call[10]; 1221 GThread *export[10]; 1222 gint i; 1223 1224 for (i = 0; i < 10; i++) 1225 { 1226 GRand *rand = g_rand_new_with_seed (g_test_rand_int ()); 1227 menu[i] = random_menu_new (rand, 2); 1228 call[i] = g_thread_new ("call", do_modify, menu[i]); 1229 export[i] = g_thread_new ("export", do_export, menu[i]); 1230 g_rand_free (rand); 1231 } 1232 1233 for (i = 0; i < 10; i++) 1234 { 1235 g_thread_join (call[i]); 1236 g_thread_join (export[i]); 1237 } 1238 1239 for (i = 0; i < 10; i++) 1240 g_object_unref (menu[i]); 1241 } 1242 1243 static void 1244 test_attributes (void) 1245 { 1246 GMenu *menu; 1247 GMenuItem *item; 1248 GVariant *v; 1249 1250 menu = g_menu_new (); 1251 1252 item = g_menu_item_new ("test", NULL); 1253 g_menu_item_set_attribute_value (item, "boolean", g_variant_new_boolean (FALSE)); 1254 g_menu_item_set_attribute_value (item, "string", g_variant_new_string ("bla")); 1255 1256 g_menu_item_set_attribute (item, "double", "d", 1.5); 1257 v = g_variant_new_parsed ("[('one', 1), ('two', %i), (%s, 3)]", 2, "three"); 1258 g_menu_item_set_attribute_value (item, "complex", v); 1259 g_menu_item_set_attribute_value (item, "test-123", g_variant_new_string ("test-123")); 1260 1261 g_menu_append_item (menu, item); 1262 1263 g_menu_item_set_attribute (item, "double", "d", G_PI); 1264 1265 g_assert_cmpint (g_menu_model_get_n_items (G_MENU_MODEL (menu)), ==, 1); 1266 1267 v = g_menu_model_get_item_attribute_value (G_MENU_MODEL (menu), 0, "boolean", NULL); 1268 g_assert (g_variant_is_of_type (v, G_VARIANT_TYPE_BOOLEAN)); 1269 g_variant_unref (v); 1270 1271 v = g_menu_model_get_item_attribute_value (G_MENU_MODEL (menu), 0, "string", NULL); 1272 g_assert (g_variant_is_of_type (v, G_VARIANT_TYPE_STRING)); 1273 g_variant_unref (v); 1274 1275 v = g_menu_model_get_item_attribute_value (G_MENU_MODEL (menu), 0, "double", NULL); 1276 g_assert (g_variant_is_of_type (v, G_VARIANT_TYPE_DOUBLE)); 1277 g_variant_unref (v); 1278 1279 v = g_menu_model_get_item_attribute_value (G_MENU_MODEL (menu), 0, "complex", NULL); 1280 g_assert (g_variant_is_of_type (v, G_VARIANT_TYPE("a(si)"))); 1281 g_variant_unref (v); 1282 1283 g_menu_remove_all (menu); 1284 1285 g_object_unref (menu); 1286 g_object_unref (item); 1287 } 1288 1289 static void 1290 test_attribute_iter (void) 1291 { 1292 GMenu *menu; 1293 GMenuItem *item; 1294 const gchar *name; 1295 GVariant *v; 1296 GMenuAttributeIter *iter; 1297 GHashTable *found; 1298 1299 menu = g_menu_new (); 1300 1301 item = g_menu_item_new ("test", NULL); 1302 g_menu_item_set_attribute_value (item, "boolean", g_variant_new_boolean (FALSE)); 1303 g_menu_item_set_attribute_value (item, "string", g_variant_new_string ("bla")); 1304 1305 g_menu_item_set_attribute (item, "double", "d", 1.5); 1306 v = g_variant_new_parsed ("[('one', 1), ('two', %i), (%s, 3)]", 2, "three"); 1307 g_menu_item_set_attribute_value (item, "complex", v); 1308 g_menu_item_set_attribute_value (item, "test-123", g_variant_new_string ("test-123")); 1309 1310 g_menu_append_item (menu, item); 1311 1312 g_menu_item_set_attribute (item, "double", "d", G_PI); 1313 1314 g_assert_cmpint (g_menu_model_get_n_items (G_MENU_MODEL (menu)), ==, 1); 1315 1316 found = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_variant_unref); 1317 1318 iter = g_menu_model_iterate_item_attributes (G_MENU_MODEL (menu), 0); 1319 while (g_menu_attribute_iter_get_next (iter, &name, &v)) 1320 g_hash_table_insert (found, g_strdup (name), v); 1321 1322 g_assert_cmpint (g_hash_table_size (found), ==, 6); 1323 1324 v = g_hash_table_lookup (found, "label"); 1325 g_assert (g_variant_is_of_type (v, G_VARIANT_TYPE_STRING)); 1326 1327 v = g_hash_table_lookup (found, "boolean"); 1328 g_assert (g_variant_is_of_type (v, G_VARIANT_TYPE_BOOLEAN)); 1329 1330 v = g_hash_table_lookup (found, "string"); 1331 g_assert (g_variant_is_of_type (v, G_VARIANT_TYPE_STRING)); 1332 1333 v = g_hash_table_lookup (found, "double"); 1334 g_assert (g_variant_is_of_type (v, G_VARIANT_TYPE_DOUBLE)); 1335 1336 v = g_hash_table_lookup (found, "complex"); 1337 g_assert (g_variant_is_of_type (v, G_VARIANT_TYPE("a(si)"))); 1338 1339 v = g_hash_table_lookup (found, "test-123"); 1340 g_assert (g_variant_is_of_type (v, G_VARIANT_TYPE_STRING)); 1341 1342 g_hash_table_unref (found); 1343 1344 g_menu_remove_all (menu); 1345 1346 g_object_unref (menu); 1347 g_object_unref (item); 1348 } 1349 1350 static void 1351 test_links (void) 1352 { 1353 GMenu *menu; 1354 GMenuModel *m; 1355 GMenuModel *x; 1356 GMenuItem *item; 1357 1358 m = G_MENU_MODEL (g_menu_new ()); 1359 g_menu_append (G_MENU (m), "test", NULL); 1360 1361 menu = g_menu_new (); 1362 1363 item = g_menu_item_new ("test2", NULL); 1364 g_menu_item_set_link (item, "submenu", m); 1365 g_menu_prepend_item (menu, item); 1366 1367 item = g_menu_item_new ("test1", NULL); 1368 g_menu_item_set_link (item, "section", m); 1369 g_menu_insert_item (menu, 0, item); 1370 1371 item = g_menu_item_new ("test3", NULL); 1372 g_menu_item_set_link (item, "wallet", m); 1373 g_menu_insert_item (menu, 1000, item); 1374 1375 item = g_menu_item_new ("test4", NULL); 1376 g_menu_item_set_link (item, "purse", m); 1377 g_menu_item_set_link (item, "purse", NULL); 1378 g_menu_append_item (menu, item); 1379 1380 g_assert_cmpint (g_menu_model_get_n_items (G_MENU_MODEL (menu)), ==, 4); 1381 1382 x = g_menu_model_get_item_link (G_MENU_MODEL (menu), 0, "section"); 1383 g_assert (x == m); 1384 g_object_unref (x); 1385 1386 x = g_menu_model_get_item_link (G_MENU_MODEL (menu), 1, "submenu"); 1387 g_assert (x == m); 1388 g_object_unref (x); 1389 1390 x = g_menu_model_get_item_link (G_MENU_MODEL (menu), 2, "wallet"); 1391 g_assert (x == m); 1392 g_object_unref (x); 1393 1394 x = g_menu_model_get_item_link (G_MENU_MODEL (menu), 3, "purse"); 1395 g_assert (x == NULL); 1396 1397 g_object_unref (m); 1398 g_object_unref (menu); 1399 } 1400 1401 static void 1402 test_mutable (void) 1403 { 1404 GMenu *menu; 1405 1406 menu = g_menu_new (); 1407 g_menu_append (menu, "test", "test"); 1408 1409 g_assert (g_menu_model_is_mutable (G_MENU_MODEL (menu))); 1410 g_menu_freeze (menu); 1411 g_assert (!g_menu_model_is_mutable (G_MENU_MODEL (menu))); 1412 1413 g_object_unref (menu); 1414 } 1415 1416 static void 1417 test_convenience (void) 1418 { 1419 GMenu *m1, *m2; 1420 GMenu *sub; 1421 GMenuItem *item; 1422 1423 m1 = g_menu_new (); 1424 m2 = g_menu_new (); 1425 sub = g_menu_new (); 1426 1427 g_menu_prepend (m1, "label1", "do::something"); 1428 g_menu_insert (m2, 0, "label1", "do::something"); 1429 1430 g_menu_append (m1, "label2", "do::somethingelse"); 1431 g_menu_insert (m2, -1, "label2", "do::somethingelse"); 1432 1433 g_menu_insert_section (m1, 10, "label3", G_MENU_MODEL (sub)); 1434 item = g_menu_item_new_section ("label3", G_MENU_MODEL (sub)); 1435 g_menu_insert_item (m2, 10, item); 1436 g_object_unref (item); 1437 1438 g_menu_prepend_section (m1, "label4", G_MENU_MODEL (sub)); 1439 g_menu_insert_section (m2, 0, "label4", G_MENU_MODEL (sub)); 1440 1441 g_menu_append_section (m1, "label5", G_MENU_MODEL (sub)); 1442 g_menu_insert_section (m2, -1, "label5", G_MENU_MODEL (sub)); 1443 1444 g_menu_insert_submenu (m1, 5, "label6", G_MENU_MODEL (sub)); 1445 item = g_menu_item_new_submenu ("label6", G_MENU_MODEL (sub)); 1446 g_menu_insert_item (m2, 5, item); 1447 g_object_unref (item); 1448 1449 g_menu_prepend_submenu (m1, "label7", G_MENU_MODEL (sub)); 1450 g_menu_insert_submenu (m2, 0, "label7", G_MENU_MODEL (sub)); 1451 1452 g_menu_append_submenu (m1, "label8", G_MENU_MODEL (sub)); 1453 g_menu_insert_submenu (m2, -1, "label8", G_MENU_MODEL (sub)); 1454 1455 assert_menus_equal (G_MENU_MODEL (m1), G_MENU_MODEL (m2)); 1456 1457 g_object_unref (m1); 1458 g_object_unref (m2); 1459 } 1460 1461 static void 1462 test_menuitem (void) 1463 { 1464 GMenu *menu; 1465 GMenu *submenu; 1466 GMenuItem *item; 1467 GIcon *icon; 1468 gboolean b; 1469 gchar *s; 1470 1471 menu = g_menu_new (); 1472 submenu = g_menu_new (); 1473 1474 item = g_menu_item_new ("label", "action"); 1475 g_menu_item_set_attribute (item, "attribute", "b", TRUE); 1476 g_menu_item_set_link (item, G_MENU_LINK_SUBMENU, G_MENU_MODEL (submenu)); 1477 g_menu_append_item (menu, item); 1478 1479 icon = g_themed_icon_new ("bla"); 1480 g_menu_item_set_icon (item, icon); 1481 g_object_unref (icon); 1482 1483 g_assert (g_menu_item_get_attribute (item, "attribute", "b", &b)); 1484 g_assert (b); 1485 1486 g_menu_item_set_action_and_target (item, "action", "(bs)", TRUE, "string"); 1487 g_assert (g_menu_item_get_attribute (item, "target", "(bs)", &b, &s)); 1488 g_assert (b); 1489 g_assert_cmpstr (s, ==, "string"); 1490 g_free (s); 1491 1492 g_object_unref (item); 1493 1494 item = g_menu_item_new_from_model (G_MENU_MODEL (menu), 0); 1495 assert_menuitem_equal (item, G_MENU_MODEL (menu), 0); 1496 g_object_unref (item); 1497 1498 g_object_unref (menu); 1499 g_object_unref (submenu); 1500 } 1501 1502 /* Epilogue {{{1 */ 1503 int 1504 main (int argc, char **argv) 1505 { 1506 gboolean ret; 1507 1508 g_test_init (&argc, &argv, NULL); 1509 1510 session_bus_up (); 1511 1512 g_test_add_func ("/gmenu/equality", test_equality); 1513 g_test_add_func ("/gmenu/random", test_random); 1514 g_test_add_func ("/gmenu/dbus/roundtrip", test_dbus_roundtrip); 1515 g_test_add_func ("/gmenu/dbus/subscriptions", test_dbus_subscriptions); 1516 g_test_add_func ("/gmenu/dbus/threaded", test_dbus_threaded); 1517 g_test_add_func ("/gmenu/dbus/peer/roundtrip", test_dbus_peer_roundtrip); 1518 g_test_add_func ("/gmenu/dbus/peer/subscriptions", test_dbus_peer_subscriptions); 1519 g_test_add_func ("/gmenu/attributes", test_attributes); 1520 g_test_add_func ("/gmenu/attributes/iterate", test_attribute_iter); 1521 g_test_add_func ("/gmenu/links", test_links); 1522 g_test_add_func ("/gmenu/mutable", test_mutable); 1523 g_test_add_func ("/gmenu/convenience", test_convenience); 1524 g_test_add_func ("/gmenu/menuitem", test_menuitem); 1525 1526 ret = g_test_run (); 1527 1528 session_bus_down (); 1529 1530 return ret; 1531 } 1532 /* vim:set foldmethod=marker: */ 1533