summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Dufresne <nicolas.dufresne@collabora.co.uk>2011-01-19 12:53:59 -0500
committerNicolas Dufresne <nicolas.dufresne@collabora.co.uk>2011-01-19 16:24:40 -0500
commita94c5e5cbc5c12e531ea677f1b7fba701e244f16 (patch)
treeb68c6a3b0f61dc95982886a26cfcff29770ec43f
parent26d77d70c6f7f52efb2dd7a829416015d87ee26c (diff)
Add test for _tpl_entity_new_from_tp_contact()
-rw-r--r--configure.ac1
-rw-r--r--tests/Makefile.am6
-rw-r--r--tests/lib/Makefile.am26
-rw-r--r--tests/lib/contacts-conn.c1268
-rw-r--r--tests/lib/contacts-conn.h184
-rw-r--r--tests/lib/simple-conn.c413
-rw-r--r--tests/lib/simple-conn.h77
-rw-r--r--tests/lib/textchan-null.c570
-rw-r--r--tests/lib/textchan-null.h137
-rw-r--r--tests/lib/util.c291
-rw-r--r--tests/lib/util.h57
-rw-r--r--tests/suppressions/tpl.supp46
-rw-r--r--tests/test-entity.c106
13 files changed, 3167 insertions, 15 deletions
diff --git a/configure.ac b/configure.ac
index f39cc73..f1efa76 100644
--- a/configure.ac
+++ b/configure.ac
@@ -222,6 +222,7 @@ AC_CONFIG_FILES([
telepathy-logger/telepathy-logger-0.1-uninstalled.pc
tools/Makefile
tests/Makefile
+ tests/lib/Makefile
tests/suppressions/Makefile
tests/twisted/Makefile
tests/twisted/tools/Makefile
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 6db1d88..b09613a 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -2,7 +2,7 @@ if WANT_TWISTED_TESTS
CHECKTWISTED = twisted
endif
-SUBDIRS = $(CHECKTWISTED) suppressions
+SUBDIRS = $(CHECKTWISTED) suppressions lib
LDADD = \
$(top_builddir)/telepathy-logger/libtelepathy-logger.la \
@@ -31,6 +31,10 @@ test_searches_SOURCES = \
test-searches.c \
constants.h
+test_entity_LDADD = \
+ $(top_builddir)/tests/lib/libtp-logger-tests.la \
+ $(LDADD)
+
AM_CFLAGS = \
$(ERROR_CFLAGS) \
$(TPL_CFLAGS) \
diff --git a/tests/lib/Makefile.am b/tests/lib/Makefile.am
new file mode 100644
index 0000000..97bcf88
--- /dev/null
+++ b/tests/lib/Makefile.am
@@ -0,0 +1,26 @@
+noinst_LTLIBRARIES = libtp-logger-tests.la
+
+libtp_logger_tests_la_SOURCES = \
+ contacts-conn.c \
+ contacts-conn.h \
+ simple-conn.c \
+ simple-conn.h \
+ textchan-null.c \
+ textchan-null.h \
+ util.c \
+ util.h
+
+check_c_sources = *.c
+include $(top_srcdir)/tools/check-coding-style.mk
+check-local: check-coding-style
+
+AM_CFLAGS = \
+ $(ERROR_CFLAGS) \
+ $(DBUS_CFLAGS) \
+ $(GLIB_CFLAGS) \
+ $(TPL_CFLAGS)
+
+libtp_logger_tests_la_LIBADD = \
+ $(DBUS_LIBS) \
+ $(GLIB_LIBS) \
+ $(top_builddir)/telepathy-logger/libtelepathy-logger.la
diff --git a/tests/lib/contacts-conn.c b/tests/lib/contacts-conn.c
new file mode 100644
index 0000000..f786d52
--- /dev/null
+++ b/tests/lib/contacts-conn.c
@@ -0,0 +1,1268 @@
+/*
+ * contacts-conn.c - connection with contact info
+ *
+ * Copyright (C) 2007-2008 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright (C) 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 "contacts-conn.h"
+
+#include <dbus/dbus-glib.h>
+
+#include <telepathy-glib/interfaces.h>
+#include <telepathy-glib/dbus.h>
+#include <telepathy-glib/errors.h>
+#include <telepathy-glib/gtypes.h>
+#include <telepathy-glib/handle-repo-dynamic.h>
+#include <telepathy-glib/util.h>
+
+static void init_aliasing (gpointer, gpointer);
+static void init_avatars (gpointer, gpointer);
+static void init_location (gpointer, gpointer);
+static void init_contact_caps (gpointer, gpointer);
+static void init_contact_info (gpointer, gpointer);
+static void conn_avatars_properties_getter (GObject *object, GQuark interface,
+ GQuark name, GValue *value, gpointer getter_data);
+
+G_DEFINE_TYPE_WITH_CODE (TpTestsContactsConnection,
+ tp_tests_contacts_connection,
+ TP_TESTS_TYPE_SIMPLE_CONNECTION,
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_ALIASING,
+ init_aliasing);
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_AVATARS,
+ init_avatars);
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACTS,
+ tp_contacts_mixin_iface_init);
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_PRESENCE,
+ tp_presence_mixin_iface_init);
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_SIMPLE_PRESENCE,
+ tp_presence_mixin_simple_presence_iface_init)
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_LOCATION,
+ init_location)
+ G_IMPLEMENT_INTERFACE (
+ TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_CAPABILITIES,
+ init_contact_caps)
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_INFO,
+ init_contact_info)
+ );
+
+/* type definition stuff */
+
+static const char *mime_types[] = { "image/png", NULL };
+static TpDBusPropertiesMixinPropImpl conn_avatars_properties[] = {
+ { "MinimumAvatarWidth", GUINT_TO_POINTER (1), NULL },
+ { "MinimumAvatarHeight", GUINT_TO_POINTER (2), NULL },
+ { "RecommendedAvatarWidth", GUINT_TO_POINTER (3), NULL },
+ { "RecommendedAvatarHeight", GUINT_TO_POINTER (4), NULL },
+ { "MaximumAvatarWidth", GUINT_TO_POINTER (5), NULL },
+ { "MaximumAvatarHeight", GUINT_TO_POINTER (6), NULL },
+ { "MaximumAvatarBytes", GUINT_TO_POINTER (7), NULL },
+ /* special-cased - it's the only one with a non-guint value */
+ { "SupportedAvatarMIMETypes", NULL, NULL },
+ { NULL }
+};
+
+enum
+{
+ N_SIGNALS
+};
+
+struct _TpTestsContactsConnectionPrivate
+{
+ /* TpHandle => gchar * */
+ GHashTable *aliases;
+ /* TpHandle => AvatarData */
+ GHashTable *avatars;
+ /* TpHandle => ContactsConnectionPresenceStatusIndex */
+ GHashTable *presence_statuses;
+ /* TpHandle => gchar * */
+ GHashTable *presence_messages;
+ /* TpHandle => GHashTable * */
+ GHashTable *locations;
+ /* TpHandle => GPtrArray * */
+ GHashTable *capabilities;
+ /* TpHandle => GPtrArray * */
+ GHashTable *contact_info;
+ GPtrArray *default_contact_info;
+};
+
+typedef struct
+{
+ GArray *data;
+ gchar *mime_type;
+ gchar *token;
+} AvatarData;
+
+static AvatarData *
+avatar_data_new (GArray *data,
+ const gchar *mime_type,
+ const gchar *token)
+{
+ AvatarData *a;
+
+ a = g_slice_new (AvatarData);
+ a->data = data ? g_array_ref (data) : NULL;
+ a->mime_type = g_strdup (mime_type);
+ a->token = g_strdup (token);
+
+ return a;
+}
+
+static void
+avatar_data_free (gpointer data)
+{
+ AvatarData *a = data;
+
+ if (a != NULL)
+ {
+ if (a->data != NULL)
+ g_array_unref (a->data);
+ g_free (a->mime_type);
+ g_free (a->token);
+ g_slice_free (AvatarData, a);
+ }
+}
+
+static void
+free_rcc_list (GPtrArray *rccs)
+{
+ g_boxed_free (TP_ARRAY_TYPE_REQUESTABLE_CHANNEL_CLASS_LIST, rccs);
+}
+
+static void
+tp_tests_contacts_connection_init (TpTestsContactsConnection *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TP_TESTS_TYPE_CONTACTS_CONNECTION,
+ TpTestsContactsConnectionPrivate);
+ self->priv->aliases = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ NULL, g_free);
+ self->priv->avatars = g_hash_table_new_full (g_direct_hash,
+ g_direct_equal, NULL, avatar_data_free);
+ self->priv->presence_statuses = g_hash_table_new_full (g_direct_hash,
+ g_direct_equal, NULL, NULL);
+ self->priv->presence_messages = g_hash_table_new_full (g_direct_hash,
+ g_direct_equal, NULL, g_free);
+ self->priv->locations = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ NULL, (GDestroyNotify) g_hash_table_unref);
+ self->priv->capabilities = g_hash_table_new_full (g_direct_hash,
+ g_direct_equal, NULL, (GDestroyNotify) free_rcc_list);
+ self->priv->contact_info = g_hash_table_new_full (g_direct_hash,
+ g_direct_equal, NULL, (GDestroyNotify) g_ptr_array_unref);
+}
+
+static void
+finalize (GObject *object)
+{
+ TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (object);
+
+ tp_contacts_mixin_finalize (object);
+ g_hash_table_destroy (self->priv->aliases);
+ g_hash_table_destroy (self->priv->avatars);
+ g_hash_table_destroy (self->priv->presence_statuses);
+ g_hash_table_destroy (self->priv->presence_messages);
+ g_hash_table_destroy (self->priv->locations);
+ g_hash_table_destroy (self->priv->capabilities);
+ g_hash_table_destroy (self->priv->contact_info);
+
+ if (self->priv->default_contact_info != NULL)
+ g_ptr_array_unref (self->priv->default_contact_info);
+
+ G_OBJECT_CLASS (tp_tests_contacts_connection_parent_class)->finalize (object);
+}
+
+static void
+aliasing_fill_contact_attributes (GObject *object,
+ const GArray *contacts,
+ GHashTable *attributes)
+{
+ guint i;
+ TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (object);
+ TpBaseConnection *base = TP_BASE_CONNECTION (object);
+ TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (base,
+ TP_HANDLE_TYPE_CONTACT);
+
+ for (i = 0; i < contacts->len; i++)
+ {
+ TpHandle handle = g_array_index (contacts, guint, i);
+ const gchar *alias = g_hash_table_lookup (self->priv->aliases,
+ GUINT_TO_POINTER (handle));
+
+ if (alias == NULL)
+ {
+ alias = tp_handle_inspect (contact_repo, handle);
+ }
+
+ tp_contacts_mixin_set_contact_attribute (attributes, handle,
+ TP_IFACE_CONNECTION_INTERFACE_ALIASING "/alias",
+ tp_g_value_slice_new_string (alias));
+ }
+}
+
+static void
+avatars_fill_contact_attributes (GObject *object,
+ const GArray *contacts,
+ GHashTable *attributes)
+{
+ guint i;
+ TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (object);
+
+ for (i = 0; i < contacts->len; i++)
+ {
+ TpHandle handle = g_array_index (contacts, guint, i);
+ AvatarData *a = g_hash_table_lookup (self->priv->avatars,
+ GUINT_TO_POINTER (handle));
+
+ if (a != NULL && a->token != NULL)
+ {
+ tp_contacts_mixin_set_contact_attribute (attributes, handle,
+ TP_IFACE_CONNECTION_INTERFACE_AVATARS "/token",
+ tp_g_value_slice_new_string (a->token));
+ }
+ }
+}
+
+static void
+location_fill_contact_attributes (GObject *object,
+ const GArray *contacts,
+ GHashTable *attributes)
+{
+ guint i;
+ TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (object);
+
+ for (i = 0; i < contacts->len; i++)
+ {
+ TpHandle handle = g_array_index (contacts, guint, i);
+ GHashTable *location = g_hash_table_lookup (self->priv->locations,
+ GUINT_TO_POINTER (handle));
+
+ if (location != NULL)
+ {
+ tp_contacts_mixin_set_contact_attribute (attributes, handle,
+ TP_IFACE_CONNECTION_INTERFACE_LOCATION "/location",
+ tp_g_value_slice_new_boxed (TP_HASH_TYPE_LOCATION, location));
+ }
+ }
+}
+
+static void
+contact_caps_fill_contact_attributes (GObject *object,
+ const GArray *contacts,
+ GHashTable *attributes)
+{
+ guint i;
+ TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (object);
+
+ for (i = 0; i < contacts->len; i++)
+ {
+ TpHandle handle = g_array_index (contacts, guint, i);
+ GPtrArray *caps = g_hash_table_lookup (self->priv->capabilities,
+ GUINT_TO_POINTER (handle));
+
+ if (caps != NULL)
+ {
+ tp_contacts_mixin_set_contact_attribute (attributes, handle,
+ TP_IFACE_CONNECTION_INTERFACE_CONTACT_CAPABILITIES "/capabilities",
+ tp_g_value_slice_new_boxed (
+ TP_ARRAY_TYPE_REQUESTABLE_CHANNEL_CLASS_LIST, caps));
+ }
+ }
+}
+
+static void
+contact_info_fill_contact_attributes (GObject *object,
+ const GArray *contacts,
+ GHashTable *attributes)
+{
+ guint i;
+ TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (object);
+
+ for (i = 0; i < contacts->len; i++)
+ {
+ TpHandle handle = g_array_index (contacts, guint, i);
+ GPtrArray *info = g_hash_table_lookup (self->priv->contact_info,
+ GUINT_TO_POINTER (handle));
+
+ if (info != NULL)
+ {
+ tp_contacts_mixin_set_contact_attribute (attributes, handle,
+ TP_IFACE_CONNECTION_INTERFACE_CONTACT_INFO "/info",
+ tp_g_value_slice_new_boxed (TP_ARRAY_TYPE_CONTACT_INFO_FIELD_LIST,
+ info));
+ }
+ }
+}
+
+static TpDBusPropertiesMixinPropImpl conn_contact_info_properties[] = {
+ { "ContactInfoFlags", GUINT_TO_POINTER (TP_CONTACT_INFO_FLAG_PUSH |
+ TP_CONTACT_INFO_FLAG_CAN_SET), NULL },
+ { "SupportedFields", NULL, NULL },
+ { NULL }
+};
+
+static void
+conn_contact_info_properties_getter (GObject *object,
+ GQuark interface,
+ GQuark name,
+ GValue *value,
+ gpointer getter_data)
+{
+ GQuark q_supported_fields = g_quark_from_static_string ("SupportedFields");
+ static GPtrArray *supported_fields = NULL;
+
+ if (name == q_supported_fields)
+ {
+ if (supported_fields == NULL)
+ {
+ supported_fields = g_ptr_array_new ();
+ g_ptr_array_add (supported_fields, tp_value_array_build (4,
+ G_TYPE_STRING, "n",
+ G_TYPE_STRV, NULL,
+ G_TYPE_UINT, 0,
+ G_TYPE_UINT, 0,
+ G_TYPE_INVALID));
+ }
+ g_value_set_boxed (value, supported_fields);
+ }
+ else
+ {
+ g_value_set_uint (value, GPOINTER_TO_UINT (getter_data));
+ }
+}
+
+static void
+constructed (GObject *object)
+{
+ TpBaseConnection *base = TP_BASE_CONNECTION (object);
+ void (*parent_impl) (GObject *) =
+ G_OBJECT_CLASS (tp_tests_contacts_connection_parent_class)->constructed;
+
+ if (parent_impl != NULL)
+ parent_impl (object);
+
+ tp_contacts_mixin_init (object,
+ G_STRUCT_OFFSET (TpTestsContactsConnection, contacts_mixin));
+ tp_base_connection_register_with_contacts_mixin (base);
+ tp_contacts_mixin_add_contact_attributes_iface (object,
+ TP_IFACE_CONNECTION_INTERFACE_ALIASING,
+ aliasing_fill_contact_attributes);
+ tp_contacts_mixin_add_contact_attributes_iface (object,
+ TP_IFACE_CONNECTION_INTERFACE_AVATARS,
+ avatars_fill_contact_attributes);
+ tp_contacts_mixin_add_contact_attributes_iface (object,
+ TP_IFACE_CONNECTION_INTERFACE_LOCATION,
+ location_fill_contact_attributes);
+ tp_contacts_mixin_add_contact_attributes_iface (object,
+ TP_IFACE_CONNECTION_INTERFACE_CONTACT_CAPABILITIES,
+ contact_caps_fill_contact_attributes);
+ tp_contacts_mixin_add_contact_attributes_iface (object,
+ TP_IFACE_CONNECTION_INTERFACE_CONTACT_INFO,
+ contact_info_fill_contact_attributes);
+
+ tp_presence_mixin_init (object,
+ G_STRUCT_OFFSET (TpTestsContactsConnection, presence_mixin));
+ tp_presence_mixin_simple_presence_register_with_contacts_mixin (object);
+}
+
+static const TpPresenceStatusOptionalArgumentSpec can_have_message[] = {
+ { "message", "s", NULL, NULL },
+ { NULL }
+};
+
+/* Must match TpTestsContactsConnectionPresenceStatusIndex in the .h */
+static const TpPresenceStatusSpec my_statuses[] = {
+ { "available", TP_CONNECTION_PRESENCE_TYPE_AVAILABLE, TRUE,
+ can_have_message },
+ { "busy", TP_CONNECTION_PRESENCE_TYPE_BUSY, TRUE, can_have_message },
+ { "away", TP_CONNECTION_PRESENCE_TYPE_AWAY, TRUE, can_have_message },
+ { "offline", TP_CONNECTION_PRESENCE_TYPE_OFFLINE, FALSE, NULL },
+ { "unknown", TP_CONNECTION_PRESENCE_TYPE_UNKNOWN, FALSE, NULL },
+ { "error", TP_CONNECTION_PRESENCE_TYPE_ERROR, FALSE, NULL },
+ { NULL }
+};
+
+static gboolean
+my_status_available (GObject *object,
+ guint index)
+{
+ TpBaseConnection *base = TP_BASE_CONNECTION (object);
+
+ if (base->status != TP_CONNECTION_STATUS_CONNECTED)
+ return FALSE;
+
+ return TRUE;
+}
+
+static GHashTable *
+my_get_contact_statuses (GObject *object,
+ const GArray *contacts,
+ GError **error)
+{
+ TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (object);
+ GHashTable *result = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ NULL, (GDestroyNotify) tp_presence_status_free);
+ guint i;
+
+ for (i = 0; i < contacts->len; i++)
+ {
+ TpHandle handle = g_array_index (contacts, TpHandle, i);
+ gpointer key = GUINT_TO_POINTER (handle);
+ TpTestsContactsConnectionPresenceStatusIndex index;
+ const gchar *presence_message;
+ GHashTable *parameters;
+
+ index = GPOINTER_TO_UINT (g_hash_table_lookup (
+ self->priv->presence_statuses, key));
+ presence_message = g_hash_table_lookup (
+ self->priv->presence_messages, key);
+
+ parameters = g_hash_table_new_full (g_str_hash,
+ g_str_equal, NULL, (GDestroyNotify) tp_g_value_slice_free);
+
+ if (presence_message != NULL)
+ g_hash_table_insert (parameters, "message",
+ tp_g_value_slice_new_string (presence_message));
+
+ g_hash_table_insert (result, key,
+ tp_presence_status_new (index, parameters));
+ g_hash_table_destroy (parameters);
+ }
+
+ return result;
+}
+
+static gboolean
+my_set_own_status (GObject *object,
+ const TpPresenceStatus *status,
+ GError **error)
+{
+ TpBaseConnection *base_conn = TP_BASE_CONNECTION (object);
+ TpTestsContactsConnectionPresenceStatusIndex index = status->index;
+ const gchar *message = "";
+
+ if (status->optional_arguments != NULL)
+ {
+ message = g_hash_table_lookup (status->optional_arguments, "message");
+
+ if (message == NULL)
+ message = "";
+ }
+
+ tp_tests_contacts_connection_change_presences (TP_TESTS_CONTACTS_CONNECTION (object),
+ 1, &(base_conn->self_handle), &index, &message);
+
+ return TRUE;
+}
+
+static void
+tp_tests_contacts_connection_class_init (TpTestsContactsConnectionClass *klass)
+{
+ TpBaseConnectionClass *base_class =
+ (TpBaseConnectionClass *) klass;
+ GObjectClass *object_class = (GObjectClass *) klass;
+ static const gchar *interfaces_always_present[] = {
+ TP_IFACE_CONNECTION_INTERFACE_ALIASING,
+ TP_IFACE_CONNECTION_INTERFACE_AVATARS,
+ TP_IFACE_CONNECTION_INTERFACE_CONTACTS,
+ TP_IFACE_CONNECTION_INTERFACE_PRESENCE,
+ TP_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE,
+ TP_IFACE_CONNECTION_INTERFACE_LOCATION,
+ TP_IFACE_CONNECTION_INTERFACE_CONTACT_CAPABILITIES,
+ TP_IFACE_CONNECTION_INTERFACE_CONTACT_INFO,
+ TP_IFACE_CONNECTION_INTERFACE_REQUESTS,
+ NULL };
+ static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = {
+ { TP_IFACE_CONNECTION_INTERFACE_AVATARS,
+ conn_avatars_properties_getter,
+ NULL,
+ conn_avatars_properties,
+ },
+ { TP_IFACE_CONNECTION_INTERFACE_CONTACT_INFO,
+ conn_contact_info_properties_getter,
+ NULL,
+ conn_contact_info_properties,
+ },
+ { NULL }
+ };
+
+ object_class->constructed = constructed;
+ object_class->finalize = finalize;
+ g_type_class_add_private (klass, sizeof (TpTestsContactsConnectionPrivate));
+
+ base_class->interfaces_always_present = interfaces_always_present;
+
+ tp_contacts_mixin_class_init (object_class,
+ G_STRUCT_OFFSET (TpTestsContactsConnectionClass, contacts_mixin));
+
+ tp_presence_mixin_class_init (object_class,
+ G_STRUCT_OFFSET (TpTestsContactsConnectionClass, presence_mixin),
+ my_status_available, my_get_contact_statuses,
+ my_set_own_status, my_statuses);
+
+ tp_presence_mixin_simple_presence_init_dbus_properties (object_class);
+
+ klass->properties_class.interfaces = prop_interfaces;
+ tp_dbus_properties_mixin_class_init (object_class,
+ G_STRUCT_OFFSET (TpTestsContactsConnectionClass, properties_class));
+}
+
+void
+tp_tests_contacts_connection_change_aliases (TpTestsContactsConnection *self,
+ guint n,
+ const TpHandle *handles,
+ const gchar * const *aliases)
+{
+ GPtrArray *structs = g_ptr_array_sized_new (n);
+ guint i;
+
+ for (i = 0; i < n; i++)
+ {
+ GValueArray *pair = g_value_array_new (2);
+
+ g_hash_table_insert (self->priv->aliases,
+ GUINT_TO_POINTER (handles[i]), g_strdup (aliases[i]));
+
+ g_value_array_append (pair, NULL);
+ g_value_init (pair->values + 0, G_TYPE_UINT);
+ g_value_set_uint (pair->values + 0, handles[i]);
+
+ g_value_array_append (pair, NULL);
+ g_value_init (pair->values + 1, G_TYPE_STRING);
+ g_value_set_string (pair->values + 1, aliases[i]);
+
+ g_ptr_array_add (structs, pair);
+ }
+
+ tp_svc_connection_interface_aliasing_emit_aliases_changed (self,
+ structs);
+
+ g_ptr_array_foreach (structs, (GFunc) g_value_array_free, NULL);
+ g_ptr_array_free (structs, TRUE);
+}
+
+void
+tp_tests_contacts_connection_change_presences (
+ TpTestsContactsConnection *self,
+ guint n,
+ const TpHandle *handles,
+ const TpTestsContactsConnectionPresenceStatusIndex *indexes,
+ const gchar * const *messages)
+{
+ GHashTable *presences = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ NULL, (GDestroyNotify) tp_presence_status_free);
+ guint i;
+
+ for (i = 0; i < n; i++)
+ {
+ GHashTable *parameters;
+ gpointer key = GUINT_TO_POINTER (handles[i]);
+
+ g_hash_table_insert (self->priv->presence_statuses, key,
+ GUINT_TO_POINTER (indexes[i]));
+ g_hash_table_insert (self->priv->presence_messages, key,
+ g_strdup (messages[i]));
+
+ parameters = g_hash_table_new_full (g_str_hash,
+ g_str_equal, NULL, (GDestroyNotify) tp_g_value_slice_free);
+
+ if (messages[i] != NULL && messages[i][0] != '\0')
+ g_hash_table_insert (parameters, "message",
+ tp_g_value_slice_new_string (messages[i]));
+
+ g_hash_table_insert (presences, key, tp_presence_status_new (indexes[i],
+ parameters));
+ g_hash_table_destroy (parameters);
+ }
+
+ tp_presence_mixin_emit_presence_update ((GObject *) self,
+ presences);
+ g_hash_table_destroy (presences);
+}
+
+void
+tp_tests_contacts_connection_change_avatar_tokens (TpTestsContactsConnection *self,
+ guint n,
+ const TpHandle *handles,
+ const gchar * const *tokens)
+{
+ guint i;
+
+ for (i = 0; i < n; i++)
+ {
+ g_hash_table_insert (self->priv->avatars,
+ GUINT_TO_POINTER (handles[i]), avatar_data_new (NULL, NULL, tokens[i]));
+ tp_svc_connection_interface_avatars_emit_avatar_updated (self,
+ handles[i], tokens[i]);
+ }
+}
+
+void
+tp_tests_contacts_connection_change_avatar_data (
+ TpTestsContactsConnection *self,
+ TpHandle handle,
+ GArray *data,
+ const gchar *mime_type,
+ const gchar *token)
+{
+ g_hash_table_insert (self->priv->avatars,
+ GUINT_TO_POINTER (handle), avatar_data_new (data, mime_type, token));
+
+ tp_svc_connection_interface_avatars_emit_avatar_updated (self,
+ handle, token);
+}
+
+void
+tp_tests_contacts_connection_change_locations (TpTestsContactsConnection *self,
+ guint n,
+ const TpHandle *handles,
+ GHashTable **locations)
+{
+ guint i;
+
+ for (i = 0; i < n; i++)
+ {
+ tp_asv_dump (locations[i]);
+ g_hash_table_insert (self->priv->locations,
+ GUINT_TO_POINTER (handles[i]), g_hash_table_ref (locations[i]));
+
+ tp_svc_connection_interface_location_emit_location_updated (self,
+ handles[i], locations[i]);
+ }
+}
+
+void
+tp_tests_contacts_connection_change_capabilities (
+ TpTestsContactsConnection *self,
+ GHashTable *capabilities)
+{
+ GHashTableIter iter;
+ gpointer handle, caps;
+
+ g_hash_table_iter_init (&iter, capabilities);
+ while (g_hash_table_iter_next (&iter, &handle, &caps))
+ {
+ g_hash_table_insert (self->priv->capabilities,
+ handle,
+ g_boxed_copy (TP_ARRAY_TYPE_REQUESTABLE_CHANNEL_CLASS_LIST,
+ caps));
+ }
+
+ tp_svc_connection_interface_contact_capabilities_emit_contact_capabilities_changed (
+ self, capabilities);
+}
+
+void
+tp_tests_contacts_connection_change_contact_info (
+ TpTestsContactsConnection *self,
+ TpHandle handle,
+ GPtrArray *info)
+{
+ g_hash_table_insert (self->priv->contact_info, GUINT_TO_POINTER (handle),
+ g_ptr_array_ref (info));
+
+ tp_svc_connection_interface_contact_info_emit_contact_info_changed (self,
+ handle, info);
+}
+
+void
+tp_tests_contacts_connection_set_default_contact_info (
+ TpTestsContactsConnection *self,
+ GPtrArray *info)
+{
+ if (self->priv->default_contact_info != NULL)
+ g_ptr_array_unref (self->priv->default_contact_info);
+ self->priv->default_contact_info = g_ptr_array_ref (info);
+}
+
+static void
+my_get_alias_flags (TpSvcConnectionInterfaceAliasing *aliasing,
+ DBusGMethodInvocation *context)
+{
+ TpBaseConnection *base = TP_BASE_CONNECTION (aliasing);
+
+ TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context);
+ tp_svc_connection_interface_aliasing_return_from_get_alias_flags (context,
+ 0);
+}
+
+static void
+my_get_aliases (TpSvcConnectionInterfaceAliasing *aliasing,
+ const GArray *contacts,
+ DBusGMethodInvocation *context)
+{
+ TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (aliasing);
+ TpBaseConnection *base = TP_BASE_CONNECTION (aliasing);
+ TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (base,
+ TP_HANDLE_TYPE_CONTACT);
+ GHashTable *result;
+ GError *error = NULL;
+ guint i;
+
+ TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context);
+
+ if (!tp_handles_are_valid (contact_repo, contacts, FALSE, &error))
+ {
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+ return;
+ }
+
+ result = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
+
+ for (i = 0; i < contacts->len; i++)
+ {
+ TpHandle handle = g_array_index (contacts, TpHandle, i);
+ const gchar *alias = g_hash_table_lookup (self->priv->aliases,
+ GUINT_TO_POINTER (handle));
+
+ if (alias == NULL)
+ g_hash_table_insert (result, GUINT_TO_POINTER (handle),
+ (gchar *) tp_handle_inspect (contact_repo, handle));
+ else
+ g_hash_table_insert (result, GUINT_TO_POINTER (handle),
+ (gchar *) alias);
+ }
+
+ tp_svc_connection_interface_aliasing_return_from_get_aliases (context,
+ result);
+ g_hash_table_destroy (result);
+}
+
+static void
+my_request_aliases (TpSvcConnectionInterfaceAliasing *aliasing,
+ const GArray *contacts,
+ DBusGMethodInvocation *context)
+{
+ TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (aliasing);
+ TpBaseConnection *base = TP_BASE_CONNECTION (aliasing);
+ TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (base,
+ TP_HANDLE_TYPE_CONTACT);
+ GPtrArray *result;
+ gchar **strings;
+ GError *error = NULL;
+ guint i;
+
+ TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context);
+
+ if (!tp_handles_are_valid (contact_repo, contacts, FALSE, &error))
+ {
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+ return;
+ }
+
+ result = g_ptr_array_sized_new (contacts->len + 1);
+
+ for (i = 0; i < contacts->len; i++)
+ {
+ TpHandle handle = g_array_index (contacts, TpHandle, i);
+ const gchar *alias = g_hash_table_lookup (self->priv->aliases,
+ GUINT_TO_POINTER (handle));
+
+ if (alias == NULL)
+ g_ptr_array_add (result,
+ (gchar *) tp_handle_inspect (contact_repo, handle));
+ else
+ g_ptr_array_add (result, (gchar *) alias);
+ }
+
+ g_ptr_array_add (result, NULL);
+ strings = (gchar **) g_ptr_array_free (result, FALSE);
+ tp_svc_connection_interface_aliasing_return_from_request_aliases (context,
+ (const gchar **) strings);
+ g_free (strings);
+}
+
+static void
+init_aliasing (gpointer g_iface,
+ gpointer iface_data)
+{
+ TpSvcConnectionInterfaceAliasingClass *klass = g_iface;
+
+#define IMPLEMENT(x) tp_svc_connection_interface_aliasing_implement_##x (\
+ klass, my_##x)
+ IMPLEMENT(get_alias_flags);
+ IMPLEMENT(request_aliases);
+ IMPLEMENT(get_aliases);
+ /* IMPLEMENT(set_aliases); */
+#undef IMPLEMENT
+}
+
+static void
+my_get_avatar_tokens (TpSvcConnectionInterfaceAvatars *avatars,
+ const GArray *contacts,
+ DBusGMethodInvocation *context)
+{
+ TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (avatars);
+ TpBaseConnection *base = TP_BASE_CONNECTION (avatars);
+ TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (base,
+ TP_HANDLE_TYPE_CONTACT);
+ GError *error = NULL;
+ GHashTable *result;
+ guint i;
+
+ TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context);
+
+ if (!tp_handles_are_valid (contact_repo, contacts, FALSE, &error))
+ {
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+ return;
+ }
+
+ result = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
+
+ for (i = 0; i < contacts->len; i++)
+ {
+ TpHandle handle = g_array_index (contacts, TpHandle, i);
+ AvatarData *a = g_hash_table_lookup (self->priv->avatars,
+ GUINT_TO_POINTER (handle));
+
+ if (a == NULL || a->token == NULL)
+ {
+ /* we're expected to do a round-trip to the server to find out
+ * their token, so we have to give some sort of result. Assume
+ * no avatar, here */
+ a = avatar_data_new (NULL, NULL, "");
+ g_hash_table_insert (self->priv->avatars,
+ GUINT_TO_POINTER (handle), a);
+ tp_svc_connection_interface_avatars_emit_avatar_updated (self,
+ handle, a->token);
+ }
+
+ g_hash_table_insert (result, GUINT_TO_POINTER (handle),
+ a->token);
+ }
+
+ tp_svc_connection_interface_avatars_return_from_get_known_avatar_tokens (
+ context, result);
+ g_hash_table_destroy (result);
+}
+
+static void
+my_get_known_avatar_tokens (TpSvcConnectionInterfaceAvatars *avatars,
+ const GArray *contacts,
+ DBusGMethodInvocation *context)
+{
+ TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (avatars);
+ TpBaseConnection *base = TP_BASE_CONNECTION (avatars);
+ TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (base,
+ TP_HANDLE_TYPE_CONTACT);
+ GError *error = NULL;
+ GHashTable *result;
+ guint i;
+
+ TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context);
+
+ if (!tp_handles_are_valid (contact_repo, contacts, FALSE, &error))
+ {
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+ return;
+ }
+
+ result = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
+
+ for (i = 0; i < contacts->len; i++)
+ {
+ TpHandle handle = g_array_index (contacts, TpHandle, i);
+ AvatarData *a = g_hash_table_lookup (self->priv->avatars,
+ GUINT_TO_POINTER (handle));
+ const gchar *token = a ? a->token : NULL;
+
+ g_hash_table_insert (result, GUINT_TO_POINTER (handle),
+ (gchar *) (token != NULL ? token : ""));
+ }
+
+ tp_svc_connection_interface_avatars_return_from_get_known_avatar_tokens (
+ context, result);
+ g_hash_table_destroy (result);
+}
+
+static void
+my_request_avatars (TpSvcConnectionInterfaceAvatars *avatars,
+ const GArray *contacts,
+ DBusGMethodInvocation *context)
+{
+ TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (avatars);
+ TpBaseConnection *base = TP_BASE_CONNECTION (avatars);
+ TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (base,
+ TP_HANDLE_TYPE_CONTACT);
+ GError *error = NULL;
+ guint i;
+
+ TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context);
+
+ if (!tp_handles_are_valid (contact_repo, contacts, FALSE, &error))
+ {
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+ return;
+ }
+
+ for (i = 0; i < contacts->len; i++)
+ {
+ TpHandle handle = g_array_index (contacts, TpHandle, i);
+ AvatarData *a = g_hash_table_lookup (self->priv->avatars,
+ GUINT_TO_POINTER (handle));
+
+ if (a != NULL)
+ tp_svc_connection_interface_avatars_emit_avatar_retrieved (self, handle,
+ a->token, a->data, a->mime_type);
+ }
+
+ tp_svc_connection_interface_avatars_return_from_request_avatars (context);
+}
+
+static void
+conn_avatars_properties_getter (GObject *object,
+ GQuark interface,
+ GQuark name,
+ GValue *value,
+ gpointer getter_data)
+{
+ GQuark q_mime_types = g_quark_from_static_string (
+ "SupportedAvatarMIMETypes");
+
+ if (name == q_mime_types)
+ {
+ g_value_set_static_boxed (value, mime_types);
+ }
+ else
+ {
+ g_value_set_uint (value, GPOINTER_TO_UINT (getter_data));
+ }
+}
+
+static void
+init_avatars (gpointer g_iface,
+ gpointer iface_data)
+{
+ TpSvcConnectionInterfaceAvatarsClass *klass = g_iface;
+
+#define IMPLEMENT(x) tp_svc_connection_interface_avatars_implement_##x (\
+ klass, my_##x)
+ /* IMPLEMENT(get_avatar_requirements); */
+ IMPLEMENT(get_avatar_tokens);
+ IMPLEMENT(get_known_avatar_tokens);
+ /* IMPLEMENT(request_avatar); */
+ IMPLEMENT(request_avatars);
+ /* IMPLEMENT(set_avatar); */
+ /* IMPLEMENT(clear_avatar); */
+#undef IMPLEMENT
+}
+
+static void
+my_get_locations (TpSvcConnectionInterfaceLocation *avatars,
+ const GArray *contacts,
+ DBusGMethodInvocation *context)
+{
+ TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (avatars);
+ TpBaseConnection *base = TP_BASE_CONNECTION (avatars);
+ TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (base,
+ TP_HANDLE_TYPE_CONTACT);
+ GError *error = NULL;
+ GHashTable *result;
+ guint i;
+
+ TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context);
+
+ if (!tp_handles_are_valid (contact_repo, contacts, FALSE, &error))
+ {
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+ return;
+ }
+
+ result = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
+
+ for (i = 0; i < contacts->len; i++)
+ {
+ TpHandle handle = g_array_index (contacts, TpHandle, i);
+ GHashTable *location = g_hash_table_lookup (self->priv->locations,
+ GUINT_TO_POINTER (handle));
+
+ if (location != NULL)
+ {
+ g_hash_table_insert (result, GUINT_TO_POINTER (handle), location);
+ }
+ }
+
+ tp_svc_connection_interface_location_return_from_get_locations (
+ context, result);
+ g_hash_table_destroy (result);
+}
+
+static void
+init_location (gpointer g_iface,
+ gpointer iface_data)
+{
+ TpSvcConnectionInterfaceLocationClass *klass = g_iface;
+
+#define IMPLEMENT(x) tp_svc_connection_interface_location_implement_##x (\
+ klass, my_##x)
+ IMPLEMENT(get_locations);
+#undef IMPLEMENT
+}
+
+static void
+my_get_contact_capabilities (TpSvcConnectionInterfaceContactCapabilities *obj,
+ const GArray *contacts,
+ DBusGMethodInvocation *context)
+{
+ TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (obj);
+ TpBaseConnection *base = TP_BASE_CONNECTION (obj);
+ TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (base,
+ TP_HANDLE_TYPE_CONTACT);
+ GError *error = NULL;
+ GHashTable *result;
+ guint i;
+
+ TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context);
+
+ if (!tp_handles_are_valid (contact_repo, contacts, FALSE, &error))
+ {
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+ return;
+ }
+
+ result = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
+
+ for (i = 0; i < contacts->len; i++)
+ {
+ TpHandle handle = g_array_index (contacts, TpHandle, i);
+ GPtrArray *arr = g_hash_table_lookup (self->priv->capabilities,
+ GUINT_TO_POINTER (handle));
+
+ if (arr != NULL)
+ {
+ g_hash_table_insert (result, GUINT_TO_POINTER (handle), arr);
+ }
+ }
+
+ tp_svc_connection_interface_contact_capabilities_return_from_get_contact_capabilities (
+ context, result);
+
+ g_hash_table_destroy (result);
+}
+
+static void
+init_contact_caps (gpointer g_iface,
+ gpointer iface_data)
+{
+ TpSvcConnectionInterfaceContactCapabilitiesClass *klass = g_iface;
+
+#define IMPLEMENT(x) tp_svc_connection_interface_contact_capabilities_implement_##x (\
+ klass, my_##x)
+ IMPLEMENT(get_contact_capabilities);
+#undef IMPLEMENT
+}
+
+static GPtrArray *
+lookup_contact_info (TpTestsContactsConnection *self,
+ TpHandle handle)
+{
+ GPtrArray *ret = g_hash_table_lookup (self->priv->contact_info,
+ GUINT_TO_POINTER (handle));
+
+ if (ret == NULL && self->priv->default_contact_info != NULL)
+ {
+ ret = self->priv->default_contact_info;
+ g_hash_table_insert (self->priv->contact_info, GUINT_TO_POINTER (handle),
+ g_ptr_array_ref (ret));
+ }
+
+ return ret;
+}
+
+static void
+my_refresh_contact_info (TpSvcConnectionInterfaceContactInfo *obj,
+ const GArray *contacts,
+ DBusGMethodInvocation *context)
+{
+ TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (obj);
+ TpBaseConnection *base = TP_BASE_CONNECTION (obj);
+ TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (base,
+ TP_HANDLE_TYPE_CONTACT);
+ GError *error = NULL;
+ guint i;
+
+ TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context);
+
+ if (!tp_handles_are_valid (contact_repo, contacts, FALSE, &error))
+ {
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+ return;
+ }
+
+ for (i = 0; i < contacts->len; i++)
+ {
+ TpHandle handle = g_array_index (contacts, guint, i);
+ GPtrArray *arr = lookup_contact_info (self, handle);
+
+ tp_svc_connection_interface_contact_info_emit_contact_info_changed (self,
+ handle, arr);
+ }
+
+ tp_svc_connection_interface_contact_info_return_from_refresh_contact_info (
+ context);
+}
+
+static void
+my_request_contact_info (TpSvcConnectionInterfaceContactInfo *obj,
+ guint handle,
+ DBusGMethodInvocation *context)
+{
+ TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (obj);
+ TpBaseConnection *base = TP_BASE_CONNECTION (obj);
+ TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (base,
+ TP_HANDLE_TYPE_CONTACT);
+ GError *error = NULL;
+ GPtrArray *ret;
+
+ TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context);
+
+ if (!tp_handle_is_valid (contact_repo, handle, &error))
+ {
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+ return;
+ }
+
+ ret = lookup_contact_info (self, handle);
+
+ tp_svc_connection_interface_contact_info_return_from_request_contact_info (
+ context, ret);
+}
+
+static void
+my_set_contact_info (TpSvcConnectionInterfaceContactInfo *obj,
+ const GPtrArray *info,
+ DBusGMethodInvocation *context)
+{
+ TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (obj);
+ TpBaseConnection *base = TP_BASE_CONNECTION (obj);
+ GPtrArray *copy;
+ guint i;
+ TpHandle self_handle;
+
+ TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context);
+
+ /* Deep copy info */
+ copy = g_ptr_array_new_with_free_func ((GDestroyNotify) g_value_array_free);
+ for (i = 0; i < info->len; i++)
+ g_ptr_array_add (copy, g_value_array_copy (g_ptr_array_index (info, i)));
+
+ self_handle = tp_base_connection_get_self_handle (base);
+ g_hash_table_insert (self->priv->contact_info, GUINT_TO_POINTER (self_handle),
+ copy);
+
+ tp_svc_connection_interface_contact_info_return_from_set_contact_info (
+ context);
+}
+
+static void
+init_contact_info (gpointer g_iface,
+ gpointer iface_data)
+{
+ TpSvcConnectionInterfaceContactInfoClass *klass = g_iface;
+
+#define IMPLEMENT(x) tp_svc_connection_interface_contact_info_implement_##x (\
+ klass, my_##x)
+ IMPLEMENT (refresh_contact_info);
+ IMPLEMENT (request_contact_info);
+ IMPLEMENT (set_contact_info);
+#undef IMPLEMENT
+}
+
+/* =============== Legacy version (no Contacts interface) ================= */
+
+G_DEFINE_TYPE (TpTestsLegacyContactsConnection,
+ tp_tests_legacy_contacts_connection, TP_TESTS_TYPE_CONTACTS_CONNECTION);
+
+enum
+{
+ LEGACY_PROP_HAS_IMMORTAL_HANDLES = 1
+};
+
+static void
+legacy_contacts_connection_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id)
+ {
+ case LEGACY_PROP_HAS_IMMORTAL_HANDLES:
+ /* Pretend we don't. */
+ g_value_set_boolean (value, FALSE);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+tp_tests_legacy_contacts_connection_init (TpTestsLegacyContactsConnection *self)
+{
+}
+
+static void
+tp_tests_legacy_contacts_connection_class_init (
+ TpTestsLegacyContactsConnectionClass *klass)
+{
+ /* Leave Contacts out of the interfaces we say are present, so clients
+ * won't use it */
+ static const gchar *interfaces_always_present[] = {
+ TP_IFACE_CONNECTION_INTERFACE_ALIASING,
+ TP_IFACE_CONNECTION_INTERFACE_AVATARS,
+ TP_IFACE_CONNECTION_INTERFACE_PRESENCE,
+ TP_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE,
+ TP_IFACE_CONNECTION_INTERFACE_LOCATION,
+ TP_IFACE_CONNECTION_INTERFACE_REQUESTS,
+ NULL };
+ TpBaseConnectionClass *base_class =
+ (TpBaseConnectionClass *) klass;
+ GObjectClass *object_class = (GObjectClass *) klass;
+
+ object_class->get_property = legacy_contacts_connection_get_property;
+
+ base_class->interfaces_always_present = interfaces_always_present;
+
+ g_object_class_override_property (object_class,
+ LEGACY_PROP_HAS_IMMORTAL_HANDLES, "has-immortal-handles");
+}
+
+/* =============== No Requests and no ContactCapabilities ================= */
+
+G_DEFINE_TYPE (TpTestsNoRequestsConnection, tp_tests_no_requests_connection,
+ TP_TESTS_TYPE_CONTACTS_CONNECTION);
+
+static void
+tp_tests_no_requests_connection_init (TpTestsNoRequestsConnection *self)
+{
+}
+
+static void
+tp_tests_no_requests_connection_class_init (
+ TpTestsNoRequestsConnectionClass *klass)
+{
+ static const gchar *interfaces_always_present[] = {
+ TP_IFACE_CONNECTION_INTERFACE_ALIASING,
+ TP_IFACE_CONNECTION_INTERFACE_AVATARS,
+ TP_IFACE_CONNECTION_INTERFACE_CONTACTS,
+ TP_IFACE_CONNECTION_INTERFACE_PRESENCE,
+ TP_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE,
+ TP_IFACE_CONNECTION_INTERFACE_LOCATION,
+ NULL };
+ TpBaseConnectionClass *base_class =
+ (TpBaseConnectionClass *) klass;
+
+ base_class->interfaces_always_present = interfaces_always_present;
+}
diff --git a/tests/lib/contacts-conn.h b/tests/lib/contacts-conn.h
new file mode 100644
index 0000000..baab460
--- /dev/null
+++ b/tests/lib/contacts-conn.h
@@ -0,0 +1,184 @@
+/*
+ * contacts-conn.h - header for a connection with contact info
+ *
+ * Copyright (C) 2007-2008 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright (C) 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.
+ */
+
+#ifndef __TP_TESTS_CONTACTS_CONN_H__
+#define __TP_TESTS_CONTACTS_CONN_H__
+
+#include <glib-object.h>
+#include <telepathy-glib/base-connection.h>
+#include <telepathy-glib/contacts-mixin.h>
+#include <telepathy-glib/presence-mixin.h>
+
+#include "simple-conn.h"
+
+G_BEGIN_DECLS
+
+typedef struct _TpTestsContactsConnection TpTestsContactsConnection;
+typedef struct _TpTestsContactsConnectionClass TpTestsContactsConnectionClass;
+typedef struct _TpTestsContactsConnectionPrivate TpTestsContactsConnectionPrivate;
+
+struct _TpTestsContactsConnectionClass {
+ TpTestsSimpleConnectionClass parent_class;
+
+ TpPresenceMixinClass presence_mixin;
+ TpContactsMixinClass contacts_mixin;
+ TpDBusPropertiesMixinClass properties_class;
+};
+
+struct _TpTestsContactsConnection {
+ TpTestsSimpleConnection parent;
+
+ TpPresenceMixin presence_mixin;
+ TpContactsMixin contacts_mixin;
+
+ TpTestsContactsConnectionPrivate *priv;
+};
+
+GType tp_tests_contacts_connection_get_type (void);
+
+/* Must match my_statuses in the .c */
+typedef enum {
+ TP_TESTS_CONTACTS_CONNECTION_STATUS_AVAILABLE,
+ TP_TESTS_CONTACTS_CONNECTION_STATUS_BUSY,
+ TP_TESTS_CONTACTS_CONNECTION_STATUS_AWAY,
+ TP_TESTS_CONTACTS_CONNECTION_STATUS_OFFLINE,
+ TP_TESTS_CONTACTS_CONNECTION_STATUS_UNKNOWN,
+ TP_TESTS_CONTACTS_CONNECTION_STATUS_ERROR
+} TpTestsContactsConnectionPresenceStatusIndex;
+
+/* TYPE MACROS */
+#define TP_TESTS_TYPE_CONTACTS_CONNECTION \
+ (tp_tests_contacts_connection_get_type ())
+#define TP_TESTS_CONTACTS_CONNECTION(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), TP_TESTS_TYPE_CONTACTS_CONNECTION, \
+ TpTestsContactsConnection))
+#define TP_TESTS_CONTACTS_CONNECTION_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), TP_TESTS_TYPE_CONTACTS_CONNECTION, \
+ TpTestsContactsConnectionClass))
+#define TP_TESTS_IS_CONTACTS_CONNECTION(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), TP_TESTS_TYPE_CONTACTS_CONNECTION))
+#define TP_TESTS_IS_CONTACTS_CONNECTION_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), TP_TESTS_TYPE_CONTACTS_CONNECTION))
+#define TP_TESTS_CONTACTS_CONNECTION_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_CONTACTS_CONNECTION, \
+ TpTestsContactsConnectionClass))
+
+void tp_tests_contacts_connection_change_aliases (
+ TpTestsContactsConnection *self, guint n,
+ const TpHandle *handles, const gchar * const *aliases);
+
+void tp_tests_contacts_connection_change_presences (
+ TpTestsContactsConnection *self, guint n, const TpHandle *handles,
+ const TpTestsContactsConnectionPresenceStatusIndex *indexes,
+ const gchar * const *messages);
+
+void tp_tests_contacts_connection_change_avatar_tokens (
+ TpTestsContactsConnection *self, guint n, const TpHandle *handles,
+ const gchar * const *tokens);
+
+void tp_tests_contacts_connection_change_avatar_data (
+ TpTestsContactsConnection *self,
+ TpHandle handle,
+ GArray *data,
+ const gchar *mime_type,
+ const gchar *token);
+
+void tp_tests_contacts_connection_change_locations (
+ TpTestsContactsConnection *self,
+ guint n,
+ const TpHandle *handles,
+ GHashTable **locations);
+
+void tp_tests_contacts_connection_change_capabilities (
+ TpTestsContactsConnection *self, GHashTable *capabilities);
+
+void tp_tests_contacts_connection_change_contact_info (
+ TpTestsContactsConnection *self, TpHandle handle, GPtrArray *info);
+
+void tp_tests_contacts_connection_set_default_contact_info (
+ TpTestsContactsConnection *self,
+ GPtrArray *info);
+
+/* Legacy version (no Contacts interface, and no immortal handles) */
+
+typedef struct _TpTestsLegacyContactsConnection TpTestsLegacyContactsConnection;
+typedef struct _TpTestsLegacyContactsConnectionClass TpTestsLegacyContactsConnectionClass;
+typedef struct _TpTestsLegacyContactsConnectionPrivate
+ TpTestsLegacyContactsConnectionPrivate;
+
+struct _TpTestsLegacyContactsConnectionClass {
+ TpTestsContactsConnectionClass parent_class;
+};
+
+struct _TpTestsLegacyContactsConnection {
+ TpTestsContactsConnection parent;
+
+ TpTestsLegacyContactsConnectionPrivate *priv;
+};
+
+GType tp_tests_legacy_contacts_connection_get_type (void);
+
+/* TYPE MACROS */
+#define TP_TESTS_TYPE_LEGACY_CONTACTS_CONNECTION \
+ (tp_tests_legacy_contacts_connection_get_type ())
+#define LEGACY_TP_TESTS_CONTACTS_CONNECTION(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), TP_TESTS_TYPE_LEGACY_CONTACTS_CONNECTION, \
+ TpTestsLegacyContactsConnection))
+#define LEGACY_TP_TESTS_CONTACTS_CONNECTION_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), TP_TESTS_TYPE_LEGACY_CONTACTS_CONNECTION, \
+ TpTestsLegacyContactsConnectionClass))
+#define TP_TESTS_LEGACY_CONTACTS_IS_CONNECTION(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), TP_TESTS_TYPE_LEGACY_CONTACTS_CONNECTION))
+#define TP_TESTS_LEGACY_CONTACTS_IS_CONNECTION_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), TP_TESTS_TYPE_LEGACY_CONTACTS_CONNECTION))
+#define LEGACY_TP_TESTS_CONTACTS_CONNECTION_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_LEGACY_CONTACTS_CONNECTION, \
+ TpTestsLegacyContactsConnectionClass))
+
+/* No Requests version */
+
+typedef struct _TpTestsNoRequestsConnection TpTestsNoRequestsConnection;
+typedef struct _TpTestsNoRequestsConnectionClass TpTestsNoRequestsConnectionClass;
+typedef struct _TpTestsNoRequestsConnectionPrivate
+ TpTestsNoRequestsConnectionPrivate;
+
+struct _TpTestsNoRequestsConnectionClass {
+ TpTestsContactsConnectionClass parent_class;
+};
+
+struct _TpTestsNoRequestsConnection {
+ TpTestsContactsConnection parent;
+
+ TpTestsNoRequestsConnectionPrivate *priv;
+};
+
+GType tp_tests_no_requests_connection_get_type (void);
+
+/* TYPE MACROS */
+#define TP_TESTS_TYPE_NO_REQUESTS_CONNECTION \
+ (tp_tests_no_requests_connection_get_type ())
+#define TP_TESTS_NO_REQUESTS_CONNECTION(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), TP_TESTS_TYPE_NO_REQUESTS_CONNECTION, \
+ TpTestsNoRequestsConnection))
+#define TP_TESTS_NO_REQUESTS_CONNECTION_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), TP_TESTS_TYPE_NO_REQUESTS_CONNECTION, \
+ TpTestsNoRequestsConnectionClass))
+#define TP_TESTS_NO_REQUESTS_IS_CONNECTION(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), TP_TESTS_TYPE_NO_REQUESTS_CONNECTION))
+#define TP_TESTS_NO_REQUESTS_IS_CONNECTION_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), TP_TESTS_TYPE_NO_REQUESTS_CONNECTION))
+#define TP_TESTS_NO_REQUESTS_CONNECTION_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_NO_REQUESTS_CONNECTION, \
+ TpTestsNoRequestsConnectionClass))
+
+G_END_DECLS
+
+#endif /* ifndef __TP_TESTS_CONTACTS_CONN_H__ */
diff --git a/tests/lib/simple-conn.c b/tests/lib/simple-conn.c
new file mode 100644
index 0000000..cbe3eda
--- /dev/null
+++ b/tests/lib/simple-conn.c
@@ -0,0 +1,413 @@
+/*
+ * simple-conn.c - a simple connection
+ *
+ * Copyright (C) 2007-2010 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright (C) 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 "simple-conn.h"
+
+#include <string.h>
+
+#include <dbus/dbus-glib.h>
+
+#include <telepathy-glib/dbus.h>
+#include <telepathy-glib/errors.h>
+#include <telepathy-glib/gtypes.h>
+#include <telepathy-glib/handle-repo-dynamic.h>
+#include <telepathy-glib/interfaces.h>
+#include <telepathy-glib/util.h>
+
+#include "textchan-null.h"
+#include "util.h"
+
+static void conn_iface_init (TpSvcConnectionClass *);
+
+G_DEFINE_TYPE_WITH_CODE (TpTestsSimpleConnection, tp_tests_simple_connection,
+ TP_TYPE_BASE_CONNECTION,
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION, conn_iface_init))
+
+/* type definition stuff */
+
+enum
+{
+ PROP_ACCOUNT = 1,
+ N_PROPS
+};
+
+enum
+{
+ SIGNAL_GOT_SELF_HANDLE,
+ N_SIGNALS
+};
+
+static guint signals[N_SIGNALS] = {0};
+
+struct _TpTestsSimpleConnectionPrivate
+{
+ gchar *account;
+ guint connect_source;
+ guint disconnect_source;
+
+ /* TpHandle => reffed TpTestsTextChannelNull */
+ GHashTable *channels;
+
+ GError *get_self_handle_error /* initially NULL */ ;
+};
+
+static void
+tp_tests_simple_connection_init (TpTestsSimpleConnection *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ TP_TESTS_TYPE_SIMPLE_CONNECTION, TpTestsSimpleConnectionPrivate);
+
+ self->priv->channels = g_hash_table_new_full (NULL, NULL, NULL,
+ (GDestroyNotify) g_object_unref);
+}
+
+static void
+get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *spec)
+{
+ TpTestsSimpleConnection *self = TP_TESTS_SIMPLE_CONNECTION (object);
+
+ switch (property_id) {
+ case PROP_ACCOUNT:
+ g_value_set_string (value, self->priv->account);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, spec);
+ }
+}
+
+static void
+set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *spec)
+{
+ TpTestsSimpleConnection *self = TP_TESTS_SIMPLE_CONNECTION (object);
+
+ switch (property_id) {
+ case PROP_ACCOUNT:
+ g_free (self->priv->account);
+ self->priv->account = g_utf8_strdown (g_value_get_string (value), -1);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, spec);
+ }
+}
+
+static void
+dispose (GObject *object)
+{
+ TpTestsSimpleConnection *self = TP_TESTS_SIMPLE_CONNECTION (object);
+
+ g_hash_table_unref (self->priv->channels);
+
+ G_OBJECT_CLASS (tp_tests_simple_connection_parent_class)->dispose (object);
+}
+
+static void
+finalize (GObject *object)
+{
+ TpTestsSimpleConnection *self = TP_TESTS_SIMPLE_CONNECTION (object);
+
+ if (self->priv->connect_source != 0)
+ {
+ g_source_remove (self->priv->connect_source);
+ }
+
+ if (self->priv->disconnect_source != 0)
+ {
+ g_source_remove (self->priv->disconnect_source);
+ }
+
+ g_clear_error (&self->priv->get_self_handle_error);
+ g_free (self->priv->account);
+
+ G_OBJECT_CLASS (tp_tests_simple_connection_parent_class)->finalize (object);
+}
+
+static gchar *
+get_unique_connection_name (TpBaseConnection *conn)
+{
+ TpTestsSimpleConnection *self = TP_TESTS_SIMPLE_CONNECTION (conn);
+
+ return g_strdup (self->priv->account);
+}
+
+static gchar *
+tp_tests_simple_normalize_contact (TpHandleRepoIface *repo,
+ const gchar *id,
+ gpointer context,
+ GError **error)
+{
+ if (id[0] == '\0')
+ {
+ g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_HANDLE,
+ "ID must not be empty");
+ return NULL;
+ }
+
+ if (strchr (id, ' ') != NULL)
+ {
+ g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_HANDLE,
+ "ID must not contain spaces");
+ return NULL;
+ }
+
+ return g_utf8_strdown (id, -1);
+}
+
+static void
+create_handle_repos (TpBaseConnection *conn,
+ TpHandleRepoIface *repos[NUM_TP_HANDLE_TYPES])
+{
+ repos[TP_HANDLE_TYPE_CONTACT] = tp_dynamic_handle_repo_new
+ (TP_HANDLE_TYPE_CONTACT, tp_tests_simple_normalize_contact, NULL);
+ repos[TP_HANDLE_TYPE_ROOM] = tp_dynamic_handle_repo_new
+ (TP_HANDLE_TYPE_ROOM, NULL, NULL);
+}
+
+static GPtrArray *
+create_channel_factories (TpBaseConnection *conn)
+{
+ return g_ptr_array_sized_new (0);
+}
+
+void
+tp_tests_simple_connection_inject_disconnect (TpTestsSimpleConnection *self)
+{
+ tp_base_connection_change_status ((TpBaseConnection *) self,
+ TP_CONNECTION_STATUS_DISCONNECTED,
+ TP_CONNECTION_STATUS_REASON_REQUESTED);
+}
+
+static gboolean
+pretend_connected (gpointer data)
+{
+ TpTestsSimpleConnection *self = TP_TESTS_SIMPLE_CONNECTION (data);
+ TpBaseConnection *conn = (TpBaseConnection *) self;
+ TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (conn,
+ TP_HANDLE_TYPE_CONTACT);
+
+ conn->self_handle = tp_handle_ensure (contact_repo, self->priv->account,
+ NULL, NULL);
+
+ if (conn->status == TP_CONNECTION_STATUS_CONNECTING)
+ {
+ tp_base_connection_change_status (conn, TP_CONNECTION_STATUS_CONNECTED,
+ TP_CONNECTION_STATUS_REASON_REQUESTED);
+ }
+
+ self->priv->connect_source = 0;
+ return FALSE;
+}
+
+static gboolean
+start_connecting (TpBaseConnection *conn,
+ GError **error)
+{
+ TpTestsSimpleConnection *self = TP_TESTS_SIMPLE_CONNECTION (conn);
+
+ tp_base_connection_change_status (conn, TP_CONNECTION_STATUS_CONNECTING,
+ TP_CONNECTION_STATUS_REASON_REQUESTED);
+
+ /* In a real connection manager we'd ask the underlying implementation to
+ * start connecting, then go to state CONNECTED when finished. Here there
+ * isn't actually a connection, so we'll fake a connection process that
+ * takes time. */
+ self->priv->connect_source = g_timeout_add (0, pretend_connected, self);
+
+ return TRUE;
+}
+
+static gboolean
+pretend_disconnected (gpointer data)
+{
+ TpTestsSimpleConnection *self = TP_TESTS_SIMPLE_CONNECTION (data);
+
+ /* We are disconnected, all our channels are invalidated */
+ g_hash_table_remove_all (self->priv->channels);
+
+ tp_base_connection_finish_shutdown (TP_BASE_CONNECTION (data));
+ self->priv->disconnect_source = 0;
+ return FALSE;
+}
+
+static void
+shut_down (TpBaseConnection *conn)
+{
+ TpTestsSimpleConnection *self = TP_TESTS_SIMPLE_CONNECTION (conn);
+
+ /* In a real connection manager we'd ask the underlying implementation to
+ * start shutting down, then call this function when finished. Here there
+ * isn't actually a connection, so we'll fake a disconnection process that
+ * takes time. */
+ self->priv->disconnect_source = g_timeout_add (0, pretend_disconnected,
+ conn);
+}
+
+static void
+tp_tests_simple_connection_class_init (TpTestsSimpleConnectionClass *klass)
+{
+ TpBaseConnectionClass *base_class =
+ (TpBaseConnectionClass *) klass;
+ GObjectClass *object_class = (GObjectClass *) klass;
+ GParamSpec *param_spec;
+ static const gchar *interfaces_always_present[] = {
+ TP_IFACE_CONNECTION_INTERFACE_REQUESTS, NULL };
+
+ object_class->get_property = get_property;
+ object_class->set_property = set_property;
+ object_class->dispose = dispose;
+ object_class->finalize = finalize;
+ g_type_class_add_private (klass, sizeof (TpTestsSimpleConnectionPrivate));
+
+ base_class->create_handle_repos = create_handle_repos;
+ base_class->get_unique_connection_name = get_unique_connection_name;
+ base_class->create_channel_factories = create_channel_factories;
+ base_class->start_connecting = start_connecting;
+ base_class->shut_down = shut_down;
+
+ base_class->interfaces_always_present = interfaces_always_present;
+
+ param_spec = g_param_spec_string ("account", "Account name",
+ "The username of this user", NULL,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
+ G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB);
+ g_object_class_install_property (object_class, PROP_ACCOUNT, param_spec);
+
+ signals[SIGNAL_GOT_SELF_HANDLE] = g_signal_new ("got-self-handle",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+void
+tp_tests_simple_connection_set_identifier (TpTestsSimpleConnection *self,
+ const gchar *identifier)
+{
+ TpBaseConnection *conn = (TpBaseConnection *) self;
+ TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (conn,
+ TP_HANDLE_TYPE_CONTACT);
+ TpHandle handle = tp_handle_ensure (contact_repo, identifier, NULL, NULL);
+
+ /* if this fails then the identifier was bad - caller error */
+ g_return_if_fail (handle != 0);
+
+ tp_base_connection_set_self_handle (conn, handle);
+ tp_handle_unref (contact_repo, handle);
+}
+
+TpTestsSimpleConnection *
+tp_tests_simple_connection_new (const gchar *account,
+ const gchar *protocol)
+{
+ return TP_TESTS_SIMPLE_CONNECTION (g_object_new (
+ TP_TESTS_TYPE_SIMPLE_CONNECTION,
+ "account", account,
+ "protocol", protocol,
+ NULL));
+}
+
+gchar *
+tp_tests_simple_connection_ensure_text_chan (TpTestsSimpleConnection *self,
+ const gchar *target_id,
+ GHashTable **props)
+{
+ TpTestsTextChannelNull *chan;
+ gchar *chan_path;
+ TpHandleRepoIface *contact_repo;
+ TpHandle handle;
+ static guint count = 0;
+ TpBaseConnection *base_conn = (TpBaseConnection *) self;
+
+ /* Get contact handle */
+ contact_repo = tp_base_connection_get_handles (base_conn,
+ TP_HANDLE_TYPE_CONTACT);
+ g_assert (contact_repo != NULL);
+
+ handle = tp_handle_ensure (contact_repo, target_id, NULL, NULL);
+
+ chan = g_hash_table_lookup (self->priv->channels, GUINT_TO_POINTER (handle));
+ if (chan != NULL)
+ {
+ /* Channel already exist, reuse it */
+ g_object_get (chan, "object-path", &chan_path, NULL);
+ }
+ else
+ {
+ chan_path = g_strdup_printf ("%s/Channel%u", base_conn->object_path,
+ count++);
+
+ chan = TP_TESTS_TEXT_CHANNEL_NULL (
+ tp_tests_object_new_static_class (
+ TP_TESTS_TYPE_TEXT_CHANNEL_NULL,
+ "connection", self,
+ "object-path", chan_path,
+ "handle", handle,
+ NULL));
+
+ g_hash_table_insert (self->priv->channels, GUINT_TO_POINTER (handle),
+ chan);
+ }
+
+ tp_handle_unref (contact_repo, handle);
+
+ if (props != NULL)
+ *props = tp_tests_text_channel_get_props (chan);
+
+ return chan_path;
+}
+
+void
+tp_tests_simple_connection_set_get_self_handle_error (
+ TpTestsSimpleConnection *self,
+ GQuark domain,
+ gint code,
+ const gchar *message)
+{
+ self->priv->get_self_handle_error = g_error_new_literal (domain, code,
+ message);
+}
+
+static void
+get_self_handle (TpSvcConnection *iface,
+ DBusGMethodInvocation *context)
+{
+ TpTestsSimpleConnection *self = TP_TESTS_SIMPLE_CONNECTION (iface);
+ TpBaseConnection *base = TP_BASE_CONNECTION (iface);
+
+ g_assert (TP_IS_BASE_CONNECTION (base));
+
+ TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context);
+
+ if (self->priv->get_self_handle_error != NULL)
+ {
+ dbus_g_method_return_error (context, self->priv->get_self_handle_error);
+ return;
+ }
+
+ tp_svc_connection_return_from_get_self_handle (context, base->self_handle);
+ g_signal_emit (self, signals[SIGNAL_GOT_SELF_HANDLE], 0);
+}
+
+static void
+conn_iface_init (TpSvcConnectionClass *iface)
+{
+#define IMPLEMENT(prefix,x) \
+ tp_svc_connection_implement_##x (iface, prefix##x)
+ IMPLEMENT(,get_self_handle);
+#undef IMPLEMENT
+}
diff --git a/tests/lib/simple-conn.h b/tests/lib/simple-conn.h
new file mode 100644
index 0000000..6322f4b
--- /dev/null
+++ b/tests/lib/simple-conn.h
@@ -0,0 +1,77 @@
+/*
+ * simple-conn.h - header for a simple connection
+ *
+ * Copyright (C) 2007-2008 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright (C) 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.
+ */
+
+#ifndef __TP_TESTS_SIMPLE_CONN_H__
+#define __TP_TESTS_SIMPLE_CONN_H__
+
+#include <glib-object.h>
+#include <telepathy-glib/base-connection.h>
+
+G_BEGIN_DECLS
+
+typedef struct _TpTestsSimpleConnection TpTestsSimpleConnection;
+typedef struct _TpTestsSimpleConnectionClass TpTestsSimpleConnectionClass;
+typedef struct _TpTestsSimpleConnectionPrivate TpTestsSimpleConnectionPrivate;
+
+struct _TpTestsSimpleConnectionClass {
+ TpBaseConnectionClass parent_class;
+};
+
+struct _TpTestsSimpleConnection {
+ TpBaseConnection parent;
+
+ TpTestsSimpleConnectionPrivate *priv;
+};
+
+GType tp_tests_simple_connection_get_type (void);
+
+/* TYPE MACROS */
+#define TP_TESTS_TYPE_SIMPLE_CONNECTION \
+ (tp_tests_simple_connection_get_type ())
+#define TP_TESTS_SIMPLE_CONNECTION(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), TP_TESTS_TYPE_SIMPLE_CONNECTION, \
+ TpTestsSimpleConnection))
+#define TP_TESTS_SIMPLE_CONNECTION_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), TP_TESTS_TYPE_SIMPLE_CONNECTION, \
+ TpTestsSimpleConnectionClass))
+#define TP_TESTS_SIMPLE_IS_CONNECTION(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), TP_TESTS_TYPE_SIMPLE_CONNECTION))
+#define TP_TESTS_SIMPLE_IS_CONNECTION_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), TP_TESTS_TYPE_SIMPLE_CONNECTION))
+#define TP_TESTS_SIMPLE_CONNECTION_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_SIMPLE_CONNECTION, \
+ TpTestsSimpleConnectionClass))
+
+TpTestsSimpleConnection * tp_tests_simple_connection_new (const gchar *account,
+ const gchar *protocol);
+
+/* Cause "network events", for debugging/testing */
+
+void tp_tests_simple_connection_inject_disconnect (
+ TpTestsSimpleConnection *self);
+
+void tp_tests_simple_connection_set_identifier (TpTestsSimpleConnection *self,
+ const gchar *identifier);
+
+gchar * tp_tests_simple_connection_ensure_text_chan (
+ TpTestsSimpleConnection *self,
+ const gchar *target_id,
+ GHashTable **props);
+
+void tp_tests_simple_connection_set_get_self_handle_error (
+ TpTestsSimpleConnection *self,
+ GQuark domain,
+ gint code,
+ const gchar *message);
+
+G_END_DECLS
+
+#endif /* #ifndef __TP_TESTS_SIMPLE_CONN_H__ */
diff --git a/tests/lib/textchan-null.c b/tests/lib/textchan-null.c
new file mode 100644
index 0000000..c41fceb
--- /dev/null
+++ b/tests/lib/textchan-null.c
@@ -0,0 +1,570 @@
+/*
+ * /dev/null as a text channel
+ *
+ * Copyright (C) 2008 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright (C) 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 "textchan-null.h"
+
+#include <telepathy-glib/base-connection.h>
+#include <telepathy-glib/channel-iface.h>
+#include <telepathy-glib/dbus.h>
+#include <telepathy-glib/dbus-properties-mixin.h>
+#include <telepathy-glib/interfaces.h>
+#include <telepathy-glib/svc-channel.h>
+#include <telepathy-glib/svc-generic.h>
+
+static void text_iface_init (gpointer iface, gpointer data);
+static void channel_iface_init (gpointer iface, gpointer data);
+
+G_DEFINE_TYPE_WITH_CODE (TpTestsTextChannelNull,
+ tp_tests_text_channel_null,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL, channel_iface_init);
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_TEXT, text_iface_init);
+ G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_IFACE, NULL))
+
+G_DEFINE_TYPE_WITH_CODE (TpTestsPropsTextChannel,
+ tp_tests_props_text_channel,
+ TP_TESTS_TYPE_TEXT_CHANNEL_NULL,
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES,
+ tp_dbus_properties_mixin_iface_init))
+
+G_DEFINE_TYPE_WITH_CODE (TpTestsPropsGroupTextChannel,
+ tp_tests_props_group_text_channel,
+ TP_TESTS_TYPE_PROPS_TEXT_CHANNEL,
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_GROUP,
+ tp_group_mixin_iface_init))
+
+static const char *tp_tests_text_channel_null_interfaces[] = { NULL };
+
+/* type definition stuff */
+
+enum
+{
+ PROP_OBJECT_PATH = 1,
+ PROP_CHANNEL_TYPE,
+ PROP_HANDLE_TYPE,
+ PROP_HANDLE,
+ PROP_TARGET_ID,
+ PROP_CONNECTION,
+ PROP_INTERFACES,
+ PROP_REQUESTED,
+ PROP_INITIATOR_HANDLE,
+ PROP_INITIATOR_ID,
+ N_PROPS
+};
+
+struct _TpTestsTextChannelNullPrivate
+{
+ TpBaseConnection *conn;
+ gchar *object_path;
+ TpHandle handle;
+
+ unsigned closed:1;
+ unsigned disposed:1;
+};
+
+static void
+tp_tests_text_channel_null_init (TpTestsTextChannelNull *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ TP_TESTS_TYPE_TEXT_CHANNEL_NULL, TpTestsTextChannelNullPrivate);
+}
+
+static void
+tp_tests_props_text_channel_init (TpTestsPropsTextChannel *self)
+{
+ self->dbus_property_interfaces_retrieved = g_hash_table_new (NULL, NULL);
+}
+
+static GObject *
+constructor (GType type,
+ guint n_props,
+ GObjectConstructParam *props)
+{
+ GObject *object =
+ G_OBJECT_CLASS (tp_tests_text_channel_null_parent_class)->constructor (type,
+ n_props, props);
+ TpTestsTextChannelNull *self = TP_TESTS_TEXT_CHANNEL_NULL (object);
+ TpHandleRepoIface *contact_repo = tp_base_connection_get_handles
+ (self->priv->conn, TP_HANDLE_TYPE_CONTACT);
+
+ tp_handle_ref (contact_repo, self->priv->handle);
+
+ tp_dbus_daemon_register_object (
+ tp_base_connection_get_dbus_daemon (self->priv->conn),
+ self->priv->object_path, self);
+
+ tp_text_mixin_init (object, G_STRUCT_OFFSET (TpTestsTextChannelNull, text),
+ contact_repo);
+
+ tp_text_mixin_set_message_types (object,
+ TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL,
+ TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION,
+ TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE,
+ G_MAXUINT);
+
+ return object;
+}
+
+static void
+get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ TpTestsTextChannelNull *self = TP_TESTS_TEXT_CHANNEL_NULL (object);
+
+ switch (property_id)
+ {
+ case PROP_OBJECT_PATH:
+ g_value_set_string (value, self->priv->object_path);
+ break;
+ case PROP_CHANNEL_TYPE:
+ g_value_set_static_string (value, TP_IFACE_CHANNEL_TYPE_TEXT);
+ break;
+ case PROP_HANDLE_TYPE:
+ g_value_set_uint (value, TP_HANDLE_TYPE_CONTACT);
+ break;
+ case PROP_HANDLE:
+ g_value_set_uint (value, self->priv->handle);
+ break;
+ case PROP_TARGET_ID:
+ {
+ TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (
+ self->priv->conn, TP_HANDLE_TYPE_CONTACT);
+
+ g_value_set_string (value,
+ tp_handle_inspect (contact_repo, self->priv->handle));
+ }
+ break;
+ case PROP_REQUESTED:
+ g_value_set_boolean (value, TRUE);
+ break;
+ case PROP_INITIATOR_HANDLE:
+ g_value_set_uint (value, self->priv->conn->self_handle);
+ break;
+ case PROP_INITIATOR_ID:
+ {
+ TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (
+ self->priv->conn, TP_HANDLE_TYPE_CONTACT);
+
+ g_value_set_string (value,
+ tp_handle_inspect (contact_repo, self->priv->conn->self_handle));
+ }
+ break;
+ case PROP_INTERFACES:
+ g_value_set_boxed (value, tp_tests_text_channel_null_interfaces);
+ break;
+ case PROP_CONNECTION:
+ g_value_set_object (value, self->priv->conn);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ TpTestsTextChannelNull *self = TP_TESTS_TEXT_CHANNEL_NULL (object);
+
+ switch (property_id)
+ {
+ case PROP_OBJECT_PATH:
+ g_free (self->priv->object_path);
+ self->priv->object_path = g_value_dup_string (value);
+ break;
+ case PROP_HANDLE:
+ /* we don't ref it here because we don't necessarily have access to the
+ * contact repo yet - instead we ref it in the constructor.
+ */
+ self->priv->handle = g_value_get_uint (value);
+ break;
+ case PROP_HANDLE_TYPE:
+ case PROP_CHANNEL_TYPE:
+ /* these properties are writable in the interface, but not actually
+ * meaningfully changable on this channel, so we do nothing */
+ break;
+ case PROP_CONNECTION:
+ self->priv->conn = g_value_get_object (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+void
+tp_tests_text_channel_null_close (TpTestsTextChannelNull *self)
+{
+ if (!self->priv->closed)
+ {
+ self->priv->closed = TRUE;
+ tp_svc_channel_emit_closed (self);
+ tp_dbus_daemon_unregister_object (
+ tp_base_connection_get_dbus_daemon (self->priv->conn), self);
+ }
+}
+
+static void
+dispose (GObject *object)
+{
+ TpTestsTextChannelNull *self = TP_TESTS_TEXT_CHANNEL_NULL (object);
+
+ if (self->priv->disposed)
+ return;
+
+ self->priv->disposed = TRUE;
+ tp_tests_text_channel_null_close (self);
+
+ ((GObjectClass *) tp_tests_text_channel_null_parent_class)->dispose (object);
+}
+
+static void
+finalize (GObject *object)
+{
+ TpTestsTextChannelNull *self = TP_TESTS_TEXT_CHANNEL_NULL (object);
+ TpHandleRepoIface *contact_handles = tp_base_connection_get_handles
+ (self->priv->conn, TP_HANDLE_TYPE_CONTACT);
+
+ tp_handle_unref (contact_handles, self->priv->handle);
+ g_free (self->priv->object_path);
+
+ tp_text_mixin_finalize (object);
+
+ ((GObjectClass *) tp_tests_text_channel_null_parent_class)->finalize (object);
+}
+
+static void
+tp_tests_text_channel_null_class_init (TpTestsTextChannelNullClass *klass)
+{
+ GObjectClass *object_class = (GObjectClass *) klass;
+ GParamSpec *param_spec;
+
+ g_type_class_add_private (klass, sizeof (TpTestsTextChannelNullPrivate));
+
+ object_class->constructor = constructor;
+ object_class->set_property = set_property;
+ object_class->get_property = get_property;
+ object_class->dispose = dispose;
+ object_class->finalize = finalize;
+
+ g_object_class_override_property (object_class, PROP_OBJECT_PATH,
+ "object-path");
+ g_object_class_override_property (object_class, PROP_CHANNEL_TYPE,
+ "channel-type");
+ g_object_class_override_property (object_class, PROP_HANDLE_TYPE,
+ "handle-type");
+ g_object_class_override_property (object_class, PROP_HANDLE, "handle");
+
+ param_spec = g_param_spec_object ("connection", "TpBaseConnection object",
+ "Connection object that owns this channel",
+ TP_TYPE_BASE_CONNECTION,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
+ G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB);
+ g_object_class_install_property (object_class, PROP_CONNECTION, param_spec);
+
+ param_spec = g_param_spec_boxed ("interfaces", "Extra D-Bus interfaces",
+ "Additional Channel.Interface.* interfaces",
+ G_TYPE_STRV,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_INTERFACES, param_spec);
+
+ param_spec = g_param_spec_string ("target-id", "Peer's ID",
+ "The string obtained by inspecting the target handle",
+ NULL,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_TARGET_ID, param_spec);
+
+ param_spec = g_param_spec_uint ("initiator-handle", "Initiator's handle",
+ "The contact who initiated the channel",
+ 0, G_MAXUINT32, 0,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_INITIATOR_HANDLE,
+ param_spec);
+
+ param_spec = g_param_spec_string ("initiator-id", "Initiator's ID",
+ "The string obtained by inspecting the initiator-handle",
+ NULL,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_INITIATOR_ID,
+ param_spec);
+
+ param_spec = g_param_spec_boolean ("requested", "Requested?",
+ "True if this channel was requested by the local user",
+ FALSE,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_REQUESTED, param_spec);
+
+ tp_text_mixin_class_init (object_class,
+ G_STRUCT_OFFSET (TpTestsTextChannelNullClass, text_class));
+}
+
+static void
+tp_tests_props_text_channel_getter_gobject_properties (GObject *object,
+ GQuark interface,
+ GQuark name,
+ GValue *value,
+ gpointer getter_data)
+{
+ TpTestsPropsTextChannel *self = TP_TESTS_PROPS_TEXT_CHANNEL (object);
+
+ g_hash_table_insert (self->dbus_property_interfaces_retrieved,
+ GUINT_TO_POINTER (interface), GUINT_TO_POINTER (interface));
+
+ tp_dbus_properties_mixin_getter_gobject_properties (object, interface, name,
+ value, getter_data);
+}
+
+static void
+props_finalize (GObject *object)
+{
+ TpTestsPropsTextChannel *self = TP_TESTS_PROPS_TEXT_CHANNEL (object);
+
+ g_hash_table_unref (self->dbus_property_interfaces_retrieved);
+
+ ((GObjectClass *) tp_tests_props_text_channel_parent_class)->finalize (object);
+}
+
+static void
+tp_tests_props_text_channel_class_init (TpTestsPropsTextChannelClass *klass)
+{
+ GObjectClass *object_class = (GObjectClass *) klass;
+ static TpDBusPropertiesMixinPropImpl channel_props[] = {
+ { "TargetHandleType", "handle-type", NULL },
+ { "TargetHandle", "handle", NULL },
+ { "ChannelType", "channel-type", NULL },
+ { "Interfaces", "interfaces", NULL },
+ { "TargetID", "target-id", NULL },
+ { "Requested", "requested", NULL },
+ { "InitiatorHandle", "initiator-handle", NULL },
+ { "InitiatorID", "initiator-id", NULL },
+ { NULL }
+ };
+ static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = {
+ { TP_IFACE_CHANNEL,
+ tp_tests_props_text_channel_getter_gobject_properties,
+ NULL,
+ channel_props,
+ },
+ { NULL }
+ };
+
+ object_class->finalize = props_finalize;
+
+ klass->dbus_properties_class.interfaces = prop_interfaces;
+ tp_dbus_properties_mixin_class_init (object_class,
+ G_STRUCT_OFFSET (TpTestsPropsTextChannelClass, dbus_properties_class));
+}
+
+static void
+tp_tests_props_group_text_channel_init (TpTestsPropsGroupTextChannel *self)
+{
+}
+
+static void
+group_constructed (GObject *self)
+{
+ TpBaseConnection *conn = TP_TESTS_TEXT_CHANNEL_NULL (self)->priv->conn;
+ void (*chain_up) (GObject *) =
+ ((GObjectClass *) tp_tests_props_group_text_channel_parent_class)->constructed;
+
+ if (chain_up != NULL)
+ chain_up (self);
+
+ tp_group_mixin_init (self,
+ G_STRUCT_OFFSET (TpTestsPropsGroupTextChannel, group),
+ tp_base_connection_get_handles (conn, TP_HANDLE_TYPE_CONTACT),
+ tp_base_connection_get_self_handle (conn));
+ tp_group_mixin_change_flags (self, TP_CHANNEL_GROUP_FLAG_PROPERTIES, 0);
+}
+
+static void
+group_finalize (GObject *self)
+{
+ tp_group_mixin_finalize (self);
+
+ ((GObjectClass *) tp_tests_props_group_text_channel_parent_class)->finalize (self);
+}
+
+static gboolean
+dummy_add_remove_member (GObject *obj,
+ TpHandle handle,
+ const gchar *message,
+ GError **error)
+{
+ return TRUE;
+}
+
+static void
+group_iface_props_getter (GObject *object,
+ GQuark interface,
+ GQuark name,
+ GValue *value,
+ gpointer getter_data)
+{
+ TpTestsPropsTextChannel *self = TP_TESTS_PROPS_TEXT_CHANNEL (object);
+
+ g_hash_table_insert (self->dbus_property_interfaces_retrieved,
+ GUINT_TO_POINTER (interface), GUINT_TO_POINTER (interface));
+
+ tp_group_mixin_get_dbus_property (object, interface, name, value, getter_data);
+}
+
+static void
+tp_tests_props_group_text_channel_class_init (TpTestsPropsGroupTextChannelClass *klass)
+{
+ GObjectClass *object_class = (GObjectClass *) klass;
+ static TpDBusPropertiesMixinPropImpl group_props[] = {
+ { "GroupFlags", NULL, NULL },
+ { "HandleOwners", NULL, NULL },
+ { "LocalPendingMembers", NULL, NULL },
+ { "Members", NULL, NULL },
+ { "RemotePendingMembers", NULL, NULL },
+ { "SelfHandle", NULL, NULL },
+ { NULL }
+ };
+
+ object_class->constructed = group_constructed;
+ object_class->finalize = group_finalize;
+
+ tp_group_mixin_class_init (object_class,
+ G_STRUCT_OFFSET (TpTestsPropsGroupTextChannelClass, group_class),
+ dummy_add_remove_member,
+ dummy_add_remove_member);
+ tp_dbus_properties_mixin_implement_interface (object_class,
+ TP_IFACE_QUARK_CHANNEL_INTERFACE_GROUP, group_iface_props_getter, NULL,
+ group_props);
+}
+
+static void
+channel_close (TpSvcChannel *iface,
+ DBusGMethodInvocation *context)
+{
+ TpTestsTextChannelNull *self = TP_TESTS_TEXT_CHANNEL_NULL (iface);
+
+ tp_tests_text_channel_null_close (self);
+ tp_svc_channel_return_from_close (context);
+}
+
+static void
+channel_get_channel_type (TpSvcChannel *iface,
+ DBusGMethodInvocation *context)
+{
+ TpTestsTextChannelNull *self = TP_TESTS_TEXT_CHANNEL_NULL (iface);
+
+ self->get_channel_type_called++;
+
+ tp_svc_channel_return_from_get_channel_type (context,
+ TP_IFACE_CHANNEL_TYPE_TEXT);
+}
+
+static void
+channel_get_handle (TpSvcChannel *iface,
+ DBusGMethodInvocation *context)
+{
+ TpTestsTextChannelNull *self = TP_TESTS_TEXT_CHANNEL_NULL (iface);
+
+ self->get_handle_called++;
+
+ tp_svc_channel_return_from_get_handle (context, TP_HANDLE_TYPE_CONTACT,
+ self->priv->handle);
+}
+
+static void
+channel_get_interfaces (TpSvcChannel *iface,
+ DBusGMethodInvocation *context)
+{
+ TpTestsTextChannelNull *self = TP_TESTS_TEXT_CHANNEL_NULL (iface);
+
+ self->get_interfaces_called++;
+
+ tp_svc_channel_return_from_get_interfaces (context,
+ tp_tests_text_channel_null_interfaces);
+}
+
+static void
+channel_iface_init (gpointer iface,
+ gpointer data)
+{
+ TpSvcChannelClass *klass = iface;
+
+#define IMPLEMENT(x) tp_svc_channel_implement_##x (klass, channel_##x)
+ IMPLEMENT (close);
+ IMPLEMENT (get_channel_type);
+ IMPLEMENT (get_handle);
+ IMPLEMENT (get_interfaces);
+#undef IMPLEMENT
+}
+
+static void
+text_send (TpSvcChannelTypeText *iface,
+ guint type,
+ const gchar *text,
+ DBusGMethodInvocation *context)
+{
+ /* silently swallow the message */
+ tp_svc_channel_type_text_return_from_send (context);
+}
+
+static void
+text_iface_init (gpointer iface,
+ gpointer data)
+{
+ TpSvcChannelTypeTextClass *klass = iface;
+
+ tp_text_mixin_iface_init (iface, data);
+#define IMPLEMENT(x) tp_svc_channel_type_text_implement_##x (klass, text_##x)
+ IMPLEMENT (send);
+#undef IMPLEMENT
+}
+
+GHashTable *
+tp_tests_text_channel_get_props (TpTestsTextChannelNull *self)
+{
+ GHashTable *props;
+ TpHandleType handle_type;
+ TpHandle handle;
+ gchar *target_id;
+ gboolean requested;
+ TpHandle initiator_handle;
+ gchar *initiator_id;
+ GStrv interfaces;
+
+ g_object_get (self,
+ "handle-type", &handle_type,
+ "handle", &handle,
+ "target-id", &target_id,
+ "requested", &requested,
+ "initiator-handle", &initiator_handle,
+ "initiator-id", &initiator_id,
+ "interfaces", &interfaces,
+ NULL);
+
+ props = tp_asv_new (
+ TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, TP_IFACE_CHANNEL_TYPE_TEXT,
+ TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, handle_type,
+ TP_PROP_CHANNEL_TARGET_HANDLE, G_TYPE_UINT, handle,
+ TP_PROP_CHANNEL_TARGET_ID, G_TYPE_STRING, target_id,
+ TP_PROP_CHANNEL_REQUESTED, G_TYPE_BOOLEAN, requested,
+ TP_PROP_CHANNEL_INITIATOR_HANDLE, G_TYPE_UINT, initiator_handle,
+ TP_PROP_CHANNEL_INITIATOR_ID, G_TYPE_STRING, initiator_id,
+ TP_PROP_CHANNEL_INTERFACES, G_TYPE_STRV, interfaces,
+ NULL);
+
+ g_free (target_id);
+ g_free (initiator_id);
+ g_strfreev (interfaces);
+ return props;
+}
diff --git a/tests/lib/textchan-null.h b/tests/lib/textchan-null.h
new file mode 100644
index 0000000..583bec5
--- /dev/null
+++ b/tests/lib/textchan-null.h
@@ -0,0 +1,137 @@
+/*
+ * /dev/null as a text channel
+ *
+ * Copyright (C) 2008 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright (C) 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.
+ */
+
+#ifndef __TP_TESTS_TEXT_CHANNEL_NULL_H__
+#define __TP_TESTS_TEXT_CHANNEL_NULL_H__
+
+#include <glib-object.h>
+#include <telepathy-glib/base-connection.h>
+#include <telepathy-glib/text-mixin.h>
+#include <telepathy-glib/group-mixin.h>
+
+G_BEGIN_DECLS
+
+typedef struct _TpTestsTextChannelNull TpTestsTextChannelNull;
+typedef struct _TpTestsTextChannelNullClass TpTestsTextChannelNullClass;
+typedef struct _TpTestsTextChannelNullPrivate TpTestsTextChannelNullPrivate;
+
+GType tp_tests_text_channel_null_get_type (void);
+
+#define TP_TESTS_TYPE_TEXT_CHANNEL_NULL \
+ (tp_tests_text_channel_null_get_type ())
+#define TP_TESTS_TEXT_CHANNEL_NULL(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), TP_TESTS_TYPE_TEXT_CHANNEL_NULL, \
+ TpTestsTextChannelNull))
+#define TP_TESTS_TEXT_CHANNEL_NULL_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), TP_TESTS_TYPE_TEXT_CHANNEL_NULL, \
+ TpTestsTextChannelNullClass))
+#define TP_TESTS_IS_TEXT_CHANNEL_NULL(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TP_TESTS_TYPE_TEXT_CHANNEL_NULL))
+#define TP_TESTS_IS_TEXT_CHANNEL_NULL_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), TP_TESTS_TYPE_TEXT_CHANNEL_NULL))
+#define TP_TESTS_TEXT_CHANNEL_NULL_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_TEXT_CHANNEL_NULL, \
+ TpTestsTextChannelNullClass))
+
+struct _TpTestsTextChannelNullClass {
+ GObjectClass parent_class;
+
+ TpTextMixinClass text_class;
+};
+
+struct _TpTestsTextChannelNull {
+ GObject parent;
+ TpTextMixin text;
+
+ guint get_handle_called;
+ guint get_interfaces_called;
+ guint get_channel_type_called;
+
+ TpTestsTextChannelNullPrivate *priv;
+};
+
+/* Subclass with D-Bus properties */
+
+typedef struct _TestPropsTextChannel TpTestsPropsTextChannel;
+typedef struct _TestPropsTextChannelClass TpTestsPropsTextChannelClass;
+
+struct _TestPropsTextChannel {
+ TpTestsTextChannelNull parent;
+
+ GHashTable *dbus_property_interfaces_retrieved;
+};
+
+struct _TestPropsTextChannelClass {
+ TpTestsTextChannelNullClass parent;
+
+ TpDBusPropertiesMixinClass dbus_properties_class;
+};
+
+GType tp_tests_props_text_channel_get_type (void);
+
+#define TP_TESTS_TYPE_PROPS_TEXT_CHANNEL \
+ (tp_tests_props_text_channel_get_type ())
+#define TP_TESTS_PROPS_TEXT_CHANNEL(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), TP_TESTS_TYPE_PROPS_TEXT_CHANNEL, \
+ TpTestsPropsTextChannel))
+#define TP_TESTS_PROPS_TEXT_CHANNEL_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), TP_TESTS_TYPE_PROPS_TEXT_CHANNEL, \
+ TpTestsPropsTextChannelClass))
+#define TP_TESTS_IS_PROPS_TEXT_CHANNEL(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TP_TESTS_TYPE_PROPS_TEXT_CHANNEL))
+#define TP_TESTS_IS_PROPS_TEXT_CHANNEL_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), TP_TESTS_TYPE_PROPS_TEXT_CHANNEL))
+#define TP_TESTS_PROPS_TEXT_CHANNEL_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_PROPS_TEXT_CHANNEL, \
+ TpTestsPropsTextChannelClass))
+
+/* Subclass with D-Bus properties and Group */
+
+typedef struct _TestPropsGroupTextChannel TpTestsPropsGroupTextChannel;
+typedef struct _TestPropsGroupTextChannelClass TpTestsPropsGroupTextChannelClass;
+
+struct _TestPropsGroupTextChannel {
+ TpTestsPropsTextChannel parent;
+
+ TpGroupMixin group;
+};
+
+struct _TestPropsGroupTextChannelClass {
+ TpTestsPropsTextChannelClass parent;
+
+ TpGroupMixinClass group_class;
+};
+
+GType tp_tests_props_group_text_channel_get_type (void);
+
+#define TP_TESTS_TYPE_PROPS_GROUP_TEXT_CHANNEL \
+ (tp_tests_props_group_text_channel_get_type ())
+#define TP_TESTS_PROPS_GROUP_TEXT_CHANNEL(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), TP_TESTS_TYPE_PROPS_GROUP_TEXT_CHANNEL, \
+ TpTestsPropsGroupTextChannel))
+#define TP_TESTS_PROPS_GROUP_TEXT_CHANNEL_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), TP_TESTS_TYPE_PROPS_GROUP_TEXT_CHANNEL, \
+ TpTestsPropsGroupTextChannelClass))
+#define TP_TESTS_IS_PROPS_GROUP_TEXT_CHANNEL(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TP_TESTS_TYPE_PROPS_GROUP_TEXT_CHANNEL))
+#define TP_TESTS_IS_PROPS_GROUP_TEXT_CHANNEL_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), TP_TESTS_TYPE_PROPS_GROUP_TEXT_CHANNEL))
+#define TP_TESTS_PROPS_GROUP_TEXT_CHANNEL_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_PROPS_GROUP_TEXT_CHANNEL, \
+ TpTestsPropsGroupTextChannelClass))
+
+void tp_tests_text_channel_null_close (TpTestsTextChannelNull *self);
+
+GHashTable * tp_tests_text_channel_get_props (TpTestsTextChannelNull *self);
+
+G_END_DECLS
+
+#endif /* #ifndef __TP_TESTS_TEXT_CHANNEL_NULL_H__ */
diff --git a/tests/lib/util.c b/tests/lib/util.c
new file mode 100644
index 0000000..f5f3d66
--- /dev/null
+++ b/tests/lib/util.c
@@ -0,0 +1,291 @@
+/* Simple utility code used by the regression tests.
+ *
+ * Copyright © 2008-2010 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright © 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 "util.h"
+
+#ifdef G_OS_UNIX
+# include <unistd.h> /* for alarm() */
+#endif
+
+void
+tp_tests_proxy_run_until_prepared (gpointer proxy,
+ const GQuark *features)
+{
+ GError *error = NULL;
+
+ tp_tests_proxy_run_until_prepared_or_failed (proxy, features, &error);
+ g_assert_no_error (error);
+}
+
+/* A GAsyncReadyCallback whose user_data is a GAsyncResult **. It writes a
+ * reference to the result into that pointer. */
+void
+tp_tests_result_ready_cb (GObject *object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GAsyncResult **result = user_data;
+
+ *result = g_object_ref (res);
+}
+
+/* Run until *result contains a result. Intended to be used with a pending
+ * async call that uses tp_tests_result_ready_cb. */
+void
+tp_tests_run_until_result (GAsyncResult **result)
+{
+ /* not synchronous */
+ g_assert (*result == NULL);
+
+ while (*result == NULL)
+ g_main_context_iteration (NULL, TRUE);
+}
+
+gboolean
+tp_tests_proxy_run_until_prepared_or_failed (gpointer proxy,
+ const GQuark *features,
+ GError **error)
+{
+ GAsyncResult *result = NULL;
+ gboolean r;
+
+ tp_proxy_prepare_async (proxy, features, tp_tests_result_ready_cb, &result);
+
+ tp_tests_run_until_result (&result);
+
+ r = tp_proxy_prepare_finish (proxy, result, error);
+ g_object_unref (result);
+ return r;
+}
+
+TpDBusDaemon *
+tp_tests_dbus_daemon_dup_or_die (void)
+{
+ TpDBusDaemon *d = tp_dbus_daemon_dup (NULL);
+
+ /* In a shared library, this would be very bad (see fd.o #18832), but in a
+ * regression test that's going to be run under a temporary session bus,
+ * it's just what we want. */
+ if (d == NULL)
+ {
+ g_error ("Unable to connect to session bus");
+ }
+
+ return d;
+}
+
+static void
+introspect_cb (TpProxy *proxy G_GNUC_UNUSED,
+ const gchar *xml G_GNUC_UNUSED,
+ const GError *error G_GNUC_UNUSED,
+ gpointer user_data,
+ GObject *weak_object G_GNUC_UNUSED)
+{
+ g_main_loop_quit (user_data);
+}
+
+void
+tp_tests_proxy_run_until_dbus_queue_processed (gpointer proxy)
+{
+ GMainLoop *loop = g_main_loop_new (NULL, FALSE);
+
+ tp_cli_dbus_introspectable_call_introspect (proxy, -1, introspect_cb,
+ loop, NULL, NULL);
+ g_main_loop_run (loop);
+ g_main_loop_unref (loop);
+}
+
+typedef struct {
+ GMainLoop *loop;
+ TpHandle handle;
+} HandleRequestResult;
+
+static void
+handles_requested_cb (TpConnection *connection G_GNUC_UNUSED,
+ TpHandleType handle_type G_GNUC_UNUSED,
+ guint n_handles,
+ const TpHandle *handles,
+ const gchar * const *ids G_GNUC_UNUSED,
+ const GError *error,
+ gpointer user_data,
+ GObject *weak_object G_GNUC_UNUSED)
+{
+ HandleRequestResult *result = user_data;
+
+ g_assert_no_error ((GError *) error);
+ g_assert_cmpuint (n_handles, ==, 1);
+ result->handle = handles[0];
+}
+
+static void
+handle_request_result_finish (gpointer r)
+{
+ HandleRequestResult *result = r;
+
+ g_main_loop_quit (result->loop);
+}
+
+TpHandle
+tp_tests_connection_run_request_contact_handle (TpConnection *connection,
+ const gchar *id)
+{
+ HandleRequestResult result = { g_main_loop_new (NULL, FALSE), 0 };
+ const gchar * const ids[] = { id, NULL };
+
+ tp_connection_request_handles (connection, -1, TP_HANDLE_TYPE_CONTACT, ids,
+ handles_requested_cb, &result, handle_request_result_finish, NULL);
+ g_main_loop_run (result.loop);
+ g_main_loop_unref (result.loop);
+ return result.handle;
+}
+
+void
+_test_assert_empty_strv (const char *file,
+ int line,
+ gconstpointer strv)
+{
+ const gchar * const *strings = strv;
+
+ if (strv != NULL && strings[0] != NULL)
+ {
+ guint i;
+
+ g_message ("%s:%d: expected empty strv, but got:", file, line);
+
+ for (i = 0; strings[i] != NULL; i++)
+ {
+ g_message ("* \"%s\"", strings[i]);
+ }
+
+ g_error ("%s:%d: strv wasn't empty (see above for contents",
+ file, line);
+ }
+}
+
+void
+_tp_tests_assert_strv_equals (const char *file,
+ int line,
+ const char *expected_desc,
+ gconstpointer expected_strv,
+ const char *actual_desc,
+ gconstpointer actual_strv)
+{
+ const gchar * const *expected = expected_strv;
+ const gchar * const *actual = actual_strv;
+ guint i;
+
+ g_assert (expected != NULL);
+ g_assert (actual != NULL);
+
+ for (i = 0; expected[i] != NULL || actual[i] != NULL; i++)
+ {
+ if (expected[i] == NULL)
+ {
+ g_error ("%s:%d: assertion failed: (%s)[%u] == (%s)[%u]: "
+ "NULL == %s", file, line, expected_desc, i,
+ actual_desc, i, actual[i]);
+ }
+ else if (actual[i] == NULL)
+ {
+ g_error ("%s:%d: assertion failed: (%s)[%u] == (%s)[%u]: "
+ "%s == NULL", file, line, expected_desc, i,
+ actual_desc, i, expected[i]);
+ }
+ else if (tp_strdiff (expected[i], actual[i]))
+ {
+ g_error ("%s:%d: assertion failed: (%s)[%u] == (%s)[%u]: "
+ "%s == %s", file, line, expected_desc, i,
+ actual_desc, i, expected[i], actual[i]);
+ }
+ }
+}
+
+void
+tp_tests_create_and_connect_conn (GType conn_type,
+ const gchar *account,
+ TpBaseConnection **service_conn,
+ TpConnection **client_conn)
+{
+ TpDBusDaemon *dbus;
+ gchar *name;
+ gchar *conn_path;
+ GError *error = NULL;
+ GQuark conn_features[] = { TP_CONNECTION_FEATURE_CONNECTED, 0 };
+
+ g_assert (service_conn != NULL);
+ g_assert (client_conn != NULL);
+
+ dbus = tp_tests_dbus_daemon_dup_or_die ();
+
+ *service_conn = tp_tests_object_new_static_class (
+ conn_type,
+ "account", account,
+ "protocol", "simple",
+ NULL);
+ g_assert (*service_conn != NULL);
+
+ g_assert (tp_base_connection_register (*service_conn, "simple",
+ &name, &conn_path, &error));
+ g_assert_no_error (error);
+
+ *client_conn = tp_connection_new (dbus, name, conn_path,
+ &error);
+ g_assert (*client_conn != NULL);
+ g_assert_no_error (error);
+
+ tp_cli_connection_call_connect (*client_conn, -1, NULL, NULL, NULL, NULL);
+ tp_tests_proxy_run_until_prepared (*client_conn, conn_features);
+
+ g_free (name);
+ g_free (conn_path);
+
+ g_object_unref (dbus);
+}
+
+/* This object exists solely so that tests/tests.supp can ignore "leaked"
+ * classes. */
+gpointer
+tp_tests_object_new_static_class (GType type,
+ ...)
+{
+ va_list ap;
+ GObject *object;
+ const gchar *first_property;
+
+ va_start (ap, type);
+ first_property = va_arg (ap, const gchar *);
+ object = g_object_new_valist (type, first_property, ap);
+ va_end (ap);
+ return object;
+}
+
+static gboolean
+time_out (gpointer nil G_GNUC_UNUSED)
+{
+ g_error ("Timed out");
+ g_assert_not_reached ();
+ return FALSE;
+}
+
+void
+tp_tests_abort_after (guint sec)
+{
+ if (g_getenv ("TP_TESTS_NO_TIMEOUT") != NULL)
+ return;
+
+ g_timeout_add_seconds (sec, time_out, NULL);
+
+#ifdef G_OS_UNIX
+ /* On Unix, we can kill the process more reliably; this is a safety-catch
+ * in case it deadlocks or something, in which case the main loop won't be
+ * processed. The default handler for SIGALRM is process termination. */
+ alarm (sec + 2);
+#endif
+}
diff --git a/tests/lib/util.h b/tests/lib/util.h
new file mode 100644
index 0000000..7eab77d
--- /dev/null
+++ b/tests/lib/util.h
@@ -0,0 +1,57 @@
+/* Simple utility code used by the regression tests.
+ *
+ * Copyright © 2008-2010 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright © 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.
+ */
+
+#ifndef __TP_TESTS_LIB_UTIL_H__
+#define __TP_TESTS_LIB_UTIL_H__
+
+#include <telepathy-glib/telepathy-glib.h>
+#include <telepathy-glib/base-connection.h>
+
+TpDBusDaemon *tp_tests_dbus_daemon_dup_or_die (void);
+
+void tp_tests_proxy_run_until_dbus_queue_processed (gpointer proxy);
+
+TpHandle tp_tests_connection_run_request_contact_handle (
+ TpConnection *connection,
+ const gchar *id);
+
+void tp_tests_proxy_run_until_prepared (gpointer proxy,
+ const GQuark *features);
+gboolean tp_tests_proxy_run_until_prepared_or_failed (gpointer proxy,
+ const GQuark *features,
+ GError **error);
+
+#define test_assert_empty_strv(strv) \
+ _test_assert_empty_strv (__FILE__, __LINE__, strv)
+void _test_assert_empty_strv (const char *file, int line, gconstpointer strv);
+
+#define tp_tests_assert_strv_equals(actual, expected) \
+ _tp_tests_assert_strv_equals (__FILE__, __LINE__, \
+ #actual, actual, \
+ #expected, expected)
+void _tp_tests_assert_strv_equals (const char *file, int line,
+ const char *actual_desc, gconstpointer actual_strv,
+ const char *expected_desc, gconstpointer expected_strv);
+
+void tp_tests_create_and_connect_conn (GType conn_type,
+ const gchar *account,
+ TpBaseConnection **service_conn,
+ TpConnection **client_conn);
+
+gpointer tp_tests_object_new_static_class (GType type,
+ ...) G_GNUC_NULL_TERMINATED;
+
+void tp_tests_run_until_result (GAsyncResult **result);
+void tp_tests_result_ready_cb (GObject *object,
+ GAsyncResult *res, gpointer user_data);
+
+void tp_tests_abort_after (guint sec);
+
+#endif /* #ifndef __TP_TESTS_LIB_UTIL_H__ */
diff --git a/tests/suppressions/tpl.supp b/tests/suppressions/tpl.supp
index c92f72a..15925d8 100644
--- a/tests/suppressions/tpl.supp
+++ b/tests/suppressions/tpl.supp
@@ -4,13 +4,13 @@
# ============================= selinux ==================================
{
- selinux getdelim
- Memcheck:Leak
- fun:malloc
- fun:getdelim
- obj:/lib/libselinux.so.1
- obj:/lib/libselinux.so.1
- obj:/lib/libselinux.so.1
+ selinux getdelim
+ Memcheck:Leak
+ fun:malloc
+ fun:getdelim
+ obj:/lib/libselinux.so.1
+ obj:/lib/libselinux.so.1
+ obj:/lib/libselinux.so.1
}
@@ -147,10 +147,17 @@
}
{
- g_type_create_instance
- Memcheck:Leak
- ...
- fun:g_type_create_instance
+ g_type_create_instance
+ Memcheck:Leak
+ ...
+ fun:g_type_create_instance
+}
+
+{
+ g_type_add_interface_static
+ Memcheck:Leak
+ ...
+ fun:g_type_add_interface_static
}
# ============================= dbus-glib =============================
@@ -242,6 +249,23 @@
fun:tp_dbus_daemon_constructor
}
+{
+ Leak in tp-glib 0.11.16 (Fedora 14)
+ Memcheck:Leak
+ ...
+ fun:g_simple_async_result_new
+ fun:tp_proxy_prepare_async
+}
+
+# ============================= tp-logger-tests ==========================
+
+{
+ tp_tests_object_new_static_class
+ Memcheck:Leak
+ ...
+ fun:tp_tests_object_new_static_class
+}
+
# ============================= unclassified ==========================
{
diff --git a/tests/test-entity.c b/tests/test-entity.c
index 93cb5c8..5877a5d 100644
--- a/tests/test-entity.c
+++ b/tests/test-entity.c
@@ -3,6 +3,9 @@
#include <telepathy-logger/entity.h>
#include <telepathy-logger/entity-internal.h>
+#include "lib/util.h"
+#include "lib/contacts-conn.h"
+
static void
test_entity_instantiation (void)
{
@@ -38,12 +41,109 @@ test_entity_instantiation_from_room_id (void)
g_object_unref (entity);
}
+
+typedef struct {
+ TpContact *contacts[2];
+ GMainLoop *loop;
+} Result;
+
+
+static void
+get_contacts_cb (TpConnection *connection,
+ guint n_contacts,
+ TpContact * const *contacts,
+ guint n_failed,
+ const TpHandle *failed,
+ const GError *error,
+ gpointer user_data,
+ GObject *weak_object)
+{
+ Result *result = user_data;
+
+ g_assert_no_error (error);
+ g_assert (n_contacts == 2);
+ g_assert (n_failed == 0);
+
+ result->contacts[0] = g_object_ref (contacts[0]);
+ result->contacts[1] = g_object_ref (contacts[1]);
+
+ g_main_loop_quit (result->loop);
+}
+
+
static void
test_entity_instantiation_from_tp_contact (void)
{
- /* TODO figure-out how to obtain a TpContact to test
- * _tpl_entity_new_from_tp_contact() */
- g_printf ("- TODO - ");
+ TpBaseConnection *base_connection;
+ TpConnection *client_connection;
+ TpTestsContactsConnection *connection;
+ TpHandleRepoIface *repo;
+ TpHandle handles[2];
+ const char *alias[] = {"Alice in Wonderland", "Bob the builder"};
+ const char *avatar_tokens[] = {"alice-token", NULL};
+ TpContactFeature features[] =
+ { TP_CONTACT_FEATURE_ALIAS, TP_CONTACT_FEATURE_AVATAR_TOKEN };
+ Result result;
+ TplEntity *entity;
+
+ tp_tests_create_and_connect_conn (TP_TESTS_TYPE_CONTACTS_CONNECTION,
+ "me@test.com", &base_connection, &client_connection);
+
+ connection = TP_TESTS_CONTACTS_CONNECTION (base_connection);
+
+ repo = tp_base_connection_get_handles (base_connection,
+ TP_HANDLE_TYPE_CONTACT);
+
+ handles[0] = tp_handle_ensure (repo, "alice", NULL, NULL);
+ g_assert (handles[0] != 0);
+
+ handles[1] = tp_handle_ensure (repo, "bob", NULL, NULL);
+ g_assert (handles[1] != 0);
+
+ tp_tests_contacts_connection_change_aliases (connection, 2, handles,
+ alias);
+ tp_tests_contacts_connection_change_avatar_tokens (connection, 2, handles,
+ avatar_tokens);
+
+ result.contacts[0] = result.contacts[1] = 0;
+ result.loop = g_main_loop_new (NULL, FALSE);
+
+ tp_connection_get_contacts_by_handle (client_connection,
+ 2, handles,
+ 2, features,
+ get_contacts_cb, &result,
+ NULL, NULL);
+ g_main_loop_run (result.loop);
+
+ entity = _tpl_entity_new_from_tp_contact (result.contacts[0],
+ TPL_ENTITY_SELF);
+
+ g_assert_cmpstr (tpl_entity_get_identifier (entity), ==, "alice");
+ g_assert (tpl_entity_get_entity_type (entity) == TPL_ENTITY_SELF);
+ g_assert_cmpstr (tpl_entity_get_alias (entity), ==, alias[0]);
+ g_assert_cmpstr (tpl_entity_get_avatar_token (entity), ==, avatar_tokens[0]);
+ g_object_unref (entity);
+
+ entity = _tpl_entity_new_from_tp_contact (result.contacts[1],
+ TPL_ENTITY_CONTACT);
+
+ g_assert_cmpstr (tpl_entity_get_identifier (entity), ==, "bob");
+ g_assert (tpl_entity_get_entity_type (entity) == TPL_ENTITY_CONTACT);
+ g_assert_cmpstr (tpl_entity_get_alias (entity), ==, alias[1]);
+ g_assert (tpl_entity_get_avatar_token (entity) == NULL);
+ g_object_unref (entity);
+
+ g_object_unref (result.contacts[0]);
+ g_object_unref (result.contacts[1]);
+ g_main_loop_unref (result.loop);
+
+ tp_base_connection_change_status (base_connection,
+ TP_CONNECTION_STATUS_DISCONNECTED,
+ TP_CONNECTION_STATUS_REASON_REQUESTED);
+ tp_base_connection_finish_shutdown (base_connection);
+
+ g_object_unref (base_connection);
+ g_object_unref (client_connection);
}
int main (int argc,