summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmilio Pozuelo Monfort <emilio.pozuelo@collabora.co.uk>2011-05-17 16:50:32 +0100
committerEmilio Pozuelo Monfort <emilio.pozuelo@collabora.co.uk>2011-05-17 16:50:32 +0100
commit58b17e55e3d941aad673d4402141a5c5aebfb1b4 (patch)
tree5ae845e464b3a5534e62860ce333d8e3447c17a5
parentc2f9bae72b15b82cdb8bad0f20bc12c09d93b6e4 (diff)
parentbbe027c08ce35a2c222660f9624dac78978230f3 (diff)
Merge remote-tracking branch 'danni/balance-feature-36334' into balance-feature-36334
Conflicts: telepathy-glib/connection-internal.h
-rw-r--r--docs/reference/telepathy-glib-sections.txt4
-rw-r--r--telepathy-glib/connection-internal.h5
-rw-r--r--telepathy-glib/connection.c307
-rw-r--r--telepathy-glib/connection.h8
-rw-r--r--tests/dbus/Makefile.am3
-rw-r--r--tests/dbus/connection-balance.c386
6 files changed, 713 insertions, 0 deletions
diff --git a/docs/reference/telepathy-glib-sections.txt b/docs/reference/telepathy-glib-sections.txt
index 0e72f6ac..4b31ee9e 100644
--- a/docs/reference/telepathy-glib-sections.txt
+++ b/docs/reference/telepathy-glib-sections.txt
@@ -3452,6 +3452,7 @@ TP_CONNECTION_FEATURE_CONNECTED
TP_CONNECTION_FEATURE_CAPABILITIES
TP_CONNECTION_FEATURE_AVATAR_REQUIREMENTS
TP_CONNECTION_FEATURE_CONTACT_INFO
+TP_CONNECTION_FEATURE_BALANCE
tp_connection_run_until_ready
TpConnectionWhenReadyCb
tp_connection_call_when_ready
@@ -3484,6 +3485,8 @@ tp_connection_get_detailed_error
tp_connection_add_client_interest
tp_connection_add_client_interest_by_id
tp_connection_bind_connection_status_to_property
+tp_connection_get_balance
+tp_connection_get_balance_uri
<SUBSECTION Standard>
tp_errors_disconnected_quark
tp_connection_get_type
@@ -3504,6 +3507,7 @@ tp_connection_get_feature_quark_connected
tp_connection_get_feature_quark_capabilities
tp_connection_get_feature_quark_avatar_requirements
tp_connection_get_feature_quark_contact_info
+tp_connection_get_feature_quark_balance
<SUBSECTION avatar-requirements>
TP_TYPE_AVATAR_REQUIREMENTS
TpAvatarRequirements
diff --git a/telepathy-glib/connection-internal.h b/telepathy-glib/connection-internal.h
index 92dddfa4..51773416 100644
--- a/telepathy-glib/connection-internal.h
+++ b/telepathy-glib/connection-internal.h
@@ -65,6 +65,11 @@ struct _TpConnectionPrivate {
TpContactInfoFlags contact_info_flags;
GList *contact_info_supported_fields;
+ gint balance;
+ guint balance_scale;
+ gchar *balance_currency;
+ gchar *balance_uri;
+
TpProxyPendingCall *introspection_call;
unsigned ready:1;
diff --git a/telepathy-glib/connection.c b/telepathy-glib/connection.c
index faf243d5..144e8812 100644
--- a/telepathy-glib/connection.c
+++ b/telepathy-glib/connection.c
@@ -173,6 +173,30 @@ tp_connection_get_feature_quark_capabilities (void)
}
/**
+ * TP_CONNECTION_FEATURE_BALANCE:
+ *
+ * Expands to a call to a function that returns a #GQuark representing the
+ * "balance" feature.
+ *
+ * When this feature is prepared, the Balance.AccountBalance and
+ * Balance.ManageCreditURI properties of the Connection have been retrieved.
+ * In particular, the %TpConnection:balance, %TpConnection:balance-scale,
+ * %TpConnection:balance-currency and %TpConnection:balance-uri properties
+ * have been set.
+ *
+ * One can ask for a feature to be prepared using the
+ * tp_proxy_prepare_async() function, and waiting for it to callback.
+ *
+ * Since: UNRELEASED
+ */
+
+GQuark
+tp_connection_get_feature_quark_balance (void)
+{
+ return g_quark_from_static_string ("tp-connection-feature-balance");
+}
+
+/**
* TP_ERRORS_DISCONNECTED:
*
* #GError domain representing a Telepathy connection becoming disconnected.
@@ -242,6 +266,10 @@ enum
PROP_SELF_CONTACT,
PROP_SELF_HANDLE,
PROP_CAPABILITIES,
+ PROP_BALANCE,
+ PROP_BALANCE_SCALE,
+ PROP_BALANCE_CURRENCY,
+ PROP_BALANCE_URI,
N_PROPS
};
@@ -283,6 +311,18 @@ tp_connection_get_property (GObject *object,
case PROP_CAPABILITIES:
g_value_set_object (value, self->priv->capabilities);
break;
+ case PROP_BALANCE:
+ g_value_set_int (value, self->priv->balance);
+ break;
+ case PROP_BALANCE_SCALE:
+ g_value_set_uint (value, self->priv->balance_scale);
+ break;
+ case PROP_BALANCE_CURRENCY:
+ g_value_set_string (value, self->priv->balance_currency);
+ break;
+ case PROP_BALANCE_URI:
+ g_value_set_string (value, self->priv->balance_uri);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -290,6 +330,130 @@ tp_connection_get_property (GObject *object,
}
static void
+tp_connection_unpack_balance (TpConnection *self,
+ GValueArray *balance_s)
+{
+ gint balance = 0;
+ guint scale = G_MAXUINT32;
+ const char *currency = "";
+
+ if (balance_s == NULL)
+ goto finally;
+
+ tp_value_array_unpack (balance_s, 3,
+ &balance, &scale, &currency);
+
+finally:
+
+ g_object_freeze_notify ((GObject *) self);
+
+ if (self->priv->balance != balance)
+ {
+ self->priv->balance = balance;
+ g_object_notify ((GObject *) self, "balance");
+ }
+
+ if (self->priv->balance_scale != scale)
+ {
+ self->priv->balance_scale = scale;
+ g_object_notify ((GObject *) self, "balance-scale");
+ }
+
+ if (tp_strdiff (self->priv->balance_currency, currency))
+ {
+ g_free (self->priv->balance_currency);
+ self->priv->balance_currency = g_strdup (currency);
+ g_object_notify ((GObject *) self, "balance-currency");
+ }
+
+ g_object_thaw_notify ((GObject *) self);
+}
+
+static void
+tp_connection_get_balance_cb (TpProxy *proxy,
+ GHashTable *props,
+ const GError *in_error,
+ gpointer user_data,
+ GObject *weak_obj)
+{
+ TpConnection *self = (TpConnection *) proxy;
+ GValueArray *balance = NULL;
+
+ self->priv->fetching_balance = FALSE;
+
+ if (in_error != NULL)
+ {
+ DEBUG ("Failed to get Balance properties: %s", in_error->message);
+
+ goto finally;
+ }
+
+ balance =
+ tp_asv_get_boxed (props, "AccountBalance", TP_STRUCT_TYPE_CURRENCY_AMOUNT);
+ self->priv->balance_uri =
+ g_strdup (tp_asv_get_string (props, "ManageCreditURI"));
+
+finally:
+ g_object_freeze_notify ((GObject *) self);
+
+ tp_connection_unpack_balance (self, balance);
+
+ _tp_proxy_set_feature_prepared (proxy, TP_CONNECTION_FEATURE_BALANCE,
+ TRUE);
+
+ g_object_notify ((GObject *) self, "balance-uri");
+
+ g_object_thaw_notify ((GObject *) self);
+}
+
+static void
+tp_connection_balance_changed_cb (TpConnection *self,
+ const GValueArray *balance,
+ gpointer user_data,
+ GObject *weak_obj)
+{
+ tp_connection_unpack_balance (self, (GValueArray *) balance);
+}
+
+static void
+tp_connection_maybe_prepare_balance (TpProxy *proxy)
+{
+ TpConnection *self = (TpConnection *) proxy;
+
+ if (self->priv->balance_currency != NULL)
+ return; /* already done */
+
+ if (!_tp_proxy_is_preparing (proxy, TP_CONNECTION_FEATURE_BALANCE))
+ return; /* not interested right now */
+
+ if (!self->priv->ready)
+ return; /* will try again when ready */
+
+ if (self->priv->fetching_balance)
+ return; /* Another Get operation is running */
+
+ if (!tp_proxy_has_interface_by_id (proxy,
+ TP_IFACE_QUARK_CONNECTION_INTERFACE_BALANCE))
+ {
+ /* Connection doesn't support Balance */
+
+ _tp_proxy_set_feature_prepared (proxy, TP_CONNECTION_FEATURE_BALANCE,
+ TRUE);
+ return;
+ }
+
+ self->priv->fetching_balance = TRUE;
+
+ tp_cli_dbus_properties_call_get_all (self, -1,
+ TP_IFACE_CONNECTION_INTERFACE_BALANCE,
+ tp_connection_get_balance_cb, NULL, NULL, NULL);
+
+ tp_cli_connection_interface_balance_connect_to_balance_changed (self,
+ tp_connection_balance_changed_cb,
+ NULL, NULL, NULL, NULL);
+}
+
+static void
tp_connection_get_rcc_cb (TpProxy *proxy,
const GValue *value,
const GError *error,
@@ -1198,6 +1362,9 @@ tp_connection_finalize (GObject *object)
tp_contact_info_spec_list_free (self->priv->contact_info_supported_fields);
self->priv->contact_info_supported_fields = NULL;
+ tp_clear_pointer (&self->priv->balance_currency, g_free);
+ tp_clear_pointer (&self->priv->balance_uri, g_free);
+
((GObjectClass *) tp_connection_parent_class)->finalize (object);
}
@@ -1267,6 +1434,7 @@ enum {
FEAT_CAPABILITIES,
FEAT_AVATAR_REQUIREMENTS,
FEAT_CONTACT_INFO,
+ FEAT_BALANCE,
N_FEAT
};
@@ -1304,6 +1472,9 @@ tp_connection_list_features (TpProxyClass *cls G_GNUC_UNUSED)
need_contact_info[0] = TP_IFACE_QUARK_CONNECTION_INTERFACE_CONTACT_INFO;
features[FEAT_CONTACT_INFO].interfaces_needed = need_contact_info;
+ features[FEAT_BALANCE].name = TP_CONNECTION_FEATURE_BALANCE;
+ features[FEAT_BALANCE].start_preparing = tp_connection_maybe_prepare_balance;
+
/* assert that the terminator at the end is there */
g_assert (features[N_FEAT].name == 0);
@@ -1482,6 +1653,72 @@ tp_connection_class_init (TpConnectionClass *klass)
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_CAPABILITIES,
param_spec);
+
+ /**
+ * TpConnection:balance:
+ *
+ * The Amount field of the Balance.AccountBalance property.
+ *
+ * For this property to be valid, you must first call
+ * tp_proxy_prepare_async() with the feature %TP_CONNECTION_FEATURE_BALANCE.
+ *
+ * See Also: tp_connection_get_balance()
+ */
+ param_spec = g_param_spec_int ("balance", "Balance Amount",
+ "The Amount field of the Account Balance",
+ G_MININT32, G_MAXINT32, 0,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_BALANCE,
+ param_spec);
+
+ /**
+ * TpConnection:balance-scale:
+ *
+ * The Scale field of the Balance.AccountBalance property.
+ *
+ * For this property to be valid, you must first call
+ * tp_proxy_prepare_async() with the feature %TP_CONNECTION_FEATURE_BALANCE.
+ *
+ * See Also: tp_connection_get_balance()
+ */
+ param_spec = g_param_spec_uint ("balance-scale", "Balance Scale",
+ "The Scale field of the Account Balance",
+ 0, G_MAXUINT32, G_MAXUINT32,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_BALANCE_SCALE,
+ param_spec);
+
+ /**
+ * TpConnection:balance-currency:
+ *
+ * The Currency field of the Balance.AccountBalance property.
+ *
+ * For this property to be valid, you must first call
+ * tp_proxy_prepare_async() with the feature %TP_CONNECTION_FEATURE_BALANCE.
+ *
+ * See Also: tp_connection_get_balance()
+ */
+ param_spec = g_param_spec_string ("balance-currency", "Balance Currency",
+ "The Currency field of the Account Balance",
+ NULL,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_BALANCE_CURRENCY,
+ param_spec);
+
+ /**
+ * TpConnection:balance-uri:
+ *
+ * The Balance.ManageCreditURI property.
+ *
+ * For this property to be valid, you must first call
+ * tp_proxy_prepare_async() with the feature %TP_CONNECTION_FEATURE_BALANCE.
+ */
+ param_spec = g_param_spec_string ("balance-uri", "Balance URI",
+ "The URI for managing the account balance",
+ NULL,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_BALANCE_URI,
+ param_spec);
}
/**
@@ -2556,3 +2793,73 @@ tp_connection_bind_connection_status_to_property (TpConnection *self,
_tp_bind_connection_status_to_boolean,
NULL, GUINT_TO_POINTER (invert), NULL);
}
+
+/**
+ * tp_connection_get_balance:
+ * @self: a #TpConnection
+ * @balance: (out): a pointer to store the account balance (or %NULL)
+ * @scale: (out): a pointer to store the balance scale (or %NULL)
+ * @currency: (out) (transfer none): a pointer to store the balance
+ * currency (or %NULL)
+ *
+ * If @self has a valid account balance, returns %TRUE and sets the variables
+ * pointed to by @balance, @scale and @currency to the appropriate fields
+ * of the Balance.AccountBalance property.
+ *
+ * The monetary value of the balance is expressed as a fixed-point number,
+ * @balance, with a decimal scale defined by @scale; for instance a @balance
+ * of 1234 with @scale of 2 represents a value of "12.34" in the currency
+ * represented by @currency.
+ *
+ * Requires %TP_CONNECTION_FEATURE_BALANCE to be prepared.
+ *
+ * Returns: %TRUE if the balance is valid (and the values set), %FALSE if the
+ * balance is invalid.
+ * Since: UNRELEASED
+ */
+gboolean
+tp_connection_get_balance (TpConnection *self,
+ gint *balance,
+ guint *scale,
+ const gchar **currency)
+{
+ g_return_val_if_fail (TP_IS_CONNECTION (self), FALSE);
+
+ if (self->priv->balance_currency == NULL)
+ return FALSE;
+
+ if (self->priv->balance == 0 &&
+ self->priv->balance_scale == G_MAXUINT32 &&
+ tp_str_empty (self->priv->balance_currency))
+ return FALSE;
+
+ if (balance != NULL)
+ *balance = self->priv->balance;
+
+ if (scale != NULL)
+ *scale = self->priv->balance_scale;
+
+ if (currency != NULL)
+ *currency = self->priv->balance_currency;
+
+ return TRUE;
+}
+
+/**
+ * tp_connection_get_balance_uri:
+ * @self: a #TpConnection
+ *
+ * The value of Balance.ManageCreditURI.
+ *
+ * Requires %TP_CONNECTION_FEATURE_BALANCE to be prepared.
+ *
+ * Returns: (transfer none): the #TpConnection:balance-uri property.
+ * Since: UNRELEASED
+ */
+const gchar *
+tp_connection_get_balance_uri (TpConnection *self)
+{
+ g_return_val_if_fail (TP_IS_CONNECTION (self), FALSE);
+
+ return self->priv->balance_uri;
+}
diff --git a/telepathy-glib/connection.h b/telepathy-glib/connection.h
index 8e625bfd..38a9b3bc 100644
--- a/telepathy-glib/connection.h
+++ b/telepathy-glib/connection.h
@@ -274,6 +274,14 @@ GQuark tp_connection_get_feature_quark_avatar_requirements (void) G_GNUC_CONST;
TpAvatarRequirements * tp_connection_get_avatar_requirements (
TpConnection *self);
+#define TP_CONNECTION_FEATURE_BALANCE \
+ (tp_connection_get_feature_quark_balance ())
+GQuark tp_connection_get_feature_quark_balance (void) G_GNUC_CONST;
+
+gboolean tp_connection_get_balance (TpConnection *self,
+ gint *balance, guint *scale, const gchar **currency);
+const gchar * tp_connection_get_balance_uri (TpConnection *self);
+
G_END_DECLS
#include <telepathy-glib/_gen/tp-cli-connection.h>
diff --git a/tests/dbus/Makefile.am b/tests/dbus/Makefile.am
index cf0d3e33..670a0b0f 100644
--- a/tests/dbus/Makefile.am
+++ b/tests/dbus/Makefile.am
@@ -17,6 +17,7 @@ noinst_PROGRAMS = \
test-cm \
test-cm-message \
test-connection \
+ test-connection-balance \
test-connection-bug-18845 \
test-connection-error \
test-connection-handles \
@@ -107,6 +108,8 @@ test_contact_lists_LDADD = \
$(LDADD) \
$(top_builddir)/examples/cm/contactlist/libexample-cm-contactlist.la
+test_connection_balance_SOURCES = connection-balance.c
+
test_connection_bug_18845_SOURCES = connection-bug-18845.c
test_connection_handles_SOURCES = connection-handles.c
diff --git a/tests/dbus/connection-balance.c b/tests/dbus/connection-balance.c
new file mode 100644
index 00000000..72634166
--- /dev/null
+++ b/tests/dbus/connection-balance.c
@@ -0,0 +1,386 @@
+/* Feature test for Conn.I.Balance
+ *
+ * Copyright © 2007-2011 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright © 2007-2008 Nokia Corporation
+ *
+ * Copying and distribution of this file, with or without modification,
+ * are permitted in any medium without royalty provided the copyright
+ * notice and this notice are preserved.
+ */
+
+#include <telepathy-glib/connection.h>
+#include <telepathy-glib/dbus.h>
+#include <telepathy-glib/debug.h>
+#include <telepathy-glib/interfaces.h>
+#include <telepathy-glib/proxy-subclass.h>
+
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include "tests/lib/simple-conn.h"
+#include "tests/lib/util.h"
+
+#define BALANCE 1234
+#define BALANCE_SCALE 2
+#define BALANCE_CURRENCY "BDD" /* badger dollars */
+#define MANAGE_CREDIT_URI "http://chat.badger.net/topup"
+
+/* -- BalancedConnection -- */
+typedef TpTestsSimpleConnection BalancedConnection;
+typedef TpTestsSimpleConnectionClass BalancedConnectionClass;
+
+#define TYPE_BALANCED_CONNECTION (balanced_connection_get_type ())
+static GType balanced_connection_get_type (void);
+
+G_DEFINE_TYPE_WITH_CODE (BalancedConnection,
+ balanced_connection,
+ TP_TESTS_TYPE_SIMPLE_CONNECTION,
+
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_BALANCE, NULL))
+
+enum
+{
+ PROP_0,
+ PROP_ACCOUNT_BALANCE,
+ PROP_MANAGE_CREDIT_URI
+};
+
+static void
+balanced_connection_get_property (GObject *self G_GNUC_UNUSED,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id)
+ {
+ case PROP_ACCOUNT_BALANCE:
+ /* known balance */
+ g_value_take_boxed (value, tp_value_array_build (3,
+ G_TYPE_INT, BALANCE,
+ G_TYPE_UINT, BALANCE_SCALE,
+ G_TYPE_STRING, BALANCE_CURRENCY,
+ G_TYPE_INVALID));
+ break;
+
+ case PROP_MANAGE_CREDIT_URI:
+ g_value_set_static_string (value, MANAGE_CREDIT_URI);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+balanced_connection_init (BalancedConnection *self G_GNUC_UNUSED)
+{
+}
+
+static void
+balanced_connection_class_init (BalancedConnectionClass *cls)
+{
+ GObjectClass *object_class = (GObjectClass *) cls;
+ TpBaseConnectionClass *base_class = TP_BASE_CONNECTION_CLASS (cls);
+
+ static TpDBusPropertiesMixinPropImpl balance_props[] = {
+ { "AccountBalance", "account-balance", NULL },
+ { "ManageCreditURI", "manage-credit-uri", NULL },
+ { NULL }
+ };
+
+ static const gchar *interfaces[] = {
+ TP_IFACE_CONNECTION_INTERFACE_BALANCE,
+ NULL
+ };
+
+ object_class->get_property = balanced_connection_get_property;
+
+ base_class->interfaces_always_present = interfaces;
+
+ g_object_class_install_property (object_class, PROP_ACCOUNT_BALANCE,
+ g_param_spec_boxed ("account-balance", "", "",
+ TP_STRUCT_TYPE_CURRENCY_AMOUNT,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (object_class, PROP_MANAGE_CREDIT_URI,
+ g_param_spec_string ("manage-credit-uri", "", "",
+ NULL,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+ tp_dbus_properties_mixin_implement_interface (object_class,
+ TP_IFACE_QUARK_CONNECTION_INTERFACE_BALANCE,
+ tp_dbus_properties_mixin_getter_gobject_properties, NULL,
+ balance_props);
+}
+
+/* -- UnbalancedConnection -- */
+typedef TpTestsSimpleConnection UnbalancedConnection;
+typedef TpTestsSimpleConnectionClass UnbalancedConnectionClass;
+
+#define TYPE_UNBALANCED_CONNECTION (unbalanced_connection_get_type ())
+static GType unbalanced_connection_get_type (void);
+
+G_DEFINE_TYPE (UnbalancedConnection,
+ unbalanced_connection,
+ TYPE_BALANCED_CONNECTION)
+
+static void
+unbalanced_connection_get_property (GObject *self G_GNUC_UNUSED,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id)
+ {
+ case PROP_ACCOUNT_BALANCE:
+ /* unknown balance */
+ g_value_take_boxed (value, tp_value_array_build (3,
+ G_TYPE_INT, 0,
+ G_TYPE_UINT, G_MAXUINT32,
+ G_TYPE_STRING, "",
+ G_TYPE_INVALID));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+unbalanced_connection_init (UnbalancedConnection *self G_GNUC_UNUSED)
+{
+}
+
+static void
+unbalanced_connection_class_init (UnbalancedConnectionClass *cls)
+{
+ GObjectClass *object_class = (GObjectClass *) cls;
+
+ object_class->get_property = unbalanced_connection_get_property;
+
+ g_object_class_override_property (object_class, PROP_ACCOUNT_BALANCE,
+ "account-balance");
+}
+
+/* -- Tests -- */
+typedef struct {
+ TpDBusDaemon *dbus;
+ DBusConnection *client_libdbus;
+ DBusGConnection *client_dbusglib;
+ TpDBusDaemon *client_bus;
+ TpTestsSimpleConnection *service_conn;
+ TpBaseConnection *service_conn_as_base;
+ gchar *conn_name;
+ gchar *conn_path;
+ TpConnection *conn;
+
+ gboolean cwr_ready;
+ GError *cwr_error /* initialized in setup */;
+
+ GAsyncResult *prepare_result;
+} Test;
+
+static void
+connection_prepared_cb (GObject *object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ Test *test = user_data;
+
+ g_message ("%p prepared", object);
+ g_assert (test->prepare_result == NULL);
+ test->prepare_result = g_object_ref (res);
+}
+
+static void
+run_prepare_proxy (Test *test,
+ GQuark *features)
+{
+ GError *error = NULL;
+
+ tp_proxy_prepare_async (test->conn, features, connection_prepared_cb, test);
+ g_assert (test->prepare_result == NULL);
+
+ while (test->prepare_result == NULL)
+ g_main_context_iteration (NULL, TRUE);
+
+ g_assert (tp_proxy_prepare_finish (test->conn, test->prepare_result,
+ &error));
+ g_assert_no_error (error);
+
+ tp_clear_object (&test->prepare_result);
+}
+
+static void
+setup (Test *test,
+ gconstpointer data)
+{
+ GError *error = NULL;
+ GQuark features[] = { TP_CONNECTION_FEATURE_CONNECTED, 0 };
+ GType conn_type = GPOINTER_TO_UINT (data);
+
+ g_type_init ();
+ tp_debug_set_flags ("all");
+ test->dbus = tp_tests_dbus_daemon_dup_or_die ();
+
+ test->client_libdbus = dbus_bus_get_private (DBUS_BUS_STARTER, NULL);
+ g_assert (test->client_libdbus != NULL);
+ dbus_connection_setup_with_g_main (test->client_libdbus, NULL);
+ dbus_connection_set_exit_on_disconnect (test->client_libdbus, FALSE);
+ test->client_dbusglib = dbus_connection_get_g_connection (
+ test->client_libdbus);
+ dbus_g_connection_ref (test->client_dbusglib);
+ test->client_bus = tp_dbus_daemon_new (test->client_dbusglib);
+ g_assert (test->client_bus != NULL);
+
+ test->service_conn = tp_tests_object_new_static_class (
+ conn_type,
+ "account", "me@example.com",
+ "protocol", "simple-protocol",
+ NULL);
+ test->service_conn_as_base = TP_BASE_CONNECTION (test->service_conn);
+ g_assert (test->service_conn != NULL);
+ g_assert (test->service_conn_as_base != NULL);
+
+ g_assert (tp_base_connection_register (test->service_conn_as_base, "simple",
+ &test->conn_name, &test->conn_path, &error));
+ g_assert_no_error (error);
+
+ test->cwr_ready = FALSE;
+ test->cwr_error = NULL;
+
+ test->conn = tp_connection_new (test->client_bus, test->conn_name,
+ test->conn_path, &error);
+ g_assert (test->conn != NULL);
+ g_assert_no_error (error);
+
+ tp_cli_connection_call_connect (test->conn, -1, NULL, NULL, NULL, NULL);
+
+ g_assert (!tp_proxy_is_prepared (test->conn, TP_CONNECTION_FEATURE_CORE));
+ g_assert (!tp_proxy_is_prepared (test->conn,
+ TP_CONNECTION_FEATURE_CONNECTED));
+ g_assert (!tp_proxy_is_prepared (test->conn, TP_CONNECTION_FEATURE_BALANCE));
+
+ run_prepare_proxy (test, features);
+}
+
+static void
+teardown (Test *test,
+ gconstpointer data G_GNUC_UNUSED)
+{
+ TpConnection *conn;
+ gboolean ok;
+ GError *error = NULL;
+
+ tp_clear_object (&test->conn);
+
+ /* disconnect the connection so we don't leak it */
+ conn = tp_connection_new (test->dbus, test->conn_name, test->conn_path,
+ &error);
+ g_assert (conn != NULL);
+ g_assert_no_error (error);
+
+ ok = tp_cli_connection_run_disconnect (conn, -1, &error, NULL);
+ g_assert (ok);
+ g_assert_no_error (error);
+
+ g_assert (!tp_connection_run_until_ready (conn, FALSE, &error, NULL));
+ g_assert_error (error, TP_ERRORS, TP_ERROR_CANCELLED);
+ g_clear_error (&error);
+
+ test->service_conn_as_base = NULL;
+ g_object_unref (test->service_conn);
+ g_free (test->conn_name);
+ g_free (test->conn_path);
+
+ g_object_unref (test->dbus);
+ test->dbus = NULL;
+ g_object_unref (test->client_bus);
+ test->client_bus = NULL;
+
+ dbus_g_connection_unref (test->client_dbusglib);
+ dbus_connection_close (test->client_libdbus);
+ dbus_connection_unref (test->client_libdbus);
+}
+
+static void
+test_balance (Test *test,
+ gconstpointer nil G_GNUC_UNUSED)
+{
+ GQuark features[] = { TP_CONNECTION_FEATURE_BALANCE, 0 };
+ gint balance;
+ guint scale;
+ const gchar *currency, *uri;
+ gchar *currency_alloc, *uri_alloc;
+
+ g_assert (!tp_proxy_is_prepared (test->conn, TP_CONNECTION_FEATURE_BALANCE));
+
+ run_prepare_proxy (test, features);
+
+ g_assert (tp_connection_get_balance (test->conn,
+ &balance, &scale, &currency));
+
+ g_assert_cmpint (balance, ==, BALANCE);
+ g_assert_cmpuint (scale, ==, BALANCE_SCALE);
+ g_assert_cmpstr (currency, ==, BALANCE_CURRENCY);
+
+ uri = tp_connection_get_balance_uri (test->conn);
+
+ g_assert_cmpstr (uri, ==, MANAGE_CREDIT_URI);
+
+ g_object_get (test->conn,
+ "balance", &balance,
+ "balance-scale", &scale,
+ "balance-currency", &currency_alloc,
+ "balance-uri", &uri_alloc,
+ NULL);
+
+ g_assert_cmpint (balance, ==, BALANCE);
+ g_assert_cmpuint (scale, ==, BALANCE_SCALE);
+ g_assert_cmpstr (currency_alloc, ==, BALANCE_CURRENCY);
+ g_assert_cmpstr (uri_alloc, ==, MANAGE_CREDIT_URI);
+
+ g_free (currency_alloc);
+ g_free (uri_alloc);
+}
+
+static void
+test_balance_unknown (Test *test,
+ gconstpointer nil G_GNUC_UNUSED)
+{
+ GQuark features[] = { TP_CONNECTION_FEATURE_BALANCE, 0 };
+ gint balance;
+ guint scale;
+ const gchar *currency;
+
+ g_assert (!tp_proxy_is_prepared (test->conn, TP_CONNECTION_FEATURE_BALANCE));
+
+ run_prepare_proxy (test, features);
+
+ g_assert (!tp_connection_get_balance (test->conn,
+ &balance, &scale, &currency));
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ g_type_init ();
+
+ tp_tests_abort_after (5);
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add ("/conn/balance", Test,
+ GUINT_TO_POINTER (TYPE_BALANCED_CONNECTION),
+ setup, test_balance, teardown);
+ g_test_add ("/conn/balance-unknown", Test,
+ GUINT_TO_POINTER (TYPE_UNBALANCED_CONNECTION),
+ setup, test_balance_unknown, teardown);
+ g_test_add ("/conn/balance-unimplemented", Test,
+ GUINT_TO_POINTER (TP_TESTS_TYPE_SIMPLE_CONNECTION),
+ setup, test_balance_unknown, teardown);
+
+ return g_test_run ();
+}