diff options
author | Guillaume Desmottes <guillaume.desmottes@collabora.co.uk> | 2011-05-30 09:39:16 +0200 |
---|---|---|
committer | Guillaume Desmottes <guillaume.desmottes@collabora.co.uk> | 2011-05-30 09:39:16 +0200 |
commit | 6a34a59d39e7c18c343b19f212b576d7ef2dd8bb (patch) | |
tree | 55a28d90ba7689b1da0630c06bccce00550f8c1e | |
parent | 396d10c4d48f9b36822ec4a34f104473d7e013c7 (diff) | |
parent | 62aac19d9b3b3cf5c56d39cb14c3b98361cb31ea (diff) |
Merge branch 'balance-feature-36334'
-rw-r--r-- | docs/reference/telepathy-glib-sections.txt | 4 | ||||
-rw-r--r-- | telepathy-glib/connection-internal.h | 5 | ||||
-rw-r--r-- | telepathy-glib/connection.c | 340 | ||||
-rw-r--r-- | telepathy-glib/connection.h | 8 | ||||
-rw-r--r-- | telepathy-glib/signals-marshal.list | 1 | ||||
-rw-r--r-- | tests/dbus/Makefile.am | 3 | ||||
-rw-r--r-- | tests/dbus/connection-balance.c | 428 |
7 files changed, 789 insertions, 0 deletions
diff --git a/docs/reference/telepathy-glib-sections.txt b/docs/reference/telepathy-glib-sections.txt index fc49aac6..927e554a 100644 --- a/docs/reference/telepathy-glib-sections.txt +++ b/docs/reference/telepathy-glib-sections.txt @@ -3453,6 +3453,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 @@ -3485,6 +3486,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 @@ -3505,6 +3508,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 d4debb2f..2d3e6369 100644 --- a/telepathy-glib/connection.c +++ b/telepathy-glib/connection.c @@ -43,6 +43,7 @@ #include "telepathy-glib/debug-internal.h" #include "telepathy-glib/proxy-internal.h" #include "telepathy-glib/util-internal.h" +#include "telepathy-glib/_gen/signals-marshal.h" #include "_gen/tp-cli-connection-body.h" @@ -173,6 +174,31 @@ 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 and the TpConnection::balance-changed: will be emitted + * when they are changed. + * + * 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,9 +268,21 @@ enum PROP_SELF_CONTACT, PROP_SELF_HANDLE, PROP_CAPABILITIES, + PROP_BALANCE, + PROP_BALANCE_SCALE, + PROP_BALANCE_CURRENCY, + PROP_BALANCE_URI, N_PROPS }; +enum { + SIGNAL_BALANCE_CHANGED, + N_SIGNALS +}; + +static guint signals[N_SIGNALS] = { 0 }; + + G_DEFINE_TYPE (TpConnection, tp_connection, TP_TYPE_PROXY) @@ -283,6 +321,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 +340,126 @@ 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 = ""; + gboolean changed = FALSE; + + if (balance_s == NULL) + goto finally; + + tp_value_array_unpack (balance_s, 3, + &balance, &scale, ¤cy); + +finally: + + g_object_freeze_notify ((GObject *) self); + + if (self->priv->balance != balance) + { + self->priv->balance = balance; + g_object_notify ((GObject *) self, "balance"); + changed = TRUE; + } + + if (self->priv->balance_scale != scale) + { + self->priv->balance_scale = scale; + g_object_notify ((GObject *) self, "balance-scale"); + changed = TRUE; + } + + 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"); + changed = TRUE; + } + + g_object_thaw_notify ((GObject *) self); + + if (changed) + { + g_signal_emit (self, signals[SIGNAL_BALANCE_CHANGED], 0, + balance, scale, currency); + } +} + +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; + GSimpleAsyncResult *result = user_data; + GValueArray *balance = NULL; + + if (in_error != NULL) + { + DEBUG ("Failed to get Balance properties: %s", in_error->message); + g_simple_async_result_set_from_error (result, in_error); + 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")); + + 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); + +finally: + g_simple_async_result_complete (result); +} + +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_prepare_balance_async (TpProxy *proxy, + const TpProxyFeature *feature, + GAsyncReadyCallback callback, + gpointer user_data) +{ + TpConnection *self = (TpConnection *) proxy; + GSimpleAsyncResult *result; + + result = g_simple_async_result_new ((GObject *) proxy, callback, user_data, + tp_connection_prepare_balance_async); + + g_assert (self->priv->balance_currency == NULL); + + tp_cli_dbus_properties_call_get_all (self, -1, + TP_IFACE_CONNECTION_INTERFACE_BALANCE, + tp_connection_get_balance_cb, result, g_object_unref, 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, @@ -1202,6 +1372,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); } @@ -1271,6 +1444,7 @@ enum { FEAT_CAPABILITIES, FEAT_AVATAR_REQUIREMENTS, FEAT_CONTACT_INFO, + FEAT_BALANCE, N_FEAT }; @@ -1281,6 +1455,7 @@ tp_connection_list_features (TpProxyClass *cls G_GNUC_UNUSED) static GQuark need_requests[2] = {0, 0}; static GQuark need_avatars[2] = {0, 0}; static GQuark need_contact_info[2] = {0, 0}; + static GQuark need_balance[2] = {0, 0}; if (G_LIKELY (features[0].name != 0)) return features; @@ -1308,6 +1483,11 @@ 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].prepare_async = tp_connection_prepare_balance_async; + need_balance[0] = TP_IFACE_QUARK_CONNECTION_INTERFACE_BALANCE; + features[FEAT_BALANCE].interfaces_needed = need_balance; + /* assert that the terminator at the end is there */ g_assert (features[N_FEAT].name == 0); @@ -1486,6 +1666,96 @@ 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); + + /** + * TpConnection::balance-changed: + * @self: a channel + * @balance: the value of the #TpConnection:balance property + * @balance_scale: the value of the #TpConnection:balance-scale property + * @balance_currency: the value of the #TpConnection:balance-currency property + * + * Emitted when at least one of the #TpConnection:balance, + * #TpConnection:balance-scale or #TpConnection:balance-currency + * property is changed. + * + * For this signal to be emitted, you must first call + * tp_proxy_prepare_async() with the feature %TP_CONNECTION_FEATURE_BALANCE. + * + * Since: 0.15.UNRELEASED + */ + signals[SIGNAL_BALANCE_CHANGED] = g_signal_new ("balance-changed", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + _tp_marshal_VOID__INT_UINT_STRING, + G_TYPE_NONE, 3, G_TYPE_INT, G_TYPE_UINT, G_TYPE_STRING); } /** @@ -2560,3 +2830,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/telepathy-glib/signals-marshal.list b/telepathy-glib/signals-marshal.list index e675efd7..cb31434e 100644 --- a/telepathy-glib/signals-marshal.list +++ b/telepathy-glib/signals-marshal.list @@ -16,3 +16,4 @@ VOID:UINT,UINT,UINT,STRING,BOXED VOID:VOID VOID:BOXED,UINT,INT,STRING VOID:OBJECT,UINT,STRING +VOID:INT,UINT,STRING 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..34d679b1 --- /dev/null +++ b/tests/dbus/connection-balance.c @@ -0,0 +1,428 @@ +/* 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 { + GMainLoop *mainloop; + 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; + + GError *error /* initialized where needed */; + gint wait; +} 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->mainloop = g_main_loop_new (NULL, FALSE); + test->error = NULL; + + 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; + + g_clear_error (&test->error); + tp_clear_pointer (&test->mainloop, g_main_loop_unref); + 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 +balance_changed_cb (TpConnection *conn, + gint balance, + guint scale, + const gchar *currency, + Test *test) +{ + g_assert_cmpint (balance, ==, BALANCE * 2); + g_assert_cmpuint (scale, ==, BALANCE_SCALE); + g_assert_cmpstr (currency, ==, BALANCE_CURRENCY); + + test->wait--; + if (test->wait <= 0) + g_main_loop_quit (test->mainloop); +} + +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; + GValueArray *v; + + 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, ¤cy)); + + 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", ¤cy_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); + + v = tp_value_array_build (3, + G_TYPE_INT, BALANCE * 2, + G_TYPE_UINT, BALANCE_SCALE, + G_TYPE_STRING, BALANCE_CURRENCY, + G_TYPE_INVALID); + + tp_svc_connection_interface_balance_emit_balance_changed ( + test->service_conn_as_base, v); + + g_signal_connect (test->conn, "balance-changed", + G_CALLBACK (balance_changed_cb), test); + + test->wait = 1; + g_main_loop_run (test->mainloop); + g_assert_no_error (test->error); + + 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, ¤cy)); +} + +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 (); +} |