summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon McVittie <simon.mcvittie@collabora.co.uk>2010-05-21 16:31:09 +0100
committerSimon McVittie <simon.mcvittie@collabora.co.uk>2010-05-21 16:31:09 +0100
commitc403d57a5ebebd9fbaa0b136f56257076adfafb9 (patch)
treee91c6dec464d7c3637bd8dc75b4e57ae72e527e7
parentdf5238a9ec5427d0931579f60be70161c5408aae (diff)
parentfa5ca18312eed17ab2b4f5e3238e64463fe29beb (diff)
Merge branch 'test-contact-list-cm'
-rw-r--r--examples/cm/contactlist/conn.c18
-rw-r--r--examples/cm/contactlist/connection-manager.c2
-rw-r--r--examples/cm/contactlist/contact-list-manager.c87
-rw-r--r--examples/cm/contactlist/manager-file.py4
-rw-r--r--tests/dbus/Makefile.am6
-rw-r--r--tests/dbus/contact-lists.c936
-rw-r--r--tests/lib/util.c37
-rw-r--r--tests/lib/util.h6
8 files changed, 1088 insertions, 8 deletions
diff --git a/examples/cm/contactlist/conn.c b/examples/cm/contactlist/conn.c
index 89588e7e..b335702f 100644
--- a/examples/cm/contactlist/conn.c
+++ b/examples/cm/contactlist/conn.c
@@ -38,12 +38,14 @@ G_DEFINE_TYPE_WITH_CODE (ExampleContactListConnection,
enum
{
PROP_ACCOUNT = 1,
+ PROP_SIMULATION_DELAY,
N_PROPS
};
struct _ExampleContactListConnectionPrivate
{
gchar *account;
+ guint simulation_delay;
ExampleContactListManager *list_manager;
gboolean away;
};
@@ -71,6 +73,10 @@ get_property (GObject *object,
g_value_set_string (value, self->priv->account);
break;
+ case PROP_SIMULATION_DELAY:
+ g_value_set_uint (value, self->priv->simulation_delay);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, spec);
}
@@ -92,6 +98,10 @@ set_property (GObject *object,
self->priv->account = g_value_dup_string (value);
break;
+ case PROP_SIMULATION_DELAY:
+ self->priv->simulation_delay = g_value_get_uint (value);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, spec);
}
@@ -221,6 +231,7 @@ create_channel_managers (TpBaseConnection *conn)
EXAMPLE_CONTACT_LIST_MANAGER (g_object_new (
EXAMPLE_TYPE_CONTACT_LIST_MANAGER,
"connection", conn,
+ "simulation-delay", self->priv->simulation_delay,
NULL));
g_signal_connect (self->priv->list_manager, "alias-updated",
@@ -431,6 +442,13 @@ example_contact_list_connection_class_init (
G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB);
g_object_class_install_property (object_class, PROP_ACCOUNT, param_spec);
+ param_spec = g_param_spec_uint ("simulation-delay", "Simulation delay",
+ "Delay between simulated network events",
+ 0, G_MAXUINT32, 1000,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_SIMULATION_DELAY,
+ param_spec);
+
tp_contacts_mixin_class_init (object_class,
G_STRUCT_OFFSET (ExampleContactListConnectionClass, contacts_mixin));
tp_presence_mixin_class_init (object_class,
diff --git a/examples/cm/contactlist/connection-manager.c b/examples/cm/contactlist/connection-manager.c
index 9c75629e..dda422a0 100644
--- a/examples/cm/contactlist/connection-manager.c
+++ b/examples/cm/contactlist/connection-manager.c
@@ -38,6 +38,7 @@ example_contact_list_connection_manager_init (
typedef struct {
gchar *account;
+ guint simulation_delay;
} ExampleParams;
static gboolean
@@ -93,6 +94,7 @@ new_connection (TpBaseConnectionManager *self,
conn = EXAMPLE_CONTACT_LIST_CONNECTION
(g_object_new (EXAMPLE_TYPE_CONTACT_LIST_CONNECTION,
"account", params->account,
+ "simulation-delay", params->simulation_delay,
"protocol", proto,
NULL));
diff --git a/examples/cm/contactlist/contact-list-manager.c b/examples/cm/contactlist/contact-list-manager.c
index 279f26be..160637ff 100644
--- a/examples/cm/contactlist/contact-list-manager.c
+++ b/examples/cm/contactlist/contact-list-manager.c
@@ -101,12 +101,14 @@ static guint signals[N_SIGNALS] = { 0 };
enum
{
PROP_CONNECTION = 1,
+ PROP_SIMULATION_DELAY,
N_PROPS
};
struct _ExampleContactListManagerPrivate
{
TpBaseConnection *conn;
+ guint simulation_delay;
TpHandleRepoIface *contact_repo;
TpHandleRepoIface *group_repo;
@@ -252,6 +254,11 @@ get_property (GObject *object,
case PROP_CONNECTION:
g_value_set_object (value, self->priv->conn);
break;
+
+ case PROP_SIMULATION_DELAY:
+ g_value_set_uint (value, self->priv->simulation_delay);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
@@ -273,6 +280,11 @@ set_property (GObject *object,
* less than its lifetime */
self->priv->conn = g_value_get_object (value);
break;
+
+ case PROP_SIMULATION_DELAY:
+ self->priv->simulation_delay = g_value_get_uint (value);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
@@ -318,6 +330,13 @@ ensure_contact (ExampleContactListManager *self,
g_hash_table_insert (self->priv->contact_details,
GUINT_TO_POINTER (contact), ret);
+
+ if (created != NULL)
+ *created = TRUE;
+ }
+ else if (created != NULL)
+ {
+ *created = FALSE;
}
return ret;
@@ -507,7 +526,7 @@ receive_contact_lists (gpointer p)
NULL, NULL, NULL, set,
0, TP_CHANNEL_GROUP_CHANGE_REASON_NONE);
tp_group_mixin_change_members ((GObject *) stored, "",
- NULL, NULL, NULL, set,
+ set, NULL, NULL, NULL,
0, TP_CHANNEL_GROUP_CHANGE_REASON_NONE);
tp_intset_fast_iter_init (&iter, set);
@@ -536,6 +555,9 @@ receive_contact_lists (gpointer p)
"I'm more metal than you!",
NULL, NULL, set, NULL,
handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE);
+ tp_group_mixin_change_members ((GObject *) stored, "",
+ set, NULL, NULL, NULL,
+ handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE);
tp_intset_destroy (set);
g_signal_emit (self, signals[ALIAS_UPDATED], 0, handle);
g_signal_emit (self, signals[PRESENCE_UPDATED], 0, handle);
@@ -553,6 +575,9 @@ receive_contact_lists (gpointer p)
"I have some fermented herring for you",
NULL, NULL, set, NULL,
handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE);
+ tp_group_mixin_change_members ((GObject *) stored, "",
+ set, NULL, NULL, NULL,
+ handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE);
tp_intset_destroy (set);
g_signal_emit (self, signals[ALIAS_UPDATED], 0, handle);
g_signal_emit (self, signals[PRESENCE_UPDATED], 0, handle);
@@ -600,7 +625,8 @@ status_changed_cb (TpBaseConnection *conn,
/* Do network I/O to get the contact list. This connection manager
* doesn't really have a server, so simulate a small network delay
* then invent a contact list */
- g_timeout_add_full (G_PRIORITY_DEFAULT, 1000, receive_contact_lists,
+ g_timeout_add_full (G_PRIORITY_DEFAULT,
+ 2 * self->priv->simulation_delay, receive_contact_lists,
g_object_ref (self), g_object_unref);
}
break;
@@ -653,6 +679,13 @@ example_contact_list_manager_class_init (ExampleContactListManagerClass *klass)
G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB);
g_object_class_install_property (object_class, PROP_CONNECTION, param_spec);
+ param_spec = g_param_spec_uint ("simulation-delay", "Simulation delay",
+ "Delay between simulated network events",
+ 0, G_MAXUINT32, 1000,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_SIMULATION_DELAY,
+ param_spec);
+
g_type_class_add_private (klass, sizeof (ExampleContactListManagerPrivate));
signals[ALIAS_UPDATED] = g_signal_new ("alias-updated",
@@ -1115,6 +1148,8 @@ receive_auth_request (ExampleContactListManager *self,
TpIntSet *set;
ExampleContactList *publish = self->priv->lists[
EXAMPLE_CONTACT_LIST_PUBLISH];
+ ExampleContactList *stored = self->priv->lists[
+ EXAMPLE_CONTACT_LIST_STORED];
/* if shutting down, do nothing */
if (publish == NULL)
@@ -1140,6 +1175,9 @@ receive_auth_request (ExampleContactListManager *self,
"May I see your presence, please?",
NULL, NULL, set, NULL,
contact, TP_CHANNEL_GROUP_CHANGE_REASON_NONE);
+ tp_group_mixin_change_members ((GObject *) stored, "",
+ set, NULL, NULL, NULL,
+ contact, TP_CHANNEL_GROUP_CHANGE_REASON_NONE);
tp_intset_destroy (set);
}
@@ -1151,6 +1189,8 @@ receive_authorized (gpointer p)
TpIntSet *set;
ExampleContactList *subscribe = s->self->priv->lists[
EXAMPLE_CONTACT_LIST_SUBSCRIBE];
+ ExampleContactList *stored = s->self->priv->lists[
+ EXAMPLE_CONTACT_LIST_STORED];
/* A remote contact has accepted our request to see their presence.
*
@@ -1173,6 +1213,9 @@ receive_authorized (gpointer p)
tp_group_mixin_change_members ((GObject *) subscribe, "",
set, NULL, NULL, NULL,
s->contact, TP_CHANNEL_GROUP_CHANGE_REASON_NONE);
+ tp_group_mixin_change_members ((GObject *) stored, "",
+ set, NULL, NULL, NULL,
+ s->contact, TP_CHANNEL_GROUP_CHANGE_REASON_NONE);
tp_intset_destroy (set);
/* their presence changes to something other than UNKNOWN */
@@ -1238,6 +1281,7 @@ example_contact_list_manager_add_to_list (ExampleContactListManager *self,
GError **error)
{
TpIntSet *set;
+ ExampleContactList *stored = self->priv->lists[EXAMPLE_CONTACT_LIST_STORED];
switch (list)
{
@@ -1268,9 +1312,14 @@ example_contact_list_manager_add_to_list (ExampleContactListManager *self,
NULL, NULL, NULL, set,
self->priv->conn->self_handle,
TP_CHANNEL_GROUP_CHANGE_REASON_NONE);
+ /* subscribing to someone implicitly puts them on Stored, too */
+ tp_group_mixin_change_members ((GObject *) stored, "",
+ set, NULL, NULL, NULL,
+ self->priv->conn->self_handle,
+ TP_CHANNEL_GROUP_CHANGE_REASON_NONE);
tp_intset_destroy (set);
- /* Pretend that after 500ms, the contact notices the request
+ /* Pretend that after a delay, the contact notices the request
* and allows or rejects it. In this example connection manager,
* empty requests are allowed, as are requests that contain "please"
* case-insensitively. All other requests are denied. */
@@ -1278,13 +1327,15 @@ example_contact_list_manager_add_to_list (ExampleContactListManager *self,
if (message[0] == '\0' || strstr (message_lc, "please") != NULL)
{
- g_timeout_add_full (G_PRIORITY_DEFAULT, 500, receive_authorized,
+ g_timeout_add_full (G_PRIORITY_DEFAULT,
+ self->priv->simulation_delay, receive_authorized,
self_and_contact_new (self, member),
self_and_contact_destroy);
}
else
{
- g_timeout_add_full (G_PRIORITY_DEFAULT, 500,
+ g_timeout_add_full (G_PRIORITY_DEFAULT,
+ self->priv->simulation_delay,
receive_unauthorized,
self_and_contact_new (self, member),
self_and_contact_destroy);
@@ -1302,6 +1353,8 @@ example_contact_list_manager_add_to_list (ExampleContactListManager *self,
if (d == NULL || !d->publish_requested)
{
+ /* the group mixin won't actually allow this to be reached,
+ * because of the flags we set */
g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
"Can't unilaterally send presence to %s",
tp_handle_inspect (self->priv->contact_repo, member));
@@ -1319,6 +1372,10 @@ example_contact_list_manager_add_to_list (ExampleContactListManager *self,
set, NULL, NULL, NULL,
self->priv->conn->self_handle,
TP_CHANNEL_GROUP_CHANGE_REASON_NONE);
+ tp_group_mixin_change_members ((GObject *) stored, "",
+ set, NULL, NULL, NULL,
+ self->priv->conn->self_handle,
+ TP_CHANNEL_GROUP_CHANGE_REASON_NONE);
tp_intset_destroy (set);
}
}
@@ -1403,9 +1460,10 @@ example_contact_list_manager_remove_from_list (ExampleContactListManager *self,
TP_CHANNEL_GROUP_CHANGE_REASON_NONE);
tp_intset_destroy (set);
- /* Pretend that after 500ms, the contact notices the change
+ /* Pretend that after a delay, the contact notices the change
* and asks for our presence again */
- g_timeout_add_full (G_PRIORITY_DEFAULT, 500, auth_request_cb,
+ g_timeout_add_full (G_PRIORITY_DEFAULT,
+ self->priv->simulation_delay, auth_request_cb,
self_and_contact_new (self, member),
self_and_contact_destroy);
}
@@ -1474,7 +1532,9 @@ example_contact_list_manager_remove_from_list (ExampleContactListManager *self,
case EXAMPLE_CONTACT_LIST_STORED:
/* we would like to remove member from the roster altogether */
{
- if (lookup_contact (self, member) != NULL)
+ ExampleContactDetails *d = lookup_contact (self, member);
+
+ if (d != NULL)
{
g_hash_table_remove (self->priv->contact_details,
GUINT_TO_POINTER (member));
@@ -1485,6 +1545,16 @@ example_contact_list_manager_remove_from_list (ExampleContactListManager *self,
NULL, set, NULL, NULL,
self->priv->conn->self_handle,
TP_CHANNEL_GROUP_CHANGE_REASON_NONE);
+ tp_group_mixin_change_members (
+ (GObject *) self->priv->lists[EXAMPLE_CONTACT_LIST_SUBSCRIBE],
+ "", NULL, set, NULL, NULL,
+ self->priv->conn->self_handle,
+ TP_CHANNEL_GROUP_CHANGE_REASON_NONE);
+ tp_group_mixin_change_members (
+ (GObject *) self->priv->lists[EXAMPLE_CONTACT_LIST_PUBLISH],
+ "", NULL, set, NULL, NULL,
+ self->priv->conn->self_handle,
+ TP_CHANNEL_GROUP_CHANGE_REASON_NONE);
tp_intset_destroy (set);
tp_handle_set_remove (self->priv->contacts, member);
@@ -1493,6 +1563,7 @@ example_contact_list_manager_remove_from_list (ExampleContactListManager *self,
* see their presence, so emit a signal changing it to
* UNKNOWN */
g_signal_emit (self, signals[PRESENCE_UPDATED], 0, member);
+
}
}
return TRUE;
diff --git a/examples/cm/contactlist/manager-file.py b/examples/cm/contactlist/manager-file.py
index 2e668a81..499de629 100644
--- a/examples/cm/contactlist/manager-file.py
+++ b/examples/cm/contactlist/manager-file.py
@@ -12,6 +12,10 @@ PARAMS = {
# 'struct_field': '...',
# 'setter_data': 'NULL',
},
+ 'simulation-delay': {
+ 'dtype': 'u',
+ 'default': 1000,
+ },
},
}
STRUCTS = {
diff --git a/tests/dbus/Makefile.am b/tests/dbus/Makefile.am
index 8f040ab5..30c2ae55 100644
--- a/tests/dbus/Makefile.am
+++ b/tests/dbus/Makefile.am
@@ -18,6 +18,7 @@ noinst_PROGRAMS = \
test-connection-handles \
test-connection-inject-bug16307 \
test-connection-getinterfaces-failure \
+ test-contact-lists \
test-contacts \
test-contacts-bug-19101 \
test-contacts-mixin \
@@ -89,6 +90,11 @@ test_cm_LDADD = \
test_connection_SOURCES = connection.c
+test_contact_lists_SOURCES = contact-lists.c
+test_contact_lists_LDADD = \
+ $(LDADD) \
+ $(top_builddir)/examples/cm/contactlist/libexample-cm-contactlist.la
+
test_connection_bug_18845_SOURCES = connection-bug-18845.c
test_connection_handles_SOURCES = connection-handles.c
diff --git a/tests/dbus/contact-lists.c b/tests/dbus/contact-lists.c
new file mode 100644
index 00000000..d75b6ac4
--- /dev/null
+++ b/tests/dbus/contact-lists.c
@@ -0,0 +1,936 @@
+/* Feature test for contact lists
+ *
+ * Copyright © 2007-2010 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright © 2007-2008 Nokia Corporation
+ *
+ * Copying and distribution of this file, with or without modification,
+ * are permitted in any medium without royalty provided the copyright
+ * notice and this notice are preserved.
+ */
+
+#include <telepathy-glib/connection.h>
+
+#include "examples/cm/contactlist/conn.h"
+#include "tests/lib/util.h"
+
+typedef struct {
+ TpDBusDaemon *dbus;
+ ExampleContactListConnection *service_conn;
+ TpBaseConnection *service_conn_as_base;
+ gchar *conn_name;
+ gchar *conn_path;
+ TpConnection *conn;
+
+ TpChannel *publish;
+ TpChannel *subscribe;
+ TpChannel *stored;
+
+ TpChannel *group;
+
+ TpHandleRepoIface *contact_repo;
+ TpHandle sjoerd;
+ TpHandle helen;
+ TpHandle wim;
+ TpHandle ninja;
+
+ GArray *arr;
+
+ GAsyncResult *prepare_result;
+} Test;
+
+static void
+setup (Test *test,
+ gconstpointer data)
+{
+ GError *error = NULL;
+ GQuark features[] = { TP_CONNECTION_FEATURE_CONNECTED, 0 };
+
+ g_type_init ();
+ tp_debug_set_flags ("all");
+ test->dbus = test_dbus_daemon_dup_or_die ();
+
+ test->service_conn = test_object_new_static_class (
+ EXAMPLE_TYPE_CONTACT_LIST_CONNECTION,
+ "account", "me@example.com",
+ "simulation-delay", 0,
+ "protocol", "example-contact-list",
+ NULL);
+ test->service_conn_as_base = TP_BASE_CONNECTION (test->service_conn);
+ g_assert (test->service_conn != NULL);
+ g_assert (test->service_conn_as_base != NULL);
+
+ g_assert (tp_base_connection_register (test->service_conn_as_base, "example",
+ &test->conn_name, &test->conn_path, &error));
+ g_assert_no_error (error);
+
+ test->contact_repo = tp_base_connection_get_handles (
+ test->service_conn_as_base, TP_HANDLE_TYPE_CONTACT);
+
+ test->conn = tp_connection_new (test->dbus, test->conn_name, test->conn_path,
+ &error);
+ g_assert (test->conn != NULL);
+ g_assert_no_error (error);
+ tp_cli_connection_call_connect (test->conn, -1, NULL, NULL, NULL, NULL);
+ test_proxy_run_until_prepared (test->conn, features);
+
+ g_assert (tp_proxy_is_prepared (test->conn, TP_CONNECTION_FEATURE_CORE));
+ g_assert (tp_proxy_is_prepared (test->conn,
+ TP_CONNECTION_FEATURE_CONNECTED));
+
+ test->sjoerd = tp_handle_ensure (test->contact_repo, "sjoerd@example.com",
+ NULL, NULL);
+ g_assert (test->sjoerd != 0);
+ test->helen = tp_handle_ensure (test->contact_repo, "helen@example.com",
+ NULL, NULL);
+ g_assert (test->helen != 0);
+ test->wim = tp_handle_ensure (test->contact_repo, "wim@example.com",
+ NULL, NULL);
+ g_assert (test->wim != 0);
+ test->ninja = tp_handle_ensure (test->contact_repo, "ninja@example.com",
+ NULL, NULL);
+ g_assert (test->ninja != 0);
+
+ test->arr = g_array_new (FALSE, FALSE, sizeof (TpHandle));
+}
+
+static void
+teardown (Test *test,
+ gconstpointer data)
+{
+ TpConnection *conn;
+ gboolean ok;
+ GError *error = NULL;
+
+ g_array_free (test->arr, TRUE);
+
+ tp_handle_unref (test->contact_repo, test->sjoerd);
+ tp_handle_unref (test->contact_repo, test->helen);
+ tp_handle_unref (test->contact_repo, test->wim);
+ tp_handle_unref (test->contact_repo, test->ninja);
+
+ test_clear_object (&test->conn);
+ test_clear_object (&test->publish);
+ test_clear_object (&test->subscribe);
+ test_clear_object (&test->stored);
+ test_clear_object (&test->group);
+
+ /* make a new TpConnection just to disconnect the underlying Connection,
+ * so we don't leak it */
+ conn = tp_connection_new (test->dbus, test->conn_name, test->conn_path,
+ &error);
+ g_assert (conn != NULL);
+ g_assert_no_error (error);
+ ok = tp_cli_connection_run_disconnect (conn, -1, &error, NULL);
+ g_assert (ok);
+ g_assert_no_error (error);
+ g_assert (!tp_connection_run_until_ready (conn, FALSE, &error, NULL));
+ g_assert_error (error, TP_ERRORS, TP_ERROR_CANCELLED);
+ g_clear_error (&error);
+
+ test->service_conn_as_base = NULL;
+ g_object_unref (test->service_conn);
+ g_free (test->conn_name);
+ g_free (test->conn_path);
+
+ g_object_unref (test->dbus);
+ test->dbus = NULL;
+}
+
+static TpChannel *
+test_ensure_channel (Test *test,
+ guint channel_type,
+ const gchar *id)
+{
+ GError *error = NULL;
+ GHashTable *asv, *props;
+ gchar *path;
+ TpChannel *ret;
+
+ asv = tp_asv_new (
+ TP_PROP_CHANNEL_CHANNEL_TYPE,
+ G_TYPE_STRING, TP_IFACE_CHANNEL_TYPE_CONTACT_LIST,
+ TP_PROP_CHANNEL_TARGET_HANDLE_TYPE,
+ G_TYPE_UINT, channel_type,
+ TP_PROP_CHANNEL_TARGET_ID,
+ G_TYPE_STRING, id,
+ NULL);
+ tp_cli_connection_interface_requests_run_ensure_channel (test->conn, -1,
+ asv, NULL, &path, &props, &error, NULL);
+ g_assert_no_error (error);
+ ret = tp_channel_new_from_properties (test->conn, path, props,
+ &error);
+ g_assert (ret != NULL);
+ g_assert_no_error (error);
+ g_free (path);
+ g_hash_table_unref (props);
+ g_hash_table_unref (asv);
+
+ test_proxy_run_until_prepared (ret, NULL);
+ return ret;
+}
+
+static void
+test_nothing (Test *test,
+ gconstpointer nil G_GNUC_UNUSED)
+{
+ /* this is actually a valuable test - it ensures that shutting down the
+ * CM before the contact list has been retrieved works! */
+}
+
+static void
+test_initial_channels (Test *test,
+ gconstpointer nil G_GNUC_UNUSED)
+{
+ test->publish = test_ensure_channel (test, TP_HANDLE_TYPE_LIST, "publish");
+ test->subscribe = test_ensure_channel (test, TP_HANDLE_TYPE_LIST,
+ "subscribe");
+ test->stored = test_ensure_channel (test, TP_HANDLE_TYPE_LIST, "stored");
+
+ g_assert_cmpuint (
+ tp_intset_size (tp_channel_group_get_members (test->publish)), ==, 4);
+ g_assert_cmpuint (
+ tp_intset_size (tp_channel_group_get_local_pending (test->publish)),
+ ==, 2);
+ g_assert_cmpuint (
+ tp_intset_size (tp_channel_group_get_remote_pending (test->publish)),
+ ==, 0);
+ g_assert (tp_intset_is_member (tp_channel_group_get_members (test->publish),
+ test->sjoerd));
+ g_assert (tp_intset_is_member (
+ tp_channel_group_get_local_pending (test->publish),
+ test->wim));
+
+ g_assert_cmpuint (
+ tp_intset_size (tp_channel_group_get_members (test->subscribe)), ==, 4);
+ g_assert_cmpuint (
+ tp_intset_size (tp_channel_group_get_local_pending (test->subscribe)),
+ ==, 0);
+ g_assert_cmpuint (
+ tp_intset_size (tp_channel_group_get_remote_pending (test->subscribe)),
+ ==, 2);
+ g_assert (tp_intset_is_member (
+ tp_channel_group_get_members (test->subscribe),
+ test->sjoerd));
+ g_assert (tp_intset_is_member (
+ tp_channel_group_get_remote_pending (test->subscribe),
+ test->helen));
+
+ g_assert_cmpuint (
+ tp_intset_size (tp_channel_group_get_members (test->stored)), ==, 8);
+ g_assert_cmpuint (
+ tp_intset_size (tp_channel_group_get_local_pending (test->stored)),
+ ==, 0);
+ g_assert_cmpuint (
+ tp_intset_size (tp_channel_group_get_remote_pending (test->stored)),
+ ==, 0);
+ g_assert (tp_intset_is_member (tp_channel_group_get_members (test->stored),
+ test->sjoerd));
+
+ g_assert (!tp_intset_is_member (tp_channel_group_get_members (test->publish),
+ test->ninja));
+ g_assert (!tp_intset_is_member (tp_channel_group_get_members (
+ test->subscribe),
+ test->ninja));
+ g_assert (!tp_intset_is_member (tp_channel_group_get_members (test->stored),
+ test->ninja));
+}
+
+static void
+test_accept_publish_request (Test *test,
+ gconstpointer nil G_GNUC_UNUSED)
+{
+ GError *error = NULL;
+
+ test->publish = test_ensure_channel (test, TP_HANDLE_TYPE_LIST, "publish");
+
+ g_assert_cmpuint (
+ tp_intset_size (tp_channel_group_get_local_pending (test->publish)),
+ ==, 2);
+ g_assert (tp_intset_is_member (
+ tp_channel_group_get_local_pending (test->publish),
+ test->wim));
+
+ g_array_append_val (test->arr, test->wim);
+ tp_cli_channel_interface_group_run_add_members (test->publish,
+ -1, test->arr, "", &error, NULL);
+ g_assert_no_error (error);
+
+ /* by the time the method returns, we should have had the
+ * change-notification, too */
+ g_assert_cmpuint (
+ tp_intset_size (tp_channel_group_get_local_pending (test->publish)),
+ ==, 1);
+ g_assert (tp_intset_is_member (
+ tp_channel_group_get_members (test->publish),
+ test->wim));
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_local_pending (test->publish),
+ test->wim));
+}
+
+static void
+test_reject_publish_request (Test *test,
+ gconstpointer nil G_GNUC_UNUSED)
+{
+ GError *error = NULL;
+
+ test->publish = test_ensure_channel (test, TP_HANDLE_TYPE_LIST, "publish");
+
+ g_assert (tp_intset_is_member (
+ tp_channel_group_get_local_pending (test->publish),
+ test->wim));
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_members (test->publish),
+ test->wim));
+
+ g_array_append_val (test->arr, test->wim);
+ tp_cli_channel_interface_group_run_remove_members (test->publish,
+ -1, test->arr, "", &error, NULL);
+
+ /* by the time the method returns, we should have had the
+ * removal-notification, too */
+ g_assert_cmpuint (
+ tp_intset_size (tp_channel_group_get_local_pending (test->publish)),
+ ==, 1);
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_members (test->publish),
+ test->wim));
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_local_pending (test->publish),
+ test->wim));
+}
+
+static void
+test_add_to_publish_invalid (Test *test,
+ gconstpointer nil G_GNUC_UNUSED)
+{
+ GError *error = NULL;
+
+ /* Unilaterally adding a member to the publish channel doesn't work. */
+
+ test->publish = test_ensure_channel (test, TP_HANDLE_TYPE_LIST, "publish");
+
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_local_pending (test->publish),
+ test->ninja));
+
+ g_array_append_val (test->arr, test->ninja);
+ tp_cli_channel_interface_group_run_add_members (test->publish,
+ -1, test->arr, "", &error, NULL);
+ g_assert_error (error, TP_ERRORS, TP_ERROR_PERMISSION_DENIED);
+ g_clear_error (&error);
+
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_local_pending (test->publish),
+ test->ninja));
+}
+
+static void
+test_add_to_publish_no_op (Test *test,
+ gconstpointer nil G_GNUC_UNUSED)
+{
+ GError *error = NULL;
+
+ /* Adding a member to the publish channel when they're already there is
+ * valid. */
+
+ test->publish = test_ensure_channel (test, TP_HANDLE_TYPE_LIST, "publish");
+
+ g_assert (tp_intset_is_member (
+ tp_channel_group_get_members (test->publish),
+ test->sjoerd));
+
+ g_array_append_val (test->arr, test->sjoerd);
+ tp_cli_channel_interface_group_run_add_members (test->publish,
+ -1, test->arr, "", &error, NULL);
+ g_assert_no_error (error);
+
+ g_assert (tp_intset_is_member (
+ tp_channel_group_get_members (test->publish),
+ test->sjoerd));
+}
+
+static void
+test_remove_from_publish (Test *test,
+ gconstpointer nil G_GNUC_UNUSED)
+{
+ GError *error = NULL;
+
+ test->publish = test_ensure_channel (test, TP_HANDLE_TYPE_LIST, "publish");
+
+ g_assert_cmpuint (
+ tp_intset_size (tp_channel_group_get_members (test->publish)),
+ ==, 4);
+ g_assert (tp_intset_is_member (
+ tp_channel_group_get_members (test->publish),
+ test->sjoerd));
+
+ g_array_append_val (test->arr, test->sjoerd);
+ tp_cli_channel_interface_group_run_remove_members (test->publish,
+ -1, test->arr, "", &error, NULL);
+ g_assert_no_error (error);
+
+ /* by the time the method returns, we should have had the
+ * removal-notification, too */
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_members (test->publish),
+ test->sjoerd));
+
+ /* the contact re-requests our presence after a short delay */
+ while (!tp_intset_is_member (
+ tp_channel_group_get_local_pending (test->publish),
+ test->sjoerd))
+ g_main_context_iteration (NULL, TRUE);
+
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_members (test->publish),
+ test->sjoerd));
+ g_assert (tp_intset_is_member (
+ tp_channel_group_get_local_pending (test->publish),
+ test->sjoerd));
+}
+
+static void
+test_remove_from_publish_no_op (Test *test,
+ gconstpointer nil G_GNUC_UNUSED)
+{
+ GError *error = NULL;
+
+ test->publish = test_ensure_channel (test, TP_HANDLE_TYPE_LIST, "publish");
+
+ g_assert_cmpuint (
+ tp_intset_size (tp_channel_group_get_members (test->publish)),
+ ==, 4);
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_members (test->publish),
+ test->ninja));
+
+ g_array_append_val (test->arr, test->ninja);
+ tp_cli_channel_interface_group_run_remove_members (test->publish,
+ -1, test->arr, "", &error, NULL);
+ g_assert_no_error (error);
+}
+
+static void
+test_add_to_stored (Test *test,
+ gconstpointer nil G_GNUC_UNUSED)
+{
+ GError *error = NULL;
+
+ test->stored = test_ensure_channel (test, TP_HANDLE_TYPE_LIST, "stored");
+ test->publish = test_ensure_channel (test, TP_HANDLE_TYPE_LIST, "publish");
+ test->subscribe = test_ensure_channel (test, TP_HANDLE_TYPE_LIST,
+ "subscribe");
+
+ g_assert_cmpuint (
+ tp_intset_size (tp_channel_group_get_members (test->stored)),
+ ==, 8);
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_members (test->stored),
+ test->ninja));
+
+ g_array_append_val (test->arr, test->ninja);
+ tp_cli_channel_interface_group_run_add_members (test->stored,
+ -1, test->arr, "", &error, NULL);
+ g_assert_no_error (error);
+
+ /* by the time the method returns, we should have had the
+ * change-notification, too */
+ g_assert_cmpuint (
+ tp_intset_size (tp_channel_group_get_members (test->stored)),
+ ==, 9);
+ g_assert (tp_intset_is_member (
+ tp_channel_group_get_members (test->stored),
+ test->ninja));
+
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_members (test->subscribe),
+ test->ninja));
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_members (test->publish),
+ test->ninja));
+}
+
+static void
+test_add_to_stored_no_op (Test *test,
+ gconstpointer nil G_GNUC_UNUSED)
+{
+ GError *error = NULL;
+
+ test->stored = test_ensure_channel (test, TP_HANDLE_TYPE_LIST, "stored");
+
+ g_assert_cmpuint (
+ tp_intset_size (tp_channel_group_get_members (test->stored)),
+ ==, 8);
+ g_assert (tp_intset_is_member (
+ tp_channel_group_get_members (test->stored),
+ test->sjoerd));
+
+ g_array_append_val (test->arr, test->sjoerd);
+ tp_cli_channel_interface_group_run_add_members (test->stored,
+ -1, test->arr, "", &error, NULL);
+ g_assert_no_error (error);
+}
+
+static void
+test_remove_from_stored (Test *test,
+ gconstpointer nil G_GNUC_UNUSED)
+{
+ GError *error = NULL;
+
+ test->stored = test_ensure_channel (test, TP_HANDLE_TYPE_LIST, "stored");
+ test->publish = test_ensure_channel (test, TP_HANDLE_TYPE_LIST, "publish");
+ test->subscribe = test_ensure_channel (test, TP_HANDLE_TYPE_LIST,
+ "subscribe");
+
+ g_assert (tp_intset_is_member (
+ tp_channel_group_get_members (test->stored),
+ test->sjoerd));
+
+ g_array_append_val (test->arr, test->sjoerd);
+ tp_cli_channel_interface_group_run_remove_members (test->stored,
+ -1, test->arr, "", &error, NULL);
+ g_assert_no_error (error);
+
+ /* by the time the method returns, we should have had the
+ * removal-notification, too */
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_members (test->stored),
+ test->sjoerd));
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_members (test->subscribe),
+ test->sjoerd));
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_members (test->publish),
+ test->sjoerd));
+}
+
+static void
+test_remove_from_stored_no_op (Test *test,
+ gconstpointer nil G_GNUC_UNUSED)
+{
+ GError *error = NULL;
+
+ test->stored = test_ensure_channel (test, TP_HANDLE_TYPE_LIST, "stored");
+
+ g_assert_cmpuint (
+ tp_intset_size (tp_channel_group_get_members (test->stored)),
+ ==, 8);
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_members (test->stored),
+ test->ninja));
+
+ g_array_append_val (test->arr, test->ninja);
+ tp_cli_channel_interface_group_run_remove_members (test->stored,
+ -1, test->arr, "", &error, NULL);
+ g_assert_no_error (error);
+}
+
+static void
+test_accept_subscribe_request (Test *test,
+ gconstpointer nil G_GNUC_UNUSED)
+{
+ GError *error = NULL;
+
+ test->subscribe = test_ensure_channel (test, TP_HANDLE_TYPE_LIST, "subscribe");
+ test->publish = test_ensure_channel (test, TP_HANDLE_TYPE_LIST, "publish");
+ test->stored = test_ensure_channel (test, TP_HANDLE_TYPE_LIST, "stored");
+
+ g_assert_cmpuint (
+ tp_intset_size (tp_channel_group_get_members (test->subscribe)),
+ ==, 4);
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_members (test->subscribe),
+ test->ninja));
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_remote_pending (test->subscribe),
+ test->ninja));
+
+ /* the example CM's fake contacts accept requests that contain "please" */
+ g_array_append_val (test->arr, test->ninja);
+ tp_cli_channel_interface_group_run_add_members (test->subscribe,
+ -1, test->arr, "Please may I see your presence?", &error, NULL);
+ g_assert_no_error (error);
+
+ /* by the time the method returns, we should have had the
+ * change-notification, too */
+ g_assert (tp_intset_is_member (
+ tp_channel_group_get_remote_pending (test->subscribe),
+ test->ninja));
+ g_assert (tp_intset_is_member (
+ tp_channel_group_get_members (test->stored),
+ test->ninja));
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_remote_pending (test->stored),
+ test->ninja));
+
+ /* after a short delay, the contact accepts our request */
+ while (tp_intset_is_member (
+ tp_channel_group_get_remote_pending (test->subscribe),
+ test->ninja))
+ g_main_context_iteration (NULL, TRUE);
+
+ g_assert (tp_intset_is_member (
+ tp_channel_group_get_members (test->subscribe),
+ test->ninja));
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_remote_pending (test->subscribe),
+ test->ninja));
+
+ /* the contact also requests our presence after a short delay */
+ while (!tp_intset_is_member (
+ tp_channel_group_get_local_pending (test->publish),
+ test->ninja))
+ g_main_context_iteration (NULL, TRUE);
+
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_members (test->publish),
+ test->ninja));
+ g_assert (tp_intset_is_member (
+ tp_channel_group_get_local_pending (test->publish),
+ test->ninja));
+}
+
+static void
+test_reject_subscribe_request (Test *test,
+ gconstpointer nil G_GNUC_UNUSED)
+{
+ GError *error = NULL;
+
+ test->subscribe = test_ensure_channel (test, TP_HANDLE_TYPE_LIST, "subscribe");
+ test->stored = test_ensure_channel (test, TP_HANDLE_TYPE_LIST, "stored");
+
+ g_assert_cmpuint (
+ tp_intset_size (tp_channel_group_get_members (test->subscribe)),
+ ==, 4);
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_members (test->subscribe),
+ test->ninja));
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_remote_pending (test->subscribe),
+ test->ninja));
+
+ /* the example CM's fake contacts reject requests that don't contain
+ * "please" */
+ g_array_append_val (test->arr, test->ninja);
+ tp_cli_channel_interface_group_run_add_members (test->subscribe,
+ -1, test->arr, "I demand to see your presence", &error, NULL);
+ g_assert_no_error (error);
+
+ /* by the time the method returns, we should have had the
+ * change-notification, too */
+ g_assert (tp_intset_is_member (
+ tp_channel_group_get_remote_pending (test->subscribe),
+ test->ninja));
+ g_assert (tp_intset_is_member (
+ tp_channel_group_get_members (test->stored),
+ test->ninja));
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_remote_pending (test->stored),
+ test->ninja));
+
+ /* after a short delay, the contact rejects our request. Say please! */
+ while (tp_intset_is_member (
+ tp_channel_group_get_remote_pending (test->subscribe),
+ test->ninja))
+ g_main_context_iteration (NULL, TRUE);
+
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_members (test->subscribe),
+ test->ninja));
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_remote_pending (test->subscribe),
+ test->ninja));
+
+ /* the ninja is still on the stored list */
+ g_assert (tp_intset_is_member (
+ tp_channel_group_get_members (test->stored),
+ test->ninja));
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_remote_pending (test->stored),
+ test->ninja));
+}
+
+static void
+test_remove_from_subscribe (Test *test,
+ gconstpointer nil G_GNUC_UNUSED)
+{
+ GError *error = NULL;
+
+ test->subscribe = test_ensure_channel (test, TP_HANDLE_TYPE_LIST, "subscribe");
+ test->stored = test_ensure_channel (test, TP_HANDLE_TYPE_LIST, "stored");
+
+ g_assert_cmpuint (
+ tp_intset_size (tp_channel_group_get_members (test->subscribe)),
+ ==, 4);
+ g_assert (tp_intset_is_member (
+ tp_channel_group_get_members (test->subscribe),
+ test->sjoerd));
+
+ g_array_append_val (test->arr, test->sjoerd);
+ tp_cli_channel_interface_group_run_remove_members (test->subscribe,
+ -1, test->arr, "", &error, NULL);
+ g_assert_no_error (error);
+
+ /* by the time the method returns, we should have had the
+ * removal-notification, too */
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_members (test->subscribe),
+ test->sjoerd));
+ g_assert (tp_intset_is_member (
+ tp_channel_group_get_members (test->stored),
+ test->sjoerd));
+}
+
+static void
+test_remove_from_subscribe_pending (Test *test,
+ gconstpointer nil G_GNUC_UNUSED)
+{
+ GError *error = NULL;
+
+ test->subscribe = test_ensure_channel (test, TP_HANDLE_TYPE_LIST, "subscribe");
+ test->stored = test_ensure_channel (test, TP_HANDLE_TYPE_LIST, "stored");
+
+ g_assert_cmpuint (
+ tp_intset_size (tp_channel_group_get_remote_pending (test->subscribe)),
+ ==, 2);
+ g_assert (tp_intset_is_member (
+ tp_channel_group_get_remote_pending (test->subscribe),
+ test->helen));
+
+ g_array_append_val (test->arr, test->helen);
+ tp_cli_channel_interface_group_run_remove_members (test->subscribe,
+ -1, test->arr, "", &error, NULL);
+ g_assert_no_error (error);
+
+ /* by the time the method returns, we should have had the
+ * removal-notification, too */
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_members (test->subscribe),
+ test->helen));
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_remote_pending (test->subscribe),
+ test->helen));
+ g_assert (tp_intset_is_member (
+ tp_channel_group_get_members (test->stored),
+ test->helen));
+}
+
+static void
+test_remove_from_subscribe_no_op (Test *test,
+ gconstpointer nil G_GNUC_UNUSED)
+{
+ GError *error = NULL;
+
+ test->subscribe = test_ensure_channel (test, TP_HANDLE_TYPE_LIST, "subscribe");
+
+ g_assert_cmpuint (
+ tp_intset_size (tp_channel_group_get_members (test->subscribe)),
+ ==, 4);
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_members (test->subscribe),
+ test->ninja));
+
+ g_array_append_val (test->arr, test->ninja);
+ tp_cli_channel_interface_group_run_remove_members (test->subscribe,
+ -1, test->arr, "", &error, NULL);
+ g_assert_no_error (error);
+}
+
+static void
+test_add_to_group (Test *test,
+ gconstpointer nil G_GNUC_UNUSED)
+{
+ GError *error = NULL;
+
+ test->group = test_ensure_channel (test, TP_HANDLE_TYPE_GROUP,
+ "Cambridge");
+ test->stored = test_ensure_channel (test, TP_HANDLE_TYPE_LIST, "stored");
+ test->publish = test_ensure_channel (test, TP_HANDLE_TYPE_LIST, "publish");
+ test->subscribe = test_ensure_channel (test, TP_HANDLE_TYPE_LIST,
+ "subscribe");
+
+ g_assert_cmpuint (
+ tp_intset_size (tp_channel_group_get_members (test->group)),
+ ==, 4);
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_members (test->group),
+ test->ninja));
+
+ g_array_append_val (test->arr, test->ninja);
+ tp_cli_channel_interface_group_run_add_members (test->group,
+ -1, test->arr, "", &error, NULL);
+ g_assert_no_error (error);
+
+ /* by the time the method returns, we should have had the
+ * change-notification, too */
+ g_assert_cmpuint (
+ tp_intset_size (tp_channel_group_get_members (test->group)),
+ ==, 5);
+ g_assert (tp_intset_is_member (
+ tp_channel_group_get_members (test->group),
+ test->ninja));
+
+ g_assert (tp_intset_is_member (
+ tp_channel_group_get_members (test->stored),
+ test->ninja));
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_members (test->subscribe),
+ test->ninja));
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_members (test->publish),
+ test->ninja));
+}
+
+static void
+test_add_to_group_no_op (Test *test,
+ gconstpointer nil G_GNUC_UNUSED)
+{
+ GError *error = NULL;
+
+ test->group = test_ensure_channel (test, TP_HANDLE_TYPE_GROUP,
+ "Cambridge");
+
+ g_assert (tp_intset_is_member (
+ tp_channel_group_get_members (test->group),
+ test->sjoerd));
+
+ g_array_append_val (test->arr, test->sjoerd);
+ tp_cli_channel_interface_group_run_add_members (test->group,
+ -1, test->arr, "", &error, NULL);
+ g_assert_no_error (error);
+}
+
+static void
+test_remove_from_group (Test *test,
+ gconstpointer nil G_GNUC_UNUSED)
+{
+ GError *error = NULL;
+
+ test->group = test_ensure_channel (test, TP_HANDLE_TYPE_GROUP,
+ "Cambridge");
+
+ g_assert (tp_intset_is_member (
+ tp_channel_group_get_members (test->group),
+ test->sjoerd));
+
+ g_array_append_val (test->arr, test->sjoerd);
+ tp_cli_channel_interface_group_run_remove_members (test->group,
+ -1, test->arr, "", &error, NULL);
+ g_assert_no_error (error);
+
+ /* by the time the method returns, we should have had the
+ * removal-notification, too */
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_members (test->group),
+ test->sjoerd));
+}
+
+static void
+test_remove_from_group_no_op (Test *test,
+ gconstpointer nil G_GNUC_UNUSED)
+{
+ GError *error = NULL;
+
+ test->group = test_ensure_channel (test, TP_HANDLE_TYPE_GROUP,
+ "Cambridge");
+
+ g_assert (!tp_intset_is_member (
+ tp_channel_group_get_members (test->group),
+ test->ninja));
+
+ g_array_append_val (test->arr, test->ninja);
+ tp_cli_channel_interface_group_run_remove_members (test->group,
+ -1, test->arr, "", &error, NULL);
+ g_assert_no_error (error);
+}
+
+static void
+test_remove_group (Test *test,
+ gconstpointer nil G_GNUC_UNUSED)
+{
+ GError *error = NULL;
+
+ test->group = test_ensure_channel (test, TP_HANDLE_TYPE_GROUP,
+ "Cambridge");
+
+ g_assert (!tp_intset_is_empty (
+ tp_channel_group_get_members (test->group)));
+
+ tp_cli_channel_run_close (test->group, -1, &error, NULL);
+ g_assert_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE);
+}
+
+static void
+test_remove_group_non_empty (Test *test,
+ gconstpointer nil G_GNUC_UNUSED)
+{
+ GError *error = NULL;
+
+ test->group = test_ensure_channel (test, TP_HANDLE_TYPE_GROUP,
+ "people who understand const in C");
+
+ g_assert (tp_intset_is_empty (
+ tp_channel_group_get_members (test->group)));
+
+ tp_cli_channel_run_close (test->group, -1, &error, NULL);
+ g_assert_no_error (error);
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add ("/contact-lists/nothing",
+ Test, NULL, setup, test_nothing, teardown);
+
+ g_test_add ("/contact-lists/initial-channels",
+ Test, NULL, setup, test_initial_channels, teardown);
+ g_test_add ("/contact-lists/accept-publish-request",
+ Test, NULL, setup, test_accept_publish_request, teardown);
+ g_test_add ("/contact-lists/reject-publish-request",
+ Test, NULL, setup, test_reject_publish_request, teardown);
+ g_test_add ("/contact-lists/add-to-publish/invalid",
+ Test, NULL, setup, test_add_to_publish_invalid, teardown);
+ g_test_add ("/contact-lists/add-to-publish/no-op",
+ Test, NULL, setup, test_add_to_publish_no_op, teardown);
+ g_test_add ("/contact-lists/remove-from-publish",
+ Test, NULL, setup, test_remove_from_publish, teardown);
+ g_test_add ("/contact-lists/remove-from-publish/no-op",
+ Test, NULL, setup, test_remove_from_publish_no_op, teardown);
+ g_test_add ("/contact-lists/add-to-stored",
+ Test, NULL, setup, test_add_to_stored, teardown);
+ g_test_add ("/contact-lists/add-to-stored/no-op",
+ Test, NULL, setup, test_add_to_stored_no_op, teardown);
+ g_test_add ("/contact-lists/remove-from-stored",
+ Test, NULL, setup, test_remove_from_stored, teardown);
+ g_test_add ("/contact-lists/remove-from-stored/no-op",
+ Test, NULL, setup, test_remove_from_stored_no_op, teardown);
+ g_test_add ("/contact-lists/accept-subscribe-request",
+ Test, NULL, setup, test_accept_subscribe_request, teardown);
+ g_test_add ("/contact-lists/reject-subscribe-request",
+ Test, NULL, setup, test_reject_subscribe_request, teardown);
+ g_test_add ("/contact-lists/remove-from-subscribe",
+ Test, NULL, setup, test_remove_from_subscribe, teardown);
+ g_test_add ("/contact-lists/remove-from-subscribe/pending",
+ Test, NULL, setup, test_remove_from_subscribe_pending, teardown);
+ g_test_add ("/contact-lists/remove-from-subscribe/no-op",
+ Test, NULL, setup, test_remove_from_subscribe_no_op, teardown);
+
+ g_test_add ("/contact-lists/add-to-group",
+ Test, NULL, setup, test_add_to_group, teardown);
+ g_test_add ("/contact-lists/add-to-group/no-op",
+ Test, NULL, setup, test_add_to_group_no_op, teardown);
+ g_test_add ("/contact-lists/remove-from-group",
+ Test, NULL, setup, test_remove_from_group, teardown);
+ g_test_add ("/contact-lists/remove-from-group/no-op",
+ Test, NULL, setup, test_remove_from_group_no_op, teardown);
+ g_test_add ("/contact-lists/remove-group",
+ Test, NULL, setup, test_remove_group, teardown);
+ g_test_add ("/contact-lists/remove-group/non-empty",
+ Test, NULL, setup, test_remove_group_non_empty, teardown);
+
+ return g_test_run ();
+}
diff --git a/tests/lib/util.c b/tests/lib/util.c
index 688725a6..5e24eb8f 100644
--- a/tests/lib/util.c
+++ b/tests/lib/util.c
@@ -10,6 +10,43 @@
#include "tests/lib/util.h"
+void
+test_proxy_run_until_prepared (gpointer proxy,
+ const GQuark *features)
+{
+ GError *error = NULL;
+
+ test_proxy_run_until_prepared_or_failed (proxy, features, &error);
+ g_assert_no_error (error);
+}
+
+static void
+prepared_cb (GObject *object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GAsyncResult **result = user_data;
+
+ *result = g_object_ref (res);
+}
+
+gboolean
+test_proxy_run_until_prepared_or_failed (gpointer proxy,
+ const GQuark *features,
+ GError **error)
+{
+ GAsyncResult *result = NULL;
+
+ tp_proxy_prepare_async (proxy, features, prepared_cb, &result);
+ /* not synchronous */
+ g_assert (result == NULL);
+
+ while (result == NULL)
+ g_main_context_iteration (NULL, TRUE);
+
+ return tp_proxy_prepare_finish (proxy, result, error);
+}
+
static void
conn_ready_cb (TpConnection *conn G_GNUC_UNUSED,
const GError *error,
diff --git a/tests/lib/util.h b/tests/lib/util.h
index 65d0957d..12ecf047 100644
--- a/tests/lib/util.h
+++ b/tests/lib/util.h
@@ -24,6 +24,12 @@ void test_proxy_run_until_dbus_queue_processed (gpointer proxy);
TpHandle test_connection_run_request_contact_handle (TpConnection *connection,
const gchar *id);
+void test_proxy_run_until_prepared (gpointer proxy,
+ const GQuark *features);
+gboolean test_proxy_run_until_prepared_or_failed (gpointer proxy,
+ const GQuark *features,
+ GError **error);
+
void test_connection_run_until_ready (TpConnection *conn);
void test_connection_manager_run_until_ready (TpConnectionManager *cm);
void test_connection_manager_run_until_readying_fails (TpConnectionManager *cm,