Blame gio/tests/gmenumodel.c

Packit ae235b
#include <gio/gio.h>
Packit ae235b
#include <gio/gunixsocketaddress.h>
Packit ae235b
#include <glib/gstdio.h>
Packit ae235b
#include <string.h>
Packit ae235b
Packit ae235b
#include "gdbus-sessionbus.h"
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
time_out (gpointer unused G_GNUC_UNUSED)
Packit ae235b
{
Packit ae235b
  g_error ("Timed out");
Packit ae235b
  /* not reached */
Packit ae235b
  return FALSE;
Packit ae235b
}
Packit ae235b
Packit ae235b
static guint
Packit ae235b
add_timeout (guint seconds)
Packit ae235b
{
Packit ae235b
#ifdef G_OS_UNIX
Packit ae235b
  /* Safety-catch against the main loop having blocked */
Packit ae235b
  alarm (seconds + 5);
Packit ae235b
#endif
Packit ae235b
  return g_timeout_add_seconds (seconds, time_out, NULL);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
cancel_timeout (guint timeout_id)
Packit ae235b
{
Packit ae235b
#ifdef G_OS_UNIX
Packit ae235b
  alarm (0);
Packit ae235b
#endif
Packit ae235b
  g_source_remove (timeout_id);
Packit ae235b
}
Packit ae235b
Packit ae235b
/* Markup printing {{{1 */
Packit ae235b
Packit ae235b
/* This used to be part of GLib, but it was removed before the stable
Packit ae235b
 * release because it wasn't generally useful.  We want it here, though.
Packit ae235b
 */
Packit ae235b
static void
Packit ae235b
indent_string (GString *string,
Packit ae235b
               gint     indent)
Packit ae235b
{
Packit ae235b
  while (indent--)
Packit ae235b
    g_string_append_c (string, ' ');
Packit ae235b
}
Packit ae235b
Packit ae235b
static GString *
Packit ae235b
g_menu_markup_print_string (GString    *string,
Packit ae235b
                            GMenuModel *model,
Packit ae235b
                            gint        indent,
Packit ae235b
                            gint        tabstop)
Packit ae235b
{
Packit ae235b
  gboolean need_nl = FALSE;
Packit ae235b
  gint i, n;
Packit ae235b
Packit ae235b
  if G_UNLIKELY (string == NULL)
Packit ae235b
    string = g_string_new (NULL);
Packit ae235b
Packit ae235b
  n = g_menu_model_get_n_items (model);
Packit ae235b
Packit ae235b
  for (i = 0; i < n; i++)
Packit ae235b
    {
Packit ae235b
      GMenuAttributeIter *attr_iter;
Packit ae235b
      GMenuLinkIter *link_iter;
Packit ae235b
      GString *contents;
Packit ae235b
      GString *attrs;
Packit ae235b
Packit ae235b
      attr_iter = g_menu_model_iterate_item_attributes (model, i);
Packit ae235b
      link_iter = g_menu_model_iterate_item_links (model, i);
Packit ae235b
      contents = g_string_new (NULL);
Packit ae235b
      attrs = g_string_new (NULL);
Packit ae235b
Packit ae235b
      while (g_menu_attribute_iter_next (attr_iter))
Packit ae235b
        {
Packit ae235b
          const char *name = g_menu_attribute_iter_get_name (attr_iter);
Packit ae235b
          GVariant *value = g_menu_attribute_iter_get_value (attr_iter);
Packit ae235b
Packit ae235b
          if (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
Packit ae235b
            {
Packit ae235b
              gchar *str;
Packit ae235b
              str = g_markup_printf_escaped (" %s='%s'", name, g_variant_get_string (value, NULL));
Packit ae235b
              g_string_append (attrs, str);
Packit ae235b
              g_free (str);
Packit ae235b
            }
Packit ae235b
Packit ae235b
          else
Packit ae235b
            {
Packit ae235b
              gchar *printed;
Packit ae235b
              gchar *str;
Packit ae235b
              const gchar *type;
Packit ae235b
Packit ae235b
              printed = g_variant_print (value, TRUE);
Packit ae235b
              type = g_variant_type_peek_string (g_variant_get_type (value));
Packit ae235b
              str = g_markup_printf_escaped ("<attribute name='%s' type='%s'>%s</attribute>\n", name, type, printed);
Packit ae235b
              indent_string (contents, indent + tabstop);
Packit ae235b
              g_string_append (contents, str);
Packit ae235b
              g_free (printed);
Packit ae235b
              g_free (str);
Packit ae235b
            }
Packit ae235b
Packit ae235b
          g_variant_unref (value);
Packit ae235b
        }
Packit ae235b
      g_object_unref (attr_iter);
Packit ae235b
Packit ae235b
      while (g_menu_link_iter_next (link_iter))
Packit ae235b
        {
Packit ae235b
          const gchar *name = g_menu_link_iter_get_name (link_iter);
Packit ae235b
          GMenuModel *menu = g_menu_link_iter_get_value (link_iter);
Packit ae235b
          gchar *str;
Packit ae235b
Packit ae235b
          if (contents->str[0])
Packit ae235b
            g_string_append_c (contents, '\n');
Packit ae235b
Packit ae235b
          str = g_markup_printf_escaped ("<link name='%s'>\n", name);
Packit ae235b
          indent_string (contents, indent + tabstop);
Packit ae235b
          g_string_append (contents, str);
Packit ae235b
          g_free (str);
Packit ae235b
Packit ae235b
          g_menu_markup_print_string (contents, menu, indent + 2 * tabstop, tabstop);
Packit ae235b
Packit ae235b
          indent_string (contents, indent + tabstop);
Packit ae235b
          g_string_append (contents, "</link>\n");
Packit ae235b
          g_object_unref (menu);
Packit ae235b
        }
Packit ae235b
      g_object_unref (link_iter);
Packit ae235b
Packit ae235b
      if (contents->str[0])
Packit ae235b
        {
Packit ae235b
          indent_string (string, indent);
Packit ae235b
          g_string_append_printf (string, "<item%s>\n", attrs->str);
Packit ae235b
          g_string_append (string, contents->str);
Packit ae235b
          indent_string (string, indent);
Packit ae235b
          g_string_append (string, "</item>\n");
Packit ae235b
          need_nl = TRUE;
Packit ae235b
        }
Packit ae235b
Packit ae235b
      else
Packit ae235b
        {
Packit ae235b
          if (need_nl)
Packit ae235b
            g_string_append_c (string, '\n');
Packit ae235b
Packit ae235b
          indent_string (string, indent);
Packit ae235b
          g_string_append_printf (string, "<item%s/>\n", attrs->str);
Packit ae235b
          need_nl = FALSE;
Packit ae235b
        }
Packit ae235b
Packit ae235b
      g_string_free (contents, TRUE);
Packit ae235b
      g_string_free (attrs, TRUE);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  return string;
Packit ae235b
}
Packit ae235b
Packit ae235b
/* TestItem {{{1 */
Packit ae235b
Packit ae235b
/* This utility struct is used by both the RandomMenu and MirrorMenu
Packit ae235b
 * class implementations below.
Packit ae235b
 */
Packit ae235b
typedef struct {
Packit ae235b
  GHashTable *attributes;
Packit ae235b
  GHashTable *links;
Packit ae235b
} TestItem;
Packit ae235b
Packit ae235b
static TestItem *
Packit ae235b
test_item_new (GHashTable *attributes,
Packit ae235b
               GHashTable *links)
Packit ae235b
{
Packit ae235b
  TestItem *item;
Packit ae235b
Packit ae235b
  item = g_slice_new (TestItem);
Packit ae235b
  item->attributes = g_hash_table_ref (attributes);
Packit ae235b
  item->links = g_hash_table_ref (links);
Packit ae235b
Packit ae235b
  return item;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
test_item_free (gpointer data)
Packit ae235b
{
Packit ae235b
  TestItem *item = data;
Packit ae235b
Packit ae235b
  g_hash_table_unref (item->attributes);
Packit ae235b
  g_hash_table_unref (item->links);
Packit ae235b
Packit ae235b
  g_slice_free (TestItem, item);
Packit ae235b
}
Packit ae235b
Packit ae235b
/* RandomMenu {{{1 */
Packit ae235b
#define MAX_ITEMS 5
Packit ae235b
#define TOP_ORDER 4
Packit ae235b
Packit ae235b
typedef struct {
Packit ae235b
  GMenuModel parent_instance;
Packit ae235b
Packit ae235b
  GSequence *items;
Packit ae235b
  gint order;
Packit ae235b
} RandomMenu;
Packit ae235b
Packit ae235b
typedef GMenuModelClass RandomMenuClass;
Packit ae235b
Packit ae235b
static GType random_menu_get_type (void);
Packit ae235b
G_DEFINE_TYPE (RandomMenu, random_menu, G_TYPE_MENU_MODEL)
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
random_menu_is_mutable (GMenuModel *model)
Packit ae235b
{
Packit ae235b
  return TRUE;
Packit ae235b
}
Packit ae235b
Packit ae235b
static gint
Packit ae235b
random_menu_get_n_items (GMenuModel *model)
Packit ae235b
{
Packit ae235b
  RandomMenu *menu = (RandomMenu *) model;
Packit ae235b
Packit ae235b
  return g_sequence_get_length (menu->items);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
random_menu_get_item_attributes (GMenuModel  *model,
Packit ae235b
                                 gint         position,
Packit ae235b
                                 GHashTable **table)
Packit ae235b
{
Packit ae235b
  RandomMenu *menu = (RandomMenu *) model;
Packit ae235b
  TestItem *item;
Packit ae235b
Packit ae235b
  item = g_sequence_get (g_sequence_get_iter_at_pos (menu->items, position));
Packit ae235b
  *table = g_hash_table_ref (item->attributes);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
random_menu_get_item_links (GMenuModel  *model,
Packit ae235b
                            gint         position,
Packit ae235b
                            GHashTable **table)
Packit ae235b
{
Packit ae235b
  RandomMenu *menu = (RandomMenu *) model;
Packit ae235b
  TestItem *item;
Packit ae235b
Packit ae235b
  item = g_sequence_get (g_sequence_get_iter_at_pos (menu->items, position));
Packit ae235b
  *table = g_hash_table_ref (item->links);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
random_menu_finalize (GObject *object)
Packit ae235b
{
Packit ae235b
  RandomMenu *menu = (RandomMenu *) object;
Packit ae235b
Packit ae235b
  g_sequence_free (menu->items);
Packit ae235b
Packit ae235b
  G_OBJECT_CLASS (random_menu_parent_class)
Packit ae235b
    ->finalize (object);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
random_menu_init (RandomMenu *menu)
Packit ae235b
{
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
random_menu_class_init (GMenuModelClass *class)
Packit ae235b
{
Packit ae235b
  GObjectClass *object_class = G_OBJECT_CLASS (class);
Packit ae235b
Packit ae235b
  class->is_mutable = random_menu_is_mutable;
Packit ae235b
  class->get_n_items = random_menu_get_n_items;
Packit ae235b
  class->get_item_attributes = random_menu_get_item_attributes;
Packit ae235b
  class->get_item_links = random_menu_get_item_links;
Packit ae235b
Packit ae235b
  object_class->finalize = random_menu_finalize;
Packit ae235b
}
Packit ae235b
Packit ae235b
static RandomMenu * random_menu_new (GRand *rand, gint order);
Packit ae235b
Packit ae235b
static void
Packit ae235b
random_menu_change (RandomMenu *menu,
Packit ae235b
                    GRand      *rand)
Packit ae235b
{
Packit ae235b
  gint position, removes, adds;
Packit ae235b
  GSequenceIter *point;
Packit ae235b
  gint n_items;
Packit ae235b
  gint i;
Packit ae235b
Packit ae235b
  n_items = g_sequence_get_length (menu->items);
Packit ae235b
Packit ae235b
  do
Packit ae235b
    {
Packit ae235b
      position = g_rand_int_range (rand, 0, n_items + 1);
Packit ae235b
      removes = g_rand_int_range (rand, 0, n_items - position + 1);
Packit ae235b
      adds = g_rand_int_range (rand, 0, MAX_ITEMS - (n_items - removes) + 1);
Packit ae235b
    }
Packit ae235b
  while (removes == 0 && adds == 0);
Packit ae235b
Packit ae235b
  point = g_sequence_get_iter_at_pos (menu->items, position + removes);
Packit ae235b
Packit ae235b
  if (removes)
Packit ae235b
    {
Packit ae235b
      GSequenceIter *start;
Packit ae235b
Packit ae235b
      start = g_sequence_get_iter_at_pos (menu->items, position);
Packit ae235b
      g_sequence_remove_range (start, point);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  for (i = 0; i < adds; i++)
Packit ae235b
    {
Packit ae235b
      const gchar *label;
Packit ae235b
      GHashTable *links;
Packit ae235b
      GHashTable *attributes;
Packit ae235b
Packit ae235b
      attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref);
Packit ae235b
      links = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_object_unref);
Packit ae235b
Packit ae235b
      if (menu->order > 0 && g_rand_boolean (rand))
Packit ae235b
        {
Packit ae235b
          RandomMenu *child;
Packit ae235b
	  const gchar *subtype;
Packit ae235b
Packit ae235b
          child = random_menu_new (rand, menu->order - 1);
Packit ae235b
Packit ae235b
          if (g_rand_boolean (rand))
Packit ae235b
            {
Packit ae235b
              subtype = G_MENU_LINK_SECTION;
Packit ae235b
              /* label some section headers */
Packit ae235b
              if (g_rand_boolean (rand))
Packit ae235b
                label = "Section";
Packit ae235b
              else
Packit ae235b
                label = NULL;
Packit ae235b
            }
Packit ae235b
          else
Packit ae235b
            {
Packit ae235b
              /* label all submenus */
Packit ae235b
              subtype = G_MENU_LINK_SUBMENU;
Packit ae235b
              label = "Submenu";
Packit ae235b
            }
Packit ae235b
Packit ae235b
          g_hash_table_insert (links, g_strdup (subtype), child);
Packit ae235b
        }
Packit ae235b
      else
Packit ae235b
        /* label all terminals */
Packit ae235b
        label = "Menu Item";
Packit ae235b
Packit ae235b
      if (label)
Packit ae235b
        g_hash_table_insert (attributes, g_strdup ("label"), g_variant_ref_sink (g_variant_new_string (label)));
Packit ae235b
Packit ae235b
      g_sequence_insert_before (point, test_item_new (attributes, links));
Packit ae235b
      g_hash_table_unref (links);
Packit ae235b
      g_hash_table_unref (attributes);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  g_menu_model_items_changed (G_MENU_MODEL (menu), position, removes, adds);
Packit ae235b
}
Packit ae235b
Packit ae235b
static RandomMenu *
Packit ae235b
random_menu_new (GRand *rand,
Packit ae235b
                 gint   order)
Packit ae235b
{
Packit ae235b
  RandomMenu *menu;
Packit ae235b
Packit ae235b
  menu = g_object_new (random_menu_get_type (), NULL);
Packit ae235b
  menu->items = g_sequence_new (test_item_free);
Packit ae235b
  menu->order = order;
Packit ae235b
Packit ae235b
  random_menu_change (menu, rand);
Packit ae235b
Packit ae235b
  return menu;
Packit ae235b
}
Packit ae235b
Packit ae235b
/* MirrorMenu {{{1 */
Packit ae235b
typedef struct {
Packit ae235b
  GMenuModel parent_instance;
Packit ae235b
Packit ae235b
  GMenuModel *clone_of;
Packit ae235b
  GSequence *items;
Packit ae235b
  gulong handler_id;
Packit ae235b
} MirrorMenu;
Packit ae235b
Packit ae235b
typedef GMenuModelClass MirrorMenuClass;
Packit ae235b
Packit ae235b
static GType mirror_menu_get_type (void);
Packit ae235b
G_DEFINE_TYPE (MirrorMenu, mirror_menu, G_TYPE_MENU_MODEL)
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
mirror_menu_is_mutable (GMenuModel *model)
Packit ae235b
{
Packit ae235b
  MirrorMenu *menu = (MirrorMenu *) model;
Packit ae235b
Packit ae235b
  return menu->handler_id != 0;
Packit ae235b
}
Packit ae235b
Packit ae235b
static gint
Packit ae235b
mirror_menu_get_n_items (GMenuModel *model)
Packit ae235b
{
Packit ae235b
  MirrorMenu *menu = (MirrorMenu *) model;
Packit ae235b
Packit ae235b
  return g_sequence_get_length (menu->items);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
mirror_menu_get_item_attributes (GMenuModel  *model,
Packit ae235b
                                 gint         position,
Packit ae235b
                                 GHashTable **table)
Packit ae235b
{
Packit ae235b
  MirrorMenu *menu = (MirrorMenu *) model;
Packit ae235b
  TestItem *item;
Packit ae235b
Packit ae235b
  item = g_sequence_get (g_sequence_get_iter_at_pos (menu->items, position));
Packit ae235b
  *table = g_hash_table_ref (item->attributes);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
mirror_menu_get_item_links (GMenuModel  *model,
Packit ae235b
                            gint         position,
Packit ae235b
                            GHashTable **table)
Packit ae235b
{
Packit ae235b
  MirrorMenu *menu = (MirrorMenu *) model;
Packit ae235b
  TestItem *item;
Packit ae235b
Packit ae235b
  item = g_sequence_get (g_sequence_get_iter_at_pos (menu->items, position));
Packit ae235b
  *table = g_hash_table_ref (item->links);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
mirror_menu_finalize (GObject *object)
Packit ae235b
{
Packit ae235b
  MirrorMenu *menu = (MirrorMenu *) object;
Packit ae235b
Packit ae235b
  if (menu->handler_id)
Packit ae235b
    g_signal_handler_disconnect (menu->clone_of, menu->handler_id);
Packit ae235b
Packit ae235b
  g_sequence_free (menu->items);
Packit ae235b
  g_object_unref (menu->clone_of);
Packit ae235b
Packit ae235b
  G_OBJECT_CLASS (mirror_menu_parent_class)
Packit ae235b
    ->finalize (object);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
mirror_menu_init (MirrorMenu *menu)
Packit ae235b
{
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
mirror_menu_class_init (GMenuModelClass *class)
Packit ae235b
{
Packit ae235b
  GObjectClass *object_class = G_OBJECT_CLASS (class);
Packit ae235b
Packit ae235b
  class->is_mutable = mirror_menu_is_mutable;
Packit ae235b
  class->get_n_items = mirror_menu_get_n_items;
Packit ae235b
  class->get_item_attributes = mirror_menu_get_item_attributes;
Packit ae235b
  class->get_item_links = mirror_menu_get_item_links;
Packit ae235b
Packit ae235b
  object_class->finalize = mirror_menu_finalize;
Packit ae235b
}
Packit ae235b
Packit ae235b
static MirrorMenu * mirror_menu_new (GMenuModel *clone_of);
Packit ae235b
Packit ae235b
static void
Packit ae235b
mirror_menu_changed (GMenuModel *model,
Packit ae235b
                     gint        position,
Packit ae235b
                     gint        removed,
Packit ae235b
                     gint        added,
Packit ae235b
                     gpointer    user_data)
Packit ae235b
{
Packit ae235b
  MirrorMenu *menu = user_data;
Packit ae235b
  GSequenceIter *point;
Packit ae235b
  gint i;
Packit ae235b
Packit ae235b
  g_assert (model == menu->clone_of);
Packit ae235b
Packit ae235b
  point = g_sequence_get_iter_at_pos (menu->items, position + removed);
Packit ae235b
Packit ae235b
  if (removed)
Packit ae235b
    {
Packit ae235b
      GSequenceIter *start;
Packit ae235b
Packit ae235b
      start = g_sequence_get_iter_at_pos (menu->items, position);
Packit ae235b
      g_sequence_remove_range (start, point);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  for (i = position; i < position + added; i++)
Packit ae235b
    {
Packit ae235b
      GMenuAttributeIter *attr_iter;
Packit ae235b
      GMenuLinkIter *link_iter;
Packit ae235b
      GHashTable *links;
Packit ae235b
      GHashTable *attributes;
Packit ae235b
      const gchar *name;
Packit ae235b
      GMenuModel *child;
Packit ae235b
      GVariant *value;
Packit ae235b
Packit ae235b
      attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref);
Packit ae235b
      links = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_object_unref);
Packit ae235b
Packit ae235b
      attr_iter = g_menu_model_iterate_item_attributes (model, i);
Packit ae235b
      while (g_menu_attribute_iter_get_next (attr_iter, &name, &value))
Packit ae235b
        {
Packit ae235b
          g_hash_table_insert (attributes, g_strdup (name), value);
Packit ae235b
        }
Packit ae235b
      g_object_unref (attr_iter);
Packit ae235b
Packit ae235b
      link_iter = g_menu_model_iterate_item_links (model, i);
Packit ae235b
      while (g_menu_link_iter_get_next (link_iter, &name, &child))
Packit ae235b
        {
Packit ae235b
          g_hash_table_insert (links, g_strdup (name), mirror_menu_new (child));
Packit ae235b
          g_object_unref (child);
Packit ae235b
        }
Packit ae235b
      g_object_unref (link_iter);
Packit ae235b
Packit ae235b
      g_sequence_insert_before (point, test_item_new (attributes, links));
Packit ae235b
      g_hash_table_unref (attributes);
Packit ae235b
      g_hash_table_unref (links);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  g_menu_model_items_changed (G_MENU_MODEL (menu), position, removed, added);
Packit ae235b
}
Packit ae235b
Packit ae235b
static MirrorMenu *
Packit ae235b
mirror_menu_new (GMenuModel *clone_of)
Packit ae235b
{
Packit ae235b
  MirrorMenu *menu;
Packit ae235b
Packit ae235b
  menu = g_object_new (mirror_menu_get_type (), NULL);
Packit ae235b
  menu->items = g_sequence_new (test_item_free);
Packit ae235b
  menu->clone_of = g_object_ref (clone_of);
Packit ae235b
Packit ae235b
  if (g_menu_model_is_mutable (clone_of))
Packit ae235b
    menu->handler_id = g_signal_connect (clone_of, "items-changed", G_CALLBACK (mirror_menu_changed), menu);
Packit ae235b
  mirror_menu_changed (clone_of, 0, 0, g_menu_model_get_n_items (clone_of), menu);
Packit ae235b
Packit ae235b
  return menu;
Packit ae235b
}
Packit ae235b
Packit ae235b
/* check_menus_equal(), assert_menus_equal() {{{1 */
Packit ae235b
static gboolean
Packit ae235b
check_menus_equal (GMenuModel *a,
Packit ae235b
                   GMenuModel *b)
Packit ae235b
{
Packit ae235b
  gboolean equal = TRUE;
Packit ae235b
  gint a_n, b_n;
Packit ae235b
  gint i;
Packit ae235b
Packit ae235b
  a_n = g_menu_model_get_n_items (a);
Packit ae235b
  b_n = g_menu_model_get_n_items (b);
Packit ae235b
Packit ae235b
  if (a_n != b_n)
Packit ae235b
    return FALSE;
Packit ae235b
Packit ae235b
  for (i = 0; i < a_n; i++)
Packit ae235b
    {
Packit ae235b
      GMenuAttributeIter *attr_iter;
Packit ae235b
      GVariant *a_value, *b_value;
Packit ae235b
      GMenuLinkIter *link_iter;
Packit ae235b
      GMenuModel *a_menu, *b_menu;
Packit ae235b
      const gchar *name;
Packit ae235b
Packit ae235b
      attr_iter = g_menu_model_iterate_item_attributes (a, i);
Packit ae235b
      while (g_menu_attribute_iter_get_next (attr_iter, &name, &a_value))
Packit ae235b
        {
Packit ae235b
          b_value = g_menu_model_get_item_attribute_value (b, i, name, NULL);
Packit ae235b
          equal &= b_value && g_variant_equal (a_value, b_value);
Packit ae235b
          if (b_value)
Packit ae235b
            g_variant_unref (b_value);
Packit ae235b
          g_variant_unref (a_value);
Packit ae235b
        }
Packit ae235b
      g_object_unref (attr_iter);
Packit ae235b
Packit ae235b
      attr_iter = g_menu_model_iterate_item_attributes (b, i);
Packit ae235b
      while (g_menu_attribute_iter_get_next (attr_iter, &name, &b_value))
Packit ae235b
        {
Packit ae235b
          a_value = g_menu_model_get_item_attribute_value (a, i, name, NULL);
Packit ae235b
          equal &= a_value && g_variant_equal (a_value, b_value);
Packit ae235b
          if (a_value)
Packit ae235b
            g_variant_unref (a_value);
Packit ae235b
          g_variant_unref (b_value);
Packit ae235b
        }
Packit ae235b
      g_object_unref (attr_iter);
Packit ae235b
Packit ae235b
      link_iter = g_menu_model_iterate_item_links (a, i);
Packit ae235b
      while (g_menu_link_iter_get_next (link_iter, &name, &a_menu))
Packit ae235b
        {
Packit ae235b
          b_menu = g_menu_model_get_item_link (b, i, name);
Packit ae235b
          equal &= b_menu && check_menus_equal (a_menu, b_menu);
Packit ae235b
          if (b_menu)
Packit ae235b
            g_object_unref (b_menu);
Packit ae235b
          g_object_unref (a_menu);
Packit ae235b
        }
Packit ae235b
      g_object_unref (link_iter);
Packit ae235b
Packit ae235b
      link_iter = g_menu_model_iterate_item_links (b, i);
Packit ae235b
      while (g_menu_link_iter_get_next (link_iter, &name, &b_menu))
Packit ae235b
        {
Packit ae235b
          a_menu = g_menu_model_get_item_link (a, i, name);
Packit ae235b
          equal &= a_menu && check_menus_equal (a_menu, b_menu);
Packit ae235b
          if (a_menu)
Packit ae235b
            g_object_unref (a_menu);
Packit ae235b
          g_object_unref (b_menu);
Packit ae235b
        }
Packit ae235b
      g_object_unref (link_iter);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  return equal;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
assert_menus_equal (GMenuModel *a,
Packit ae235b
                    GMenuModel *b)
Packit ae235b
{
Packit ae235b
  if (!check_menus_equal (a, b))
Packit ae235b
    {
Packit ae235b
      GString *string;
Packit ae235b
Packit ae235b
      string = g_string_new ("\n  \n");
Packit ae235b
      g_menu_markup_print_string (string, G_MENU_MODEL (a), 4, 2);
Packit ae235b
      g_string_append (string, "  \n\n-------------\n  \n");
Packit ae235b
      g_menu_markup_print_string (string, G_MENU_MODEL (b), 4, 2);
Packit ae235b
      g_string_append (string, "  \n");
Packit ae235b
      g_error ("%s", string->str);
Packit ae235b
    }
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
assert_menuitem_equal (GMenuItem  *item,
Packit ae235b
                       GMenuModel *model,
Packit ae235b
                       gint        index)
Packit ae235b
{
Packit ae235b
  GMenuAttributeIter *attr_iter;
Packit ae235b
  GMenuLinkIter *link_iter;
Packit ae235b
  const gchar *name;
Packit ae235b
  GVariant *value;
Packit ae235b
  GMenuModel *linked_model;
Packit ae235b
Packit ae235b
  /* NOTE we can't yet test whether item has attributes or links that
Packit ae235b
   * are not in the model, because there's no iterator API for menu
Packit ae235b
   * items */
Packit ae235b
Packit ae235b
  attr_iter = g_menu_model_iterate_item_attributes (model, index);
Packit ae235b
  while (g_menu_attribute_iter_get_next (attr_iter, &name, &value))
Packit ae235b
    {
Packit ae235b
      GVariant *item_value;
Packit ae235b
Packit ae235b
      item_value = g_menu_item_get_attribute_value (item, name, g_variant_get_type (value));
Packit ae235b
      g_assert (item_value && g_variant_equal (item_value, value));
Packit ae235b
Packit ae235b
      g_variant_unref (item_value);
Packit ae235b
      g_variant_unref (value);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  link_iter = g_menu_model_iterate_item_links (model, index);
Packit ae235b
  while (g_menu_link_iter_get_next (link_iter, &name, &linked_model))
Packit ae235b
    {
Packit ae235b
      GMenuModel *item_linked_model;
Packit ae235b
Packit ae235b
      item_linked_model = g_menu_item_get_link (item, name);
Packit ae235b
      g_assert (linked_model == item_linked_model);
Packit ae235b
Packit ae235b
      g_object_unref (item_linked_model);
Packit ae235b
      g_object_unref (linked_model);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  g_object_unref (attr_iter);
Packit ae235b
  g_object_unref (link_iter);
Packit ae235b
}
Packit ae235b
Packit ae235b
/* Test cases {{{1 */
Packit ae235b
static void
Packit ae235b
test_equality (void)
Packit ae235b
{
Packit ae235b
  GRand *randa, *randb;
Packit ae235b
  guint32 seed;
Packit ae235b
  gint i;
Packit ae235b
Packit ae235b
  seed = g_test_rand_int ();
Packit ae235b
Packit ae235b
  randa = g_rand_new_with_seed (seed);
Packit ae235b
  randb = g_rand_new_with_seed (seed);
Packit ae235b
Packit ae235b
  for (i = 0; i < 500; i++)
Packit ae235b
    {
Packit ae235b
      RandomMenu *a, *b;
Packit ae235b
Packit ae235b
      a = random_menu_new (randa, TOP_ORDER);
Packit ae235b
      b = random_menu_new (randb, TOP_ORDER);
Packit ae235b
      assert_menus_equal (G_MENU_MODEL (a), G_MENU_MODEL (b));
Packit ae235b
      g_object_unref (b);
Packit ae235b
      g_object_unref (a);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  g_rand_int (randa);
Packit ae235b
Packit ae235b
  for (i = 0; i < 500;)
Packit ae235b
    {
Packit ae235b
      RandomMenu *a, *b;
Packit ae235b
Packit ae235b
      a = random_menu_new (randa, TOP_ORDER);
Packit ae235b
      b = random_menu_new (randb, TOP_ORDER);
Packit ae235b
      if (check_menus_equal (G_MENU_MODEL (a), G_MENU_MODEL (b)))
Packit ae235b
        {
Packit ae235b
          /* by chance, they may really be equal.  double check. */
Packit ae235b
          GString *as, *bs;
Packit ae235b
Packit ae235b
          as = g_menu_markup_print_string (NULL, G_MENU_MODEL (a), 4, 2);
Packit ae235b
          bs = g_menu_markup_print_string (NULL, G_MENU_MODEL (b), 4, 2);
Packit ae235b
          g_assert_cmpstr (as->str, ==, bs->str);
Packit ae235b
          g_string_free (bs, TRUE);
Packit ae235b
          g_string_free (as, TRUE);
Packit ae235b
Packit ae235b
          /* we're here because randa and randb just generated equal
Packit ae235b
           * menus.  they may do it again, so throw away randb and make
Packit ae235b
           * a fresh one.
Packit ae235b
           */
Packit ae235b
          g_rand_free (randb);
Packit ae235b
          randb = g_rand_new_with_seed (g_rand_int (randa));
Packit ae235b
        }
Packit ae235b
      else
Packit ae235b
        /* make sure we get enough unequals (ie: no GRand failure) */
Packit ae235b
        i++;
Packit ae235b
Packit ae235b
      g_object_unref (b);
Packit ae235b
      g_object_unref (a);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  g_rand_free (randb);
Packit ae235b
  g_rand_free (randa);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
test_random (void)
Packit ae235b
{
Packit ae235b
  RandomMenu *random;
Packit ae235b
  MirrorMenu *mirror;
Packit ae235b
  GRand *rand;
Packit ae235b
  gint i;
Packit ae235b
Packit ae235b
  rand = g_rand_new_with_seed (g_test_rand_int ());
Packit ae235b
  random = random_menu_new (rand, TOP_ORDER);
Packit ae235b
  mirror = mirror_menu_new (G_MENU_MODEL (random));
Packit ae235b
Packit ae235b
  for (i = 0; i < 500; i++)
Packit ae235b
    {
Packit ae235b
      assert_menus_equal (G_MENU_MODEL (random), G_MENU_MODEL (mirror));
Packit ae235b
      random_menu_change (random, rand);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  g_object_unref (mirror);
Packit ae235b
  g_object_unref (random);
Packit ae235b
Packit ae235b
  g_rand_free (rand);
Packit ae235b
}
Packit ae235b
Packit ae235b
typedef struct
Packit ae235b
{
Packit ae235b
  GDBusConnection *client_connection;
Packit ae235b
  GDBusConnection *server_connection;
Packit ae235b
  GDBusServer *server;
Packit ae235b
Packit ae235b
  GThread *service_thread;
Packit ae235b
  GMutex service_loop_lock;
Packit ae235b
  GCond service_loop_cond;
Packit ae235b
Packit ae235b
  GMainLoop *service_loop;
Packit ae235b
  GMainLoop *loop;
Packit ae235b
} PeerConnection;
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
on_new_connection (GDBusServer *server,
Packit ae235b
                   GDBusConnection *connection,
Packit ae235b
                   gpointer user_data)
Packit ae235b
{
Packit ae235b
  PeerConnection *data = user_data;
Packit ae235b
Packit ae235b
  data->server_connection = g_object_ref (connection);
Packit ae235b
Packit ae235b
  g_main_loop_quit (data->loop);
Packit ae235b
Packit ae235b
  return TRUE;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
create_service_loop (GMainContext   *service_context,
Packit ae235b
                     PeerConnection *data)
Packit ae235b
{
Packit ae235b
  g_assert (data->service_loop == NULL);
Packit ae235b
  g_mutex_lock (&data->service_loop_lock);
Packit ae235b
  data->service_loop = g_main_loop_new (service_context, FALSE);
Packit ae235b
  g_cond_broadcast (&data->service_loop_cond);
Packit ae235b
  g_mutex_unlock (&data->service_loop_lock);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
teardown_service_loop (PeerConnection *data)
Packit ae235b
{
Packit ae235b
  g_mutex_lock (&data->service_loop_lock);
Packit ae235b
  g_clear_pointer (&data->service_loop, g_main_loop_unref);
Packit ae235b
  g_mutex_unlock (&data->service_loop_lock);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
await_service_loop (PeerConnection *data)
Packit ae235b
{
Packit ae235b
  g_mutex_lock (&data->service_loop_lock);
Packit ae235b
  while (data->service_loop == NULL)
Packit ae235b
    g_cond_wait (&data->service_loop_cond, &data->service_loop_lock);
Packit ae235b
  g_mutex_unlock (&data->service_loop_lock);
Packit ae235b
}
Packit ae235b
Packit ae235b
static gpointer
Packit ae235b
service_thread_func (gpointer user_data)
Packit ae235b
{
Packit ae235b
  PeerConnection *data = user_data;
Packit ae235b
  GMainContext *service_context;
Packit ae235b
  GError *error;
Packit ae235b
  gchar *address;
Packit ae235b
  gchar *tmpdir;
Packit ae235b
  GDBusServerFlags flags;
Packit ae235b
  gchar *guid;
Packit ae235b
Packit ae235b
  service_context = g_main_context_new ();
Packit ae235b
  g_main_context_push_thread_default (service_context);
Packit ae235b
Packit ae235b
  tmpdir = NULL;
Packit ae235b
  flags = G_DBUS_SERVER_FLAGS_NONE;
Packit ae235b
Packit ae235b
#ifdef G_OS_UNIX
Packit ae235b
  if (g_unix_socket_address_abstract_names_supported ())
Packit ae235b
    address = g_strdup ("unix:tmpdir=/tmp/test-dbus-peer");
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      tmpdir = g_dir_make_tmp ("test-dbus-peer-XXXXXX", NULL);
Packit ae235b
      address = g_strdup_printf ("unix:tmpdir=%s", tmpdir);
Packit ae235b
    }
Packit ae235b
#else
Packit ae235b
  address = g_strdup ("nonce-tcp:");
Packit ae235b
  flags |= G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS;
Packit ae235b
#endif
Packit ae235b
Packit ae235b
  guid = g_dbus_generate_guid ();
Packit ae235b
Packit ae235b
  error = NULL;
Packit ae235b
  data->server = g_dbus_server_new_sync (address,
Packit ae235b
                                         flags,
Packit ae235b
                                         guid,
Packit ae235b
                                         NULL,
Packit ae235b
                                         NULL,
Packit ae235b
                                         &error);
Packit ae235b
  g_assert_no_error (error);
Packit ae235b
  g_free (address);
Packit ae235b
  g_free (guid);
Packit ae235b
Packit ae235b
  g_signal_connect (data->server,
Packit ae235b
                    "new-connection",
Packit ae235b
                    G_CALLBACK (on_new_connection),
Packit ae235b
                    data);
Packit ae235b
Packit ae235b
  g_dbus_server_start (data->server);
Packit ae235b
Packit ae235b
  create_service_loop (service_context, data);
Packit ae235b
  g_main_loop_run (data->service_loop);
Packit ae235b
Packit ae235b
  g_main_context_pop_thread_default (service_context);
Packit ae235b
Packit ae235b
  teardown_service_loop (data);
Packit ae235b
  g_main_context_unref (service_context);
Packit ae235b
Packit ae235b
  if (tmpdir)
Packit ae235b
    {
Packit ae235b
      g_rmdir (tmpdir);
Packit ae235b
      g_free (tmpdir);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  return NULL;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
peer_connection_up (PeerConnection *data)
Packit ae235b
{
Packit ae235b
  GError *error;
Packit ae235b
Packit ae235b
  memset (data, '\0', sizeof (PeerConnection));
Packit ae235b
  data->loop = g_main_loop_new (NULL, FALSE);
Packit ae235b
Packit ae235b
  g_mutex_init (&data->service_loop_lock);
Packit ae235b
  g_cond_init (&data->service_loop_cond);
Packit ae235b
Packit ae235b
  /* bring up a server - we run the server in a different thread to
Packit ae235b
     avoid deadlocks */
Packit ae235b
  data->service_thread = g_thread_new ("test_dbus_peer",
Packit ae235b
                                       service_thread_func,
Packit ae235b
                                       data);
Packit ae235b
  await_service_loop (data);
Packit ae235b
  g_assert (data->server != NULL);
Packit ae235b
Packit ae235b
  /* bring up a connection and accept it */
Packit ae235b
  error = NULL;
Packit ae235b
  data->client_connection =
Packit ae235b
    g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (data->server),
Packit ae235b
                                            G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
Packit ae235b
                                            NULL, /* GDBusAuthObserver */
Packit ae235b
                                            NULL, /* cancellable */
Packit ae235b
                                            &error);
Packit ae235b
  g_assert_no_error (error);
Packit ae235b
  g_assert (data->client_connection != NULL);
Packit ae235b
  while (data->server_connection == NULL)
Packit ae235b
    g_main_loop_run (data->loop);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
peer_connection_down (PeerConnection *data)
Packit ae235b
{
Packit ae235b
  g_object_unref (data->client_connection);
Packit ae235b
  g_object_unref (data->server_connection);
Packit ae235b
Packit ae235b
  g_dbus_server_stop (data->server);
Packit ae235b
  g_object_unref (data->server);
Packit ae235b
Packit ae235b
  g_main_loop_quit (data->service_loop);
Packit ae235b
  g_thread_join (data->service_thread);
Packit ae235b
Packit ae235b
  g_mutex_clear (&data->service_loop_lock);
Packit ae235b
  g_cond_clear (&data->service_loop_cond);
Packit ae235b
Packit ae235b
  g_main_loop_unref (data->loop);
Packit ae235b
}
Packit ae235b
Packit ae235b
struct roundtrip_state
Packit ae235b
{
Packit ae235b
  RandomMenu *random;
Packit ae235b
  MirrorMenu *proxy_mirror;
Packit ae235b
  GDBusMenuModel *proxy;
Packit ae235b
  GMainLoop *loop;
Packit ae235b
  GRand *rand;
Packit ae235b
  gint success;
Packit ae235b
  gint count;
Packit ae235b
};
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
roundtrip_step (gpointer data)
Packit ae235b
{
Packit ae235b
  struct roundtrip_state *state = data;
Packit ae235b
Packit ae235b
  if (check_menus_equal (G_MENU_MODEL (state->random), G_MENU_MODEL (state->proxy)) &&
Packit ae235b
      check_menus_equal (G_MENU_MODEL (state->random), G_MENU_MODEL (state->proxy_mirror)))
Packit ae235b
    {
Packit ae235b
      state->success++;
Packit ae235b
      state->count = 0;
Packit ae235b
Packit ae235b
      if (state->success < 100)
Packit ae235b
        random_menu_change (state->random, state->rand);
Packit ae235b
      else
Packit ae235b
        g_main_loop_quit (state->loop);
Packit ae235b
    }
Packit ae235b
  else if (state->count == 100)
Packit ae235b
    {
Packit ae235b
      assert_menus_equal (G_MENU_MODEL (state->random), G_MENU_MODEL (state->proxy));
Packit ae235b
      g_assert_not_reached ();
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    state->count++;
Packit ae235b
Packit ae235b
  return G_SOURCE_CONTINUE;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
do_roundtrip (GDBusConnection *exporter_connection,
Packit ae235b
              GDBusConnection *proxy_connection)
Packit ae235b
{
Packit ae235b
  struct roundtrip_state state;
Packit ae235b
  guint export_id;
Packit ae235b
  guint id;
Packit ae235b
Packit ae235b
  state.rand = g_rand_new_with_seed (g_test_rand_int ());
Packit ae235b
Packit ae235b
  state.random = random_menu_new (state.rand, 2);
Packit ae235b
  export_id = g_dbus_connection_export_menu_model (exporter_connection,
Packit ae235b
                                                   "/",
Packit ae235b
                                                   G_MENU_MODEL (state.random),
Packit ae235b
                                                   NULL);
Packit ae235b
  state.proxy = g_dbus_menu_model_get (proxy_connection,
Packit ae235b
                                       g_dbus_connection_get_unique_name (proxy_connection),
Packit ae235b
                                       "/");
Packit ae235b
  state.proxy_mirror = mirror_menu_new (G_MENU_MODEL (state.proxy));
Packit ae235b
  state.count = 0;
Packit ae235b
  state.success = 0;
Packit ae235b
Packit ae235b
  id = g_timeout_add (10, roundtrip_step, &state);
Packit ae235b
Packit ae235b
  state.loop = g_main_loop_new (NULL, FALSE);
Packit ae235b
  g_main_loop_run (state.loop);
Packit ae235b
Packit ae235b
  g_main_loop_unref (state.loop);
Packit ae235b
  g_source_remove (id);
Packit ae235b
  g_object_unref (state.proxy);
Packit ae235b
  g_dbus_connection_unexport_menu_model (exporter_connection, export_id);
Packit ae235b
  g_object_unref (state.random);
Packit ae235b
  g_object_unref (state.proxy_mirror);
Packit ae235b
  g_rand_free (state.rand);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
test_dbus_roundtrip (void)
Packit ae235b
{
Packit ae235b
  GDBusConnection *bus;
Packit ae235b
Packit ae235b
  bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
Packit ae235b
  do_roundtrip (bus, bus);
Packit ae235b
  g_object_unref (bus);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
test_dbus_peer_roundtrip (void)
Packit ae235b
{
Packit ae235b
  PeerConnection peer;
Packit ae235b
Packit ae235b
  peer_connection_up (&peer);
Packit ae235b
  do_roundtrip (peer.server_connection, peer.client_connection);
Packit ae235b
  peer_connection_down (&peer);
Packit ae235b
}
Packit ae235b
Packit ae235b
static gint items_changed_count;
Packit ae235b
Packit ae235b
static void
Packit ae235b
items_changed (GMenuModel *model,
Packit ae235b
               gint        position,
Packit ae235b
               gint        removed,
Packit ae235b
               gint        added,
Packit ae235b
               gpointer    data)
Packit ae235b
{
Packit ae235b
  items_changed_count++;
Packit ae235b
}
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
stop_loop (gpointer data)
Packit ae235b
{
Packit ae235b
  GMainLoop *loop = data;
Packit ae235b
Packit ae235b
  g_main_loop_quit (loop);
Packit ae235b
Packit ae235b
  return G_SOURCE_REMOVE;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
do_subscriptions (GDBusConnection *exporter_connection,
Packit ae235b
                  GDBusConnection *proxy_connection)
Packit ae235b
{
Packit ae235b
  GMenu *menu;
Packit ae235b
  GDBusMenuModel *proxy;
Packit ae235b
  GMainLoop *loop;
Packit ae235b
  GError *error = NULL;
Packit ae235b
  guint export_id;
Packit ae235b
  guint timeout_id;
Packit ae235b
Packit ae235b
  timeout_id = add_timeout (60);
Packit ae235b
  loop = g_main_loop_new (NULL, FALSE);
Packit ae235b
Packit ae235b
  menu = g_menu_new ();
Packit ae235b
Packit ae235b
  export_id = g_dbus_connection_export_menu_model (exporter_connection,
Packit ae235b
                                                   "/",
Packit ae235b
                                                   G_MENU_MODEL (menu),
Packit ae235b
                                                   &error);
Packit ae235b
  g_assert_no_error (error);
Packit ae235b
Packit ae235b
  proxy = g_dbus_menu_model_get (proxy_connection,
Packit ae235b
                                 g_dbus_connection_get_unique_name (proxy_connection),
Packit ae235b
                                 "/");
Packit ae235b
  items_changed_count = 0;
Packit ae235b
  g_signal_connect (proxy, "items-changed",
Packit ae235b
                    G_CALLBACK (items_changed), NULL);
Packit ae235b
Packit ae235b
  g_menu_append (menu, "item1", NULL);
Packit ae235b
  g_menu_append (menu, "item2", NULL);
Packit ae235b
  g_menu_append (menu, "item3", NULL);
Packit ae235b
Packit ae235b
  g_assert_cmpint (items_changed_count, ==, 0);
Packit ae235b
Packit ae235b
  /* We don't subscribe to change-notification until we look at the items */
Packit ae235b
  g_timeout_add (100, stop_loop, loop);
Packit ae235b
  g_main_loop_run (loop);
Packit ae235b
Packit ae235b
  /* Looking at the items triggers subscription */
Packit ae235b
  g_menu_model_get_n_items (G_MENU_MODEL (proxy));
Packit ae235b
Packit ae235b
  while (items_changed_count < 1)
Packit ae235b
    g_main_context_iteration (NULL, TRUE);
Packit ae235b
Packit ae235b
  /* We get all three items in one batch */
Packit ae235b
  g_assert_cmpint (items_changed_count, ==, 1);
Packit ae235b
  g_assert_cmpint (g_menu_model_get_n_items (G_MENU_MODEL (proxy)), ==, 3);
Packit ae235b
Packit ae235b
  /* If we wait, we don't get any more */
Packit ae235b
  g_timeout_add (100, stop_loop, loop);
Packit ae235b
  g_main_loop_run (loop);
Packit ae235b
  g_assert_cmpint (items_changed_count, ==, 1);
Packit ae235b
  g_assert_cmpint (g_menu_model_get_n_items (G_MENU_MODEL (proxy)), ==, 3);
Packit ae235b
Packit ae235b
  /* Now we're subscribed, we get changes individually */
Packit ae235b
  g_menu_append (menu, "item4", NULL);
Packit ae235b
  g_menu_append (menu, "item5", NULL);
Packit ae235b
  g_menu_append (menu, "item6", NULL);
Packit ae235b
  g_menu_remove (menu, 0);
Packit ae235b
  g_menu_remove (menu, 0);
Packit ae235b
Packit ae235b
  while (items_changed_count < 6)
Packit ae235b
    g_main_context_iteration (NULL, TRUE);
Packit ae235b
Packit ae235b
  g_assert_cmpint (items_changed_count, ==, 6);
Packit ae235b
Packit ae235b
  g_assert_cmpint (g_menu_model_get_n_items (G_MENU_MODEL (proxy)), ==, 4);
Packit ae235b
Packit ae235b
  /* After destroying the proxy and waiting a bit, we don't get any more
Packit ae235b
   * items-changed signals */
Packit ae235b
  g_object_unref (proxy);
Packit ae235b
Packit ae235b
  g_timeout_add (100, stop_loop, loop);
Packit ae235b
  g_main_loop_run (loop);
Packit ae235b
Packit ae235b
  g_menu_remove (menu, 0);
Packit ae235b
  g_menu_remove (menu, 0);
Packit ae235b
Packit ae235b
  g_timeout_add (100, stop_loop, loop);
Packit ae235b
  g_main_loop_run (loop);
Packit ae235b
Packit ae235b
  g_assert_cmpint (items_changed_count, ==, 6);
Packit ae235b
Packit ae235b
  g_dbus_connection_unexport_menu_model (exporter_connection, export_id);
Packit ae235b
  g_object_unref (menu);
Packit ae235b
Packit ae235b
  g_main_loop_unref (loop);
Packit ae235b
  cancel_timeout (timeout_id);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
test_dbus_subscriptions (void)
Packit ae235b
{
Packit ae235b
  GDBusConnection *bus;
Packit ae235b
Packit ae235b
  bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
Packit ae235b
  do_subscriptions (bus, bus);
Packit ae235b
  g_object_unref (bus);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
test_dbus_peer_subscriptions (void)
Packit ae235b
{
Packit ae235b
  PeerConnection peer;
Packit ae235b
Packit ae235b
  peer_connection_up (&peer);
Packit ae235b
  do_subscriptions (peer.server_connection, peer.client_connection);
Packit ae235b
  peer_connection_down (&peer);
Packit ae235b
}
Packit ae235b
Packit ae235b
static gpointer
Packit ae235b
do_modify (gpointer data)
Packit ae235b
{
Packit ae235b
  RandomMenu *menu = data;
Packit ae235b
  GRand *rand;
Packit ae235b
  gint i;
Packit ae235b
Packit ae235b
  rand = g_rand_new_with_seed (g_test_rand_int ());
Packit ae235b
Packit ae235b
  for (i = 0; i < 10000; i++)
Packit ae235b
    {
Packit ae235b
      random_menu_change (menu, rand);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  return NULL;
Packit ae235b
}
Packit ae235b
Packit ae235b
static gpointer
Packit ae235b
do_export (gpointer data)
Packit ae235b
{
Packit ae235b
  GMenuModel *menu = data;
Packit ae235b
  gint i;
Packit ae235b
  GDBusConnection *bus;
Packit ae235b
  gchar *path;
Packit ae235b
  GError *error = NULL;
Packit ae235b
  guint id;
Packit ae235b
Packit ae235b
  bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
Packit ae235b
  path = g_strdup_printf ("/%p", data);
Packit ae235b
Packit ae235b
  for (i = 0; i < 10000; i++)
Packit ae235b
    {
Packit ae235b
      id = g_dbus_connection_export_menu_model (bus, path, menu, &error);
Packit ae235b
      g_assert_no_error (error);
Packit ae235b
      g_dbus_connection_unexport_menu_model (bus, id);
Packit ae235b
      while (g_main_context_iteration (NULL, FALSE));
Packit ae235b
    }
Packit ae235b
Packit ae235b
  g_free (path);
Packit ae235b
Packit ae235b
  g_object_unref (bus);
Packit ae235b
Packit ae235b
  return NULL;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
test_dbus_threaded (void)
Packit ae235b
{
Packit ae235b
  RandomMenu *menu[10];
Packit ae235b
  GThread *call[10];
Packit ae235b
  GThread *export[10];
Packit ae235b
  gint i;
Packit ae235b
Packit ae235b
  for (i = 0; i < 10; i++)
Packit ae235b
    {
Packit ae235b
      menu[i] = random_menu_new (g_rand_new_with_seed (g_test_rand_int ()), 2);
Packit ae235b
      call[i] = g_thread_new ("call", do_modify, menu[i]);
Packit ae235b
      export[i] = g_thread_new ("export", do_export, menu[i]);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  for (i = 0; i < 10; i++)
Packit ae235b
    {
Packit ae235b
      g_thread_join (call[i]);
Packit ae235b
      g_thread_join (export[i]);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  for (i = 0; i < 10; i++)
Packit ae235b
    g_object_unref (menu[i]);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
test_attributes (void)
Packit ae235b
{
Packit ae235b
  GMenu *menu;
Packit ae235b
  GMenuItem *item;
Packit ae235b
  GVariant *v;
Packit ae235b
Packit ae235b
  menu = g_menu_new ();
Packit ae235b
Packit ae235b
  item = g_menu_item_new ("test", NULL);
Packit ae235b
  g_menu_item_set_attribute_value (item, "boolean", g_variant_new_boolean (FALSE));
Packit ae235b
  g_menu_item_set_attribute_value (item, "string", g_variant_new_string ("bla"));
Packit ae235b
Packit ae235b
  g_menu_item_set_attribute (item, "double", "d", 1.5);
Packit ae235b
  v = g_variant_new_parsed ("[('one', 1), ('two', %i), (%s, 3)]", 2, "three");
Packit ae235b
  g_menu_item_set_attribute_value (item, "complex", v);
Packit ae235b
  g_menu_item_set_attribute_value (item, "test-123", g_variant_new_string ("test-123"));
Packit ae235b
Packit ae235b
  g_menu_append_item (menu, item);
Packit ae235b
Packit ae235b
  g_menu_item_set_attribute (item, "double", "d", G_PI);
Packit ae235b
Packit ae235b
  g_assert_cmpint (g_menu_model_get_n_items (G_MENU_MODEL (menu)), ==, 1);
Packit ae235b
Packit ae235b
  v = g_menu_model_get_item_attribute_value (G_MENU_MODEL (menu), 0, "boolean", NULL);
Packit ae235b
  g_assert (g_variant_is_of_type (v, G_VARIANT_TYPE_BOOLEAN));
Packit ae235b
  g_variant_unref (v);
Packit ae235b
Packit ae235b
  v = g_menu_model_get_item_attribute_value (G_MENU_MODEL (menu), 0, "string", NULL);
Packit ae235b
  g_assert (g_variant_is_of_type (v, G_VARIANT_TYPE_STRING));
Packit ae235b
  g_variant_unref (v);
Packit ae235b
Packit ae235b
  v = g_menu_model_get_item_attribute_value (G_MENU_MODEL (menu), 0, "double", NULL);
Packit ae235b
  g_assert (g_variant_is_of_type (v, G_VARIANT_TYPE_DOUBLE));
Packit ae235b
  g_variant_unref (v);
Packit ae235b
Packit ae235b
  v = g_menu_model_get_item_attribute_value (G_MENU_MODEL (menu), 0, "complex", NULL);
Packit ae235b
  g_assert (g_variant_is_of_type (v, G_VARIANT_TYPE("a(si)")));
Packit ae235b
  g_variant_unref (v);
Packit ae235b
Packit ae235b
  g_menu_remove_all (menu);
Packit ae235b
Packit ae235b
  g_object_unref (menu);
Packit ae235b
  g_object_unref (item);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
test_attribute_iter (void)
Packit ae235b
{
Packit ae235b
  GMenu *menu;
Packit ae235b
  GMenuItem *item;
Packit ae235b
  const gchar *name;
Packit ae235b
  GVariant *v;
Packit ae235b
  GMenuAttributeIter *iter;
Packit ae235b
  GHashTable *found;
Packit ae235b
Packit ae235b
  menu = g_menu_new ();
Packit ae235b
Packit ae235b
  item = g_menu_item_new ("test", NULL);
Packit ae235b
  g_menu_item_set_attribute_value (item, "boolean", g_variant_new_boolean (FALSE));
Packit ae235b
  g_menu_item_set_attribute_value (item, "string", g_variant_new_string ("bla"));
Packit ae235b
Packit ae235b
  g_menu_item_set_attribute (item, "double", "d", 1.5);
Packit ae235b
  v = g_variant_new_parsed ("[('one', 1), ('two', %i), (%s, 3)]", 2, "three");
Packit ae235b
  g_menu_item_set_attribute_value (item, "complex", v);
Packit ae235b
  g_menu_item_set_attribute_value (item, "test-123", g_variant_new_string ("test-123"));
Packit ae235b
Packit ae235b
  g_menu_append_item (menu, item);
Packit ae235b
Packit ae235b
  g_menu_item_set_attribute (item, "double", "d", G_PI);
Packit ae235b
Packit ae235b
  g_assert_cmpint (g_menu_model_get_n_items (G_MENU_MODEL (menu)), ==, 1);
Packit ae235b
Packit ae235b
  found = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_variant_unref); 
Packit ae235b
Packit ae235b
  iter = g_menu_model_iterate_item_attributes (G_MENU_MODEL (menu), 0);
Packit ae235b
  while (g_menu_attribute_iter_get_next (iter, &name, &v))
Packit ae235b
    g_hash_table_insert (found, g_strdup (name), v);
Packit ae235b
Packit ae235b
  g_assert_cmpint (g_hash_table_size (found), ==, 6);
Packit ae235b
  
Packit ae235b
  v = g_hash_table_lookup (found, "label");
Packit ae235b
  g_assert (g_variant_is_of_type (v, G_VARIANT_TYPE_STRING));
Packit ae235b
Packit ae235b
  v = g_hash_table_lookup (found, "boolean");
Packit ae235b
  g_assert (g_variant_is_of_type (v, G_VARIANT_TYPE_BOOLEAN));
Packit ae235b
 
Packit ae235b
  v = g_hash_table_lookup (found, "string");
Packit ae235b
  g_assert (g_variant_is_of_type (v, G_VARIANT_TYPE_STRING));
Packit ae235b
Packit ae235b
  v = g_hash_table_lookup (found, "double");
Packit ae235b
  g_assert (g_variant_is_of_type (v, G_VARIANT_TYPE_DOUBLE));
Packit ae235b
Packit ae235b
  v = g_hash_table_lookup (found, "complex");
Packit ae235b
  g_assert (g_variant_is_of_type (v, G_VARIANT_TYPE("a(si)")));
Packit ae235b
Packit ae235b
  v = g_hash_table_lookup (found, "test-123");
Packit ae235b
  g_assert (g_variant_is_of_type (v, G_VARIANT_TYPE_STRING));
Packit ae235b
Packit ae235b
  g_hash_table_unref (found);
Packit ae235b
Packit ae235b
  g_menu_remove_all (menu);
Packit ae235b
Packit ae235b
  g_object_unref (menu);
Packit ae235b
  g_object_unref (item);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
test_links (void)
Packit ae235b
{
Packit ae235b
  GMenu *menu;
Packit ae235b
  GMenuModel *m;
Packit ae235b
  GMenuModel *x;
Packit ae235b
  GMenuItem *item;
Packit ae235b
Packit ae235b
  m = G_MENU_MODEL (g_menu_new ());
Packit ae235b
  g_menu_append (G_MENU (m), "test", NULL);
Packit ae235b
Packit ae235b
  menu = g_menu_new ();
Packit ae235b
Packit ae235b
  item = g_menu_item_new ("test2", NULL);
Packit ae235b
  g_menu_item_set_link (item, "submenu", m);
Packit ae235b
  g_menu_prepend_item (menu, item);
Packit ae235b
Packit ae235b
  item = g_menu_item_new ("test1", NULL);
Packit ae235b
  g_menu_item_set_link (item, "section", m);
Packit ae235b
  g_menu_insert_item (menu, 0, item);
Packit ae235b
Packit ae235b
  item = g_menu_item_new ("test3", NULL);
Packit ae235b
  g_menu_item_set_link (item, "wallet", m);
Packit ae235b
  g_menu_insert_item (menu, 1000, item);
Packit ae235b
Packit ae235b
  item = g_menu_item_new ("test4", NULL);
Packit ae235b
  g_menu_item_set_link (item, "purse", m);
Packit ae235b
  g_menu_item_set_link (item, "purse", NULL);
Packit ae235b
  g_menu_append_item (menu, item);
Packit ae235b
Packit ae235b
  g_assert_cmpint (g_menu_model_get_n_items (G_MENU_MODEL (menu)), ==, 4);
Packit ae235b
Packit ae235b
  x = g_menu_model_get_item_link (G_MENU_MODEL (menu), 0, "section");
Packit ae235b
  g_assert (x == m);
Packit ae235b
  g_object_unref (x);
Packit ae235b
Packit ae235b
  x = g_menu_model_get_item_link (G_MENU_MODEL (menu), 1, "submenu");
Packit ae235b
  g_assert (x == m);
Packit ae235b
  g_object_unref (x);
Packit ae235b
Packit ae235b
  x = g_menu_model_get_item_link (G_MENU_MODEL (menu), 2, "wallet");
Packit ae235b
  g_assert (x == m);
Packit ae235b
  g_object_unref (x);
Packit ae235b
Packit ae235b
  x = g_menu_model_get_item_link (G_MENU_MODEL (menu), 3, "purse");
Packit ae235b
  g_assert (x == NULL);
Packit ae235b
Packit ae235b
  g_object_unref (m);
Packit ae235b
  g_object_unref (menu);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
test_mutable (void)
Packit ae235b
{
Packit ae235b
  GMenu *menu;
Packit ae235b
Packit ae235b
  menu = g_menu_new ();
Packit ae235b
  g_menu_append (menu, "test", "test");
Packit ae235b
Packit ae235b
  g_assert (g_menu_model_is_mutable (G_MENU_MODEL (menu)));
Packit ae235b
  g_menu_freeze (menu);
Packit ae235b
  g_assert (!g_menu_model_is_mutable (G_MENU_MODEL (menu)));
Packit ae235b
Packit ae235b
  g_object_unref (menu);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
test_convenience (void)
Packit ae235b
{
Packit ae235b
  GMenu *m1, *m2;
Packit ae235b
  GMenu *sub;
Packit ae235b
  GMenuItem *item;
Packit ae235b
Packit ae235b
  m1 = g_menu_new ();
Packit ae235b
  m2 = g_menu_new ();
Packit ae235b
  sub = g_menu_new ();
Packit ae235b
Packit ae235b
  g_menu_prepend (m1, "label1", "do::something");
Packit ae235b
  g_menu_insert (m2, 0, "label1", "do::something");
Packit ae235b
Packit ae235b
  g_menu_append (m1, "label2", "do::somethingelse");
Packit ae235b
  g_menu_insert (m2, -1, "label2", "do::somethingelse");
Packit ae235b
Packit ae235b
  g_menu_insert_section (m1, 10, "label3", G_MENU_MODEL (sub));
Packit ae235b
  item = g_menu_item_new_section ("label3", G_MENU_MODEL (sub));
Packit ae235b
  g_menu_insert_item (m2, 10, item);
Packit ae235b
  g_object_unref (item);
Packit ae235b
Packit ae235b
  g_menu_prepend_section (m1, "label4", G_MENU_MODEL (sub));
Packit ae235b
  g_menu_insert_section (m2, 0, "label4", G_MENU_MODEL (sub));
Packit ae235b
Packit ae235b
  g_menu_append_section (m1, "label5", G_MENU_MODEL (sub));
Packit ae235b
  g_menu_insert_section (m2, -1, "label5", G_MENU_MODEL (sub));
Packit ae235b
Packit ae235b
  g_menu_insert_submenu (m1, 5, "label6", G_MENU_MODEL (sub));
Packit ae235b
  item = g_menu_item_new_submenu ("label6", G_MENU_MODEL (sub));
Packit ae235b
  g_menu_insert_item (m2, 5, item);
Packit ae235b
  g_object_unref (item);
Packit ae235b
Packit ae235b
  g_menu_prepend_submenu (m1, "label7", G_MENU_MODEL (sub));
Packit ae235b
  g_menu_insert_submenu (m2, 0, "label7", G_MENU_MODEL (sub));
Packit ae235b
Packit ae235b
  g_menu_append_submenu (m1, "label8", G_MENU_MODEL (sub));
Packit ae235b
  g_menu_insert_submenu (m2, -1, "label8", G_MENU_MODEL (sub));
Packit ae235b
Packit ae235b
  assert_menus_equal (G_MENU_MODEL (m1), G_MENU_MODEL (m2));
Packit ae235b
Packit ae235b
  g_object_unref (m1);
Packit ae235b
  g_object_unref (m2);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
test_menuitem (void)
Packit ae235b
{
Packit ae235b
  GMenu *menu;
Packit ae235b
  GMenu *submenu;
Packit ae235b
  GMenuItem *item;
Packit ae235b
  GIcon *icon;
Packit ae235b
  gboolean b;
Packit ae235b
  gchar *s;
Packit ae235b
Packit ae235b
  menu = g_menu_new ();
Packit ae235b
  submenu = g_menu_new ();
Packit ae235b
Packit ae235b
  item = g_menu_item_new ("label", "action");
Packit ae235b
  g_menu_item_set_attribute (item, "attribute", "b", TRUE);
Packit ae235b
  g_menu_item_set_link (item, G_MENU_LINK_SUBMENU, G_MENU_MODEL (submenu));
Packit ae235b
  g_menu_append_item (menu, item);
Packit ae235b
Packit ae235b
  icon = g_themed_icon_new ("bla");
Packit ae235b
  g_menu_item_set_icon (item, icon);
Packit ae235b
  g_object_unref (icon);
Packit ae235b
Packit ae235b
  g_assert (g_menu_item_get_attribute (item, "attribute", "b", &b);;
Packit ae235b
  g_assert (b);
Packit ae235b
Packit ae235b
  g_menu_item_set_action_and_target (item, "action", "(bs)", TRUE, "string");
Packit ae235b
  g_assert (g_menu_item_get_attribute (item, "target", "(bs)", &b, &s);;
Packit ae235b
  g_assert (b);
Packit ae235b
  g_assert_cmpstr (s, ==, "string");
Packit ae235b
  g_free (s);
Packit ae235b
Packit ae235b
  g_object_unref (item);
Packit ae235b
Packit ae235b
  item = g_menu_item_new_from_model (G_MENU_MODEL (menu), 0);
Packit ae235b
  assert_menuitem_equal (item, G_MENU_MODEL (menu), 0);
Packit ae235b
  g_object_unref (item);
Packit ae235b
Packit ae235b
  g_object_unref (menu);
Packit ae235b
  g_object_unref (submenu);
Packit ae235b
}
Packit ae235b
Packit ae235b
/* Epilogue {{{1 */
Packit ae235b
int
Packit ae235b
main (int argc, char **argv)
Packit ae235b
{
Packit ae235b
  gboolean ret;
Packit ae235b
Packit ae235b
  g_test_init (&argc, &argv, NULL);
Packit ae235b
Packit ae235b
  session_bus_up ();
Packit ae235b
Packit ae235b
  g_test_add_func ("/gmenu/equality", test_equality);
Packit ae235b
  g_test_add_func ("/gmenu/random", test_random);
Packit ae235b
  g_test_add_func ("/gmenu/dbus/roundtrip", test_dbus_roundtrip);
Packit ae235b
  g_test_add_func ("/gmenu/dbus/subscriptions", test_dbus_subscriptions);
Packit ae235b
  g_test_add_func ("/gmenu/dbus/threaded", test_dbus_threaded);
Packit ae235b
  g_test_add_func ("/gmenu/dbus/peer/roundtrip", test_dbus_peer_roundtrip);
Packit ae235b
  g_test_add_func ("/gmenu/dbus/peer/subscriptions", test_dbus_peer_subscriptions);
Packit ae235b
  g_test_add_func ("/gmenu/attributes", test_attributes);
Packit ae235b
  g_test_add_func ("/gmenu/attributes/iterate", test_attribute_iter);
Packit ae235b
  g_test_add_func ("/gmenu/links", test_links);
Packit ae235b
  g_test_add_func ("/gmenu/mutable", test_mutable);
Packit ae235b
  g_test_add_func ("/gmenu/convenience", test_convenience);
Packit ae235b
  g_test_add_func ("/gmenu/menuitem", test_menuitem);
Packit ae235b
Packit ae235b
  ret = g_test_run ();
Packit ae235b
Packit ae235b
  session_bus_down ();
Packit ae235b
Packit ae235b
  return ret;
Packit ae235b
}
Packit ae235b
/* vim:set foldmethod=marker: */