1 /* A very basic feature test for TpAccount
2  *
3  * Copyright (C) 2009-2012 Collabora Ltd. <http://www.collabora.co.uk/>
4  * Copyright (C) 2009 Nokia Corporation
5  *
6  * Copying and distribution of this file, with or without modification,
7  * are permitted in any medium without royalty provided the copyright
8  * notice and this notice are preserved.
9  */
10 
11 #include "config.h"
12 
13 #include <telepathy-glib/account.h>
14 #include <telepathy-glib/debug.h>
15 #include <telepathy-glib/defs.h>
16 #include <telepathy-glib/svc-account.h>
17 #include <telepathy-glib/enums.h>
18 
19 #include "tests/lib/contacts-conn.h"
20 #include "tests/lib/simple-account.h"
21 #include "tests/lib/util.h"
22 
23 #define ACCOUNT_PATH TP_ACCOUNT_OBJECT_PATH_BASE "what/ev/er"
24 #define SUPERSEDED_PATH TP_ACCOUNT_OBJECT_PATH_BASE "super/seded/whatever"
25 
26 static void
test_parse_failure(gconstpointer test_data)27 test_parse_failure (gconstpointer test_data)
28 {
29   GError *error = NULL;
30 
31   g_assert (!tp_account_parse_object_path (test_data, NULL, NULL, NULL,
32       &error));
33   g_assert (error != NULL);
34   g_error_free (error);
35 }
36 
37 typedef struct {
38     const gchar *path;
39     const gchar *cm;
40     const gchar *protocol;
41     const gchar *account_id;
42 } TestParseData;
43 
44 static TestParseData *
test_parse_data_new(const gchar * path,const gchar * cm,const gchar * protocol,const gchar * account_id)45 test_parse_data_new (const gchar *path,
46     const gchar *cm,
47     const gchar *protocol,
48     const gchar *account_id)
49 {
50   TestParseData *t = g_slice_new (TestParseData);
51 
52   t->path = path;
53   t->cm = cm;
54   t->protocol = protocol;
55   t->account_id = account_id;
56 
57   return t;
58 }
59 
60 static void
test_parse_success(gconstpointer test_data)61 test_parse_success (gconstpointer test_data)
62 {
63   TestParseData *t = (TestParseData *) test_data;
64   gchar *cm, *protocol, *account_id;
65   GError *error = NULL;
66 
67   g_assert (tp_account_parse_object_path (t->path, &cm, &protocol, &account_id,
68       &error));
69   g_assert_no_error (error);
70   g_assert_cmpstr (cm, ==, t->cm);
71   g_assert_cmpstr (protocol, ==, t->protocol);
72   g_assert_cmpstr (account_id, ==, t->account_id);
73 
74   g_free (cm);
75   g_free (protocol);
76   g_free (account_id);
77 
78   g_slice_free (TestParseData, t);
79 }
80 
81 typedef struct {
82     GMainLoop *mainloop;
83     TpDBusDaemon *dbus;
84 
85     TpAccount *account;
86     gulong notify_id;
87     /* g_strdup (property name) => GUINT_TO_POINTER (counter) */
88     GHashTable *times_notified;
89     GAsyncResult *result;
90     GError *error /* initialized where needed */;
91 
92     /* initialized in prepare_service */
93     TpTestsSimpleAccount *account_service;
94     TpBaseConnection *conn1_service;
95     TpBaseConnection *conn2_service;
96     TpConnection *conn1;
97     TpConnection *conn2;
98 } Test;
99 
100 static void
setup(Test * test,gconstpointer data)101 setup (Test *test,
102        gconstpointer data)
103 {
104   test->mainloop = g_main_loop_new (NULL, FALSE);
105   test->dbus = tp_tests_dbus_daemon_dup_or_die ();
106   g_assert (test->dbus != NULL);
107 
108   test->account = NULL;
109 
110   test->times_notified = g_hash_table_new_full (g_str_hash, g_str_equal,
111       g_free, NULL);
112 }
113 
114 static void
setup_service(Test * test,gconstpointer data)115 setup_service (Test *test,
116     gconstpointer data)
117 {
118   setup (test, data);
119 
120   tp_dbus_daemon_request_name (test->dbus,
121       TP_ACCOUNT_MANAGER_BUS_NAME, FALSE, &test->error);
122   g_assert_no_error (test->error);
123 
124   test->account_service = g_object_new (TP_TESTS_TYPE_SIMPLE_ACCOUNT, NULL);
125   tp_dbus_daemon_register_object (test->dbus, ACCOUNT_PATH,
126       test->account_service);
127 
128   tp_tests_create_and_connect_conn (TP_TESTS_TYPE_CONTACTS_CONNECTION,
129       "what@ever", &test->conn1_service, &test->conn1);
130   tp_tests_create_and_connect_conn (TP_TESTS_TYPE_CONTACTS_CONNECTION,
131       "what2@ever", &test->conn2_service, &test->conn2);
132 }
133 
134 static guint
test_get_times_notified(Test * test,const gchar * property)135 test_get_times_notified (Test *test,
136     const gchar *property)
137 {
138   return GPOINTER_TO_UINT (g_hash_table_lookup (test->times_notified,
139         property));
140 }
141 
142 static void
test_notify_cb(Test * test,GParamSpec * pspec,TpAccount * account)143 test_notify_cb (Test *test,
144     GParamSpec *pspec,
145     TpAccount *account)
146 {
147   guint counter = test_get_times_notified (test, pspec->name);
148 
149   g_hash_table_insert (test->times_notified, g_strdup (pspec->name),
150       GUINT_TO_POINTER (++counter));
151 }
152 
153 static void
test_set_up_account_notify(Test * test)154 test_set_up_account_notify (Test *test)
155 {
156   g_assert (test->account != NULL);
157 
158   g_hash_table_remove_all (test->times_notified);
159 
160   if (test->notify_id != 0)
161     {
162       g_signal_handler_disconnect (test->account, test->notify_id);
163     }
164 
165   test->notify_id = g_signal_connect_swapped (test->account, "notify",
166       G_CALLBACK (test_notify_cb), test);
167 }
168 
169 static void
teardown(Test * test,gconstpointer data)170 teardown (Test *test,
171           gconstpointer data)
172 {
173   if (test->account != NULL)
174     {
175       tp_tests_proxy_run_until_dbus_queue_processed (test->account);
176 
177       if (test->notify_id != 0)
178         {
179           g_signal_handler_disconnect (test->account, test->notify_id);
180         }
181 
182       g_object_unref (test->account);
183       test->account = NULL;
184     }
185 
186   g_hash_table_unref (test->times_notified);
187   test->times_notified = NULL;
188 
189   /* make sure any pending calls on the account have happened, so it can die */
190   tp_tests_proxy_run_until_dbus_queue_processed (test->dbus);
191 
192   g_object_unref (test->dbus);
193   test->dbus = NULL;
194   g_main_loop_unref (test->mainloop);
195   test->mainloop = NULL;
196 
197   g_clear_error (&test->error);
198   tp_clear_object (&test->result);
199 }
200 
201 static void
teardown_service(Test * test,gconstpointer data)202 teardown_service (Test *test,
203     gconstpointer data)
204 {
205   tp_dbus_daemon_release_name (test->dbus, TP_ACCOUNT_MANAGER_BUS_NAME,
206       &test->error);
207   g_assert_no_error (test->error);
208 
209   tp_dbus_daemon_unregister_object (test->dbus, test->account_service);
210   g_clear_object (&test->account_service);
211 
212   tp_tests_connection_assert_disconnect_succeeds (test->conn1);
213   g_clear_object (&test->conn1);
214   g_clear_object (&test->conn1_service);
215 
216   tp_tests_connection_assert_disconnect_succeeds (test->conn2);
217   g_clear_object (&test->conn2);
218   g_clear_object (&test->conn2_service);
219 
220   teardown (test, data);
221 }
222 
223 static void
test_new(Test * test,gconstpointer data G_GNUC_UNUSED)224 test_new (Test *test,
225           gconstpointer data G_GNUC_UNUSED)
226 {
227   test->account = tp_account_new (test->dbus,
228       "/secretly/not/an/object", NULL);
229   g_assert (test->account == NULL);
230 
231   test->account = tp_account_new (test->dbus,
232       "not even syntactically valid", NULL);
233   g_assert (test->account == NULL);
234 
235   test->account = tp_account_new (test->dbus,
236       "/org/freedesktop/Telepathy/Account/what/ev/er", NULL);
237   g_assert (test->account != NULL);
238 }
239 
240 static void
test_setters(Test * test,gconstpointer data G_GNUC_UNUSED)241 test_setters (Test *test,
242     gconstpointer data G_GNUC_UNUSED)
243 {
244   test->account = tp_account_new (test->dbus,
245       "/org/freedesktop/Telepathy/Account/what/ev/er", NULL);
246   g_assert (test->account != NULL);
247 
248   tp_account_set_enabled_async (test->account, TRUE, tp_tests_result_ready_cb,
249     &test->result);
250   tp_tests_run_until_result (&test->result);
251   tp_account_set_enabled_finish (test->account, test->result, &test->error);
252   g_assert_error (test->error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED);
253   g_clear_error (&test->error);
254   tp_clear_object (&test->result);
255 }
256 
257 static void
test_reconnect(Test * test,gconstpointer data)258 test_reconnect (Test *test,
259     gconstpointer data)
260 {
261   GStrv reconnect_required;
262   const gchar *unset[] = { "unset", NULL };
263 
264   test->account = tp_account_new (test->dbus, ACCOUNT_PATH, NULL);
265   g_assert (test->account != NULL);
266 
267   if (!tp_strdiff (data, "vardict"))
268     {
269       tp_account_update_parameters_vardict_async (test->account,
270           g_variant_new_parsed ("{ 'set': <%s> }", "value"), unset,
271           tp_tests_result_ready_cb, &test->result);
272       tp_tests_run_until_result (&test->result);
273       tp_account_update_parameters_vardict_finish (test->account, test->result,
274           &reconnect_required, &test->error);
275     }
276   else
277     {
278       GHashTable *set = tp_asv_new (
279           "set", G_TYPE_STRING, "value",
280           NULL);
281 
282       tp_account_update_parameters_async (test->account, set, unset,
283           tp_tests_result_ready_cb, &test->result);
284       tp_tests_run_until_result (&test->result);
285       tp_account_update_parameters_finish (test->account, test->result,
286           &reconnect_required, &test->error);
287 
288       g_hash_table_unref (set);
289     }
290 
291   g_assert_no_error (test->error);
292   /* check that reconnect_required survives longer than result */
293   tp_clear_object (&test->result);
294 
295   g_assert (reconnect_required != NULL);
296   g_assert_cmpstr (reconnect_required[0], ==, "set");
297   g_assert_cmpstr (reconnect_required[1], ==, "unset");
298   g_assert_cmpstr (reconnect_required[2], ==, NULL);
299   g_strfreev (reconnect_required);
300 
301   tp_account_reconnect_async (test->account, tp_tests_result_ready_cb,
302       &test->result);
303   tp_tests_run_until_result (&test->result);
304   tp_account_reconnect_finish (test->account, test->result, &test->error);
305   g_assert_error (test->error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED);
306   g_clear_error (&test->error);
307   tp_clear_object (&test->result);
308 }
309 
310 static void
account_prepare_cb(GObject * source,GAsyncResult * result,gpointer user_data)311 account_prepare_cb (GObject *source,
312     GAsyncResult *result,
313     gpointer user_data)
314 {
315   Test *test = user_data;
316   GError *error = NULL;
317 
318   tp_proxy_prepare_finish (source, result, &error);
319   g_assert_no_error (error);
320 
321   g_main_loop_quit (test->mainloop);
322 }
323 
324 #define assert_strprop(self, prop, val) \
325   {\
326     gchar *_s; \
327     \
328     g_object_get (self, \
329         prop, &_s, \
330         NULL); \
331     g_assert_cmpstr (_s, ==, val);\
332     g_free (_s); \
333   }
334 #define assert_uintprop(self, prop, val) \
335   {\
336     guint _u; \
337     \
338     g_object_get (self, \
339         prop, &_u, \
340         NULL); \
341     g_assert_cmpuint (_u, ==, val);\
342   }
343 #define assert_boolprop(self, prop, val) \
344   {\
345     gboolean _b; \
346     \
347     g_object_get (self, \
348         prop, &_b, \
349         NULL); \
350     g_assert_cmpint (_b, ==, val);\
351   }
352 
353 static void
test_prepare_success(Test * test,gconstpointer data G_GNUC_UNUSED)354 test_prepare_success (Test *test,
355     gconstpointer data G_GNUC_UNUSED)
356 {
357   GQuark account_features[] = { TP_ACCOUNT_FEATURE_CORE, 0 };
358   TpConnectionStatusReason reason;
359   gchar *status = NULL;
360   gchar *message = NULL;
361   const GHashTable *details = GUINT_TO_POINTER (666);
362   GStrv strv;
363   const gchar * const *cstrv;
364   GVariant *variant;
365 
366   test->account = tp_account_new (test->dbus, ACCOUNT_PATH, NULL);
367   g_assert (test->account != NULL);
368 
369   tp_proxy_prepare_async (test->account, account_features,
370       account_prepare_cb, test);
371   g_main_loop_run (test->mainloop);
372 
373   /* the obvious accessors */
374   g_assert (tp_proxy_is_prepared (test->account, TP_ACCOUNT_FEATURE_CORE));
375   g_assert (tp_account_is_enabled (test->account));
376   assert_boolprop (test->account, "enabled", TRUE);
377   g_assert (tp_account_is_valid (test->account));
378   assert_boolprop (test->account, "valid", TRUE);
379   g_assert_cmpstr (tp_account_get_display_name (test->account), ==,
380       "Fake Account");
381   assert_strprop (test->account, "display-name", "Fake Account");
382   g_assert_cmpstr (tp_account_get_nickname (test->account), ==, "badger");
383   assert_strprop (test->account, "nickname", "badger");
384   g_assert_cmpuint (tp_asv_size (tp_account_get_parameters (test->account)),
385       ==, 0);
386   variant = tp_account_dup_parameters_vardict (test->account);
387   g_assert_cmpstr (g_variant_get_type_string (variant), ==, "a{sv}");
388   g_assert_cmpuint (g_variant_n_children (variant), ==, 0);
389   g_variant_unref (variant);
390   g_assert (!tp_account_get_connect_automatically (test->account));
391   assert_boolprop (test->account, "connect-automatically", FALSE);
392   g_assert (tp_account_get_has_been_online (test->account));
393   assert_boolprop (test->account, "has-been-online", TRUE);
394   g_assert_cmpint (tp_account_get_connection_status (test->account, NULL),
395       ==, TP_CONNECTION_STATUS_CONNECTED);
396   assert_uintprop (test->account, "connection-status",
397       TP_CONNECTION_STATUS_CONNECTED);
398   g_assert_cmpint (tp_account_get_connection_status (test->account, &reason),
399       ==, TP_CONNECTION_STATUS_CONNECTED);
400   g_assert_cmpint (reason, ==, TP_CONNECTION_STATUS_REASON_REQUESTED);
401   assert_uintprop (test->account, "connection-status-reason",
402       TP_CONNECTION_STATUS_REASON_REQUESTED);
403   g_assert_cmpstr (tp_account_get_detailed_error (test->account, NULL), ==,
404       NULL);
405   assert_strprop (test->account, "connection-error", NULL);
406   g_assert_cmpstr (tp_account_get_detailed_error (test->account, &details), ==,
407       NULL);
408   /* this is documented to be untouched */
409   g_assert_cmpuint (GPOINTER_TO_UINT (details), ==, 666);
410 
411   /* the CM and protocol come from the object path */
412   g_assert_cmpstr (tp_account_get_cm_name (test->account),
413       ==, "what");
414   assert_strprop (test->account, "cm-name", "what");
415   g_assert_cmpstr (tp_account_get_protocol_name (test->account), ==, "ev");
416   assert_strprop (test->account, "protocol-name", "ev");
417 
418   /* the icon name in SimpleAccount is "", so we guess based on the protocol */
419   g_assert_cmpstr (tp_account_get_icon_name (test->account), ==, "im-ev");
420   assert_strprop (test->account, "icon-name", "im-ev");
421 
422   /* RequestedPresence */
423   g_assert_cmpint (tp_account_get_requested_presence (test->account, NULL,
424         NULL), ==, TP_CONNECTION_PRESENCE_TYPE_BUSY);
425   assert_uintprop (test->account, "requested-presence-type",
426       TP_CONNECTION_PRESENCE_TYPE_BUSY);
427   g_assert_cmpint (tp_account_get_requested_presence (test->account, &status,
428         NULL), ==, TP_CONNECTION_PRESENCE_TYPE_BUSY);
429   g_assert_cmpstr (status, ==, "requesting");
430   g_free (status);
431   assert_strprop (test->account, "requested-status", "requesting");
432   g_assert_cmpint (tp_account_get_requested_presence (test->account, NULL,
433         &message), ==, TP_CONNECTION_PRESENCE_TYPE_BUSY);
434   g_assert_cmpstr (message, ==, "this is my RequestedPresence");
435   g_free (message);
436   assert_strprop (test->account, "requested-status-message",
437       "this is my RequestedPresence");
438 
439   /* CurrentPresence */
440   g_assert_cmpint (tp_account_get_current_presence (test->account, NULL,
441         NULL), ==, TP_CONNECTION_PRESENCE_TYPE_AWAY);
442   assert_uintprop (test->account, "current-presence-type",
443       TP_CONNECTION_PRESENCE_TYPE_AWAY);
444   g_assert_cmpint (tp_account_get_current_presence (test->account, &status,
445         NULL), ==, TP_CONNECTION_PRESENCE_TYPE_AWAY);
446   g_assert_cmpstr (status, ==, "currently-away");
447   g_free (status);
448   assert_strprop (test->account, "current-status", "currently-away");
449   g_assert_cmpint (tp_account_get_current_presence (test->account, NULL,
450         &message), ==, TP_CONNECTION_PRESENCE_TYPE_AWAY);
451   g_assert_cmpstr (message, ==, "this is my CurrentPresence");
452   g_free (message);
453   assert_strprop (test->account, "current-status-message",
454       "this is my CurrentPresence");
455 
456   /* AutomaticPresence */
457   g_assert_cmpint (tp_account_get_automatic_presence (test->account, NULL,
458         NULL), ==, TP_CONNECTION_PRESENCE_TYPE_AVAILABLE);
459   assert_uintprop (test->account, "automatic-presence-type",
460       TP_CONNECTION_PRESENCE_TYPE_AVAILABLE);
461   g_assert_cmpint (tp_account_get_automatic_presence (test->account, &status,
462         NULL), ==, TP_CONNECTION_PRESENCE_TYPE_AVAILABLE);
463   g_assert_cmpstr (status, ==, "automatically-available");
464   g_free (status);
465   assert_strprop (test->account, "automatic-status",
466       "automatically-available");
467   g_assert_cmpint (tp_account_get_automatic_presence (test->account, NULL,
468         &message), ==, TP_CONNECTION_PRESENCE_TYPE_AVAILABLE);
469   g_assert_cmpstr (message, ==, "this is my AutomaticPresence");
470   g_free (message);
471   assert_strprop (test->account, "automatic-status-message",
472       "this is my AutomaticPresence");
473 
474   /* NormalizedName */
475   g_assert_cmpstr (tp_account_get_normalized_name (test->account), ==,
476       "bob.mcbadgers@example.com");
477   assert_strprop (test->account, "normalized-name",
478       "bob.mcbadgers@example.com");
479 
480   g_object_get (test->account,
481       "supersedes", &strv,
482       NULL);
483   g_assert_cmpstr (strv[0], ==, SUPERSEDED_PATH);
484   g_assert_cmpstr (strv[1], ==, NULL);
485   g_strfreev (strv);
486 
487   cstrv = tp_account_get_supersedes (test->account);
488   g_assert_cmpstr (cstrv[0], ==, SUPERSEDED_PATH);
489   g_assert_cmpstr (cstrv[1], ==, NULL);
490 }
491 
492 static void
test_storage(Test * test,gconstpointer mode)493 test_storage (Test *test,
494     gconstpointer mode)
495 {
496   GQuark account_features[] = { TP_ACCOUNT_FEATURE_STORAGE, 0 };
497   GValue *gvalue;
498   GVariant *gvariant;
499   GHashTable *info;
500   GError *error = NULL;
501   gboolean found;
502   gint32 i;
503   guint32 u;
504   const gchar *s;
505 
506   test->account = tp_account_new (test->dbus, ACCOUNT_PATH, NULL);
507   g_assert (test->account != NULL);
508 
509   if (g_str_equal (mode, "later"))
510     {
511       /* prepare the core feature first */
512       tp_proxy_prepare_async (test->account, NULL, account_prepare_cb, test);
513       g_main_loop_run (test->mainloop);
514 
515       /* storage stuff doesn't work yet */
516       g_assert_cmpstr (tp_account_get_storage_provider (test->account), ==,
517           NULL);
518       assert_strprop (test->account, "storage-provider", NULL);
519       g_assert (tp_account_get_storage_identifier (test->account) == NULL);
520       g_object_get (test->account,
521           "storage-identifier", &gvalue,
522           NULL);
523       g_assert (gvalue == NULL);
524       g_assert (tp_account_get_storage_identifier (test->account) == NULL);
525       g_object_get (test->account,
526           "storage-identifier", &gvariant,
527           NULL);
528       g_assert (gvariant == NULL);
529       g_assert_cmpuint (tp_account_get_storage_restrictions (test->account), ==,
530           0);
531       assert_uintprop (test->account, "storage-restrictions", 0);
532     }
533 
534   /* prepare the storage feature */
535   tp_proxy_prepare_async (test->account, account_features,
536       account_prepare_cb, test);
537   g_main_loop_run (test->mainloop);
538 
539   g_assert_cmpstr (tp_account_get_storage_provider (test->account), ==,
540       "org.freedesktop.Telepathy.glib.test");
541   assert_strprop (test->account, "storage-provider",
542       "org.freedesktop.Telepathy.glib.test");
543 
544   g_assert_cmpstr (
545       g_value_get_string (tp_account_get_storage_identifier (test->account)),
546       ==, "unique-identifier");
547   g_object_get (test->account,
548       "storage-identifier", &gvalue,
549       NULL);
550   g_assert_cmpstr (g_value_get_string (gvalue), ==, "unique-identifier");
551   g_boxed_free (G_TYPE_VALUE, gvalue);
552 
553   gvariant = tp_account_dup_storage_identifier_variant (test->account);
554   g_assert_cmpstr (g_variant_get_type_string (gvariant), ==, "s");
555   g_assert_cmpstr (g_variant_get_string (gvariant, NULL), ==,
556       "unique-identifier");
557   g_variant_unref (gvariant);
558   g_object_get (test->account,
559       "storage-identifier-variant", &gvariant,
560       NULL);
561   g_assert_cmpstr (g_variant_get_type_string (gvariant), ==, "s");
562   g_assert_cmpstr (g_variant_get_string (gvariant, NULL), ==,
563       "unique-identifier");
564   g_variant_unref (gvariant);
565 
566   g_assert_cmpuint (tp_account_get_storage_restrictions (test->account), ==,
567       TP_STORAGE_RESTRICTION_FLAG_CANNOT_SET_ENABLED |
568       TP_STORAGE_RESTRICTION_FLAG_CANNOT_SET_PARAMETERS);
569   assert_uintprop (test->account, "storage-restrictions",
570       TP_STORAGE_RESTRICTION_FLAG_CANNOT_SET_ENABLED |
571       TP_STORAGE_RESTRICTION_FLAG_CANNOT_SET_PARAMETERS);
572 
573   /* request the StorageSpecificProperties hash */
574   tp_account_get_storage_specific_information_async (test->account,
575       tp_tests_result_ready_cb, &test->result);
576   tp_tests_run_until_result (&test->result);
577 
578   info = tp_account_get_storage_specific_information_finish (
579       test->account, test->result, &error);
580   g_assert_no_error (error);
581 
582   g_assert_cmpuint (g_hash_table_size (info), ==, 3);
583 
584   g_assert_cmpint (tp_asv_get_int32 (info, "one", NULL), ==, 1);
585   g_assert_cmpuint (tp_asv_get_uint32 (info, "two", NULL), ==, 2);
586   g_assert_cmpstr (tp_asv_get_string (info, "marco"), ==, "polo");
587 
588   tp_clear_object (&test->result);
589 
590   /* the same, but with 100% more GVariant */
591   tp_account_dup_storage_specific_information_vardict_async (test->account,
592       tp_tests_result_ready_cb, &test->result);
593   tp_tests_run_until_result (&test->result);
594 
595   gvariant = tp_account_dup_storage_specific_information_vardict_finish (
596       test->account, test->result, &error);
597   g_assert_no_error (error);
598 
599   g_assert_cmpstr (g_variant_get_type_string (gvariant), ==, "a{sv}");
600   found = g_variant_lookup (gvariant, "one", "i", &i);
601   g_assert (found);
602   g_assert_cmpint (i, ==, 1);
603   found = g_variant_lookup (gvariant, "two", "u", &u);
604   g_assert (found);
605   g_assert_cmpint (u, ==, 2);
606   found = g_variant_lookup (gvariant, "marco", "&s", &s);
607   g_assert (found);
608   g_assert_cmpstr (s, ==, "polo");
609   found = g_variant_lookup (gvariant, "barisione", "&s", &s);
610   g_assert (!found);
611 
612   g_variant_unref (gvariant);
613   tp_clear_object (&test->result);
614 }
615 
616 static void
check_uri_schemes(const gchar * const * schemes)617 check_uri_schemes (const gchar * const * schemes)
618 {
619   g_assert (schemes != NULL);
620   g_assert (tp_strv_contains (schemes, "about"));
621   g_assert (tp_strv_contains (schemes, "telnet"));
622   g_assert (schemes[2] == NULL);
623 }
624 
625 static void
notify_cb(GObject * object,GParamSpec * spec,Test * test)626 notify_cb (GObject *object,
627     GParamSpec *spec,
628     Test *test)
629 {
630   g_main_loop_quit (test->mainloop);
631 }
632 
633 static void
test_addressing(Test * test,gconstpointer mode)634 test_addressing (Test *test,
635     gconstpointer mode)
636 {
637   GQuark account_features[] = { TP_ACCOUNT_FEATURE_ADDRESSING, 0 };
638   const gchar * const *schemes;
639   GStrv tmp;
640 
641   test->account = tp_account_new (test->dbus, ACCOUNT_PATH, NULL);
642   g_assert (test->account != NULL);
643 
644   if (g_str_equal (mode, "later"))
645     {
646       /* prepare the core feature first */
647       tp_proxy_prepare_async (test->account, NULL, account_prepare_cb, test);
648       g_main_loop_run (test->mainloop);
649 
650       /* addressing stuff doesn't work yet */
651       g_assert (tp_account_get_uri_schemes (test->account) == NULL);
652       g_assert (!tp_account_associated_with_uri_scheme (test->account,
653             "about"));
654       g_assert (!tp_account_associated_with_uri_scheme (test->account,
655             "telnet"));
656       g_assert (!tp_account_associated_with_uri_scheme (test->account,
657             "xmpp"));
658     }
659 
660   /* prepare the addressing feature */
661   tp_proxy_prepare_async (test->account, account_features,
662       account_prepare_cb, test);
663   g_main_loop_run (test->mainloop);
664 
665   schemes = tp_account_get_uri_schemes (test->account);
666   check_uri_schemes (schemes);
667 
668   g_object_get (test->account,
669       "uri-schemes", &tmp,
670       NULL);
671 
672   check_uri_schemes ((const gchar * const *) tmp);
673   g_strfreev (tmp);
674 
675   g_assert (tp_account_associated_with_uri_scheme (test->account,
676         "about"));
677   g_assert (tp_account_associated_with_uri_scheme (test->account,
678         "telnet"));
679   g_assert (!tp_account_associated_with_uri_scheme (test->account,
680         "xmpp"));
681 
682   g_signal_connect (test->account, "notify::uri-schemes",
683       G_CALLBACK (notify_cb), test);
684 
685   tp_tests_simple_account_add_uri_scheme (test->account_service, "xmpp");
686   g_main_loop_run (test->mainloop);
687 
688   g_assert (tp_account_associated_with_uri_scheme (test->account,
689         "xmpp"));
690 }
691 
692 static void
avatar_changed_cb(TpAccount * account,Test * test)693 avatar_changed_cb (TpAccount *account,
694     Test *test)
695 {
696   g_main_loop_quit (test->mainloop);
697 }
698 
699 static void
test_avatar(Test * test,gconstpointer mode)700 test_avatar (Test *test,
701     gconstpointer mode)
702 {
703   const GArray *blob;
704   GError *error = NULL;
705 
706   test->account = tp_account_new (test->dbus, ACCOUNT_PATH, NULL);
707   g_assert (test->account != NULL);
708 
709   tp_proxy_prepare_async (test->account, NULL, account_prepare_cb, test);
710   g_main_loop_run (test->mainloop);
711 
712   tp_account_get_avatar_async (test->account,
713       tp_tests_result_ready_cb, &test->result);
714   tp_tests_run_until_result (&test->result);
715 
716   blob = tp_account_get_avatar_finish (
717       test->account, test->result, &error);
718   g_assert_no_error (error);
719 
720   g_assert_cmpuint (blob->len, ==, 4);
721   g_assert_cmpstr (((char *) blob->data), ==, ":-)");
722 
723   tp_clear_object (&test->result);
724 
725   /* change the avatar */
726   g_signal_connect (test->account, "avatar-changed",
727       G_CALLBACK (avatar_changed_cb), test);
728 
729   tp_tests_simple_account_set_avatar (test->account_service, ":-(");
730   g_main_loop_run (test->mainloop);
731 
732   tp_account_get_avatar_async (test->account,
733       tp_tests_result_ready_cb, &test->result);
734   tp_tests_run_until_result (&test->result);
735 
736   blob = tp_account_get_avatar_finish (
737       test->account, test->result, &error);
738   g_assert_no_error (error);
739 
740   g_assert (blob != NULL);
741   g_assert_cmpuint (blob->len, ==, 4);
742   g_assert_cmpstr (((char *) blob->data), ==, ":-(");
743 
744   tp_clear_object (&test->result);
745 }
746 
747 static void
test_connection(Test * test,gconstpointer data G_GNUC_UNUSED)748 test_connection (Test *test,
749     gconstpointer data G_GNUC_UNUSED)
750 {
751   const gchar *conn1_path = tp_proxy_get_object_path (test->conn1);
752   const gchar *conn2_path = tp_proxy_get_object_path (test->conn2);
753   GQuark account_features[] = { TP_ACCOUNT_FEATURE_CORE, 0 };
754   GHashTable *change = tp_asv_new (NULL, NULL);
755   TpConnection *conn;
756   const GHashTable *details;
757   GVariant *details_v;
758   gboolean found;
759   gchar *s;
760   guint32 u;
761 
762   test->account = tp_account_new (test->dbus, ACCOUNT_PATH, NULL);
763   g_assert (test->account != NULL);
764 
765   tp_proxy_prepare_async (test->account, account_features,
766       account_prepare_cb, test);
767   g_main_loop_run (test->mainloop);
768 
769   g_assert (tp_proxy_is_prepared (test->account, TP_ACCOUNT_FEATURE_CORE));
770 
771   /* a connection turns up */
772 
773   test_set_up_account_notify (test);
774   tp_asv_set_object_path (change, "Connection", conn1_path);
775   tp_asv_set_uint32 (change, "ConnectionStatus",
776       TP_CONNECTION_STATUS_CONNECTING);
777   tp_asv_set_uint32 (change, "ConnectionStatusReason",
778       TP_CONNECTION_STATUS_REASON_REQUESTED);
779   tp_svc_account_emit_account_property_changed (test->account_service, change);
780   g_hash_table_remove_all (change);
781 
782   while (test_get_times_notified (test, "connection") < 1)
783     g_main_context_iteration (NULL, TRUE);
784 
785   g_assert_cmpuint (test_get_times_notified (test, "connection"), ==, 1);
786   conn = tp_account_get_connection (test->account);
787   g_assert_cmpstr (tp_proxy_get_object_path (conn), ==, conn1_path);
788   g_assert_cmpuint (test_get_times_notified (test, "connection"), ==, 1);
789 
790   g_assert_cmpstr (tp_account_get_detailed_error (test->account, NULL), ==,
791       TP_ERROR_STR_CANCELLED);
792 
793   /* ensure the same connection - no change notification */
794 
795   test_set_up_account_notify (test);
796   conn = tp_account_ensure_connection (test->account, conn1_path);
797   g_assert_cmpstr (tp_proxy_get_object_path (conn), ==, conn1_path);
798   g_assert_cmpuint (test_get_times_notified (test, "connection"), ==, 0);
799 
800   /* a no-op "change" */
801 
802   test_set_up_account_notify (test);
803   tp_asv_set_object_path (change, "Connection", conn1_path);
804   tp_asv_set_uint32 (change, "ConnectionStatus",
805       TP_CONNECTION_STATUS_CONNECTING);
806   tp_asv_set_uint32 (change, "ConnectionStatusReason",
807       TP_CONNECTION_STATUS_REASON_REQUESTED);
808   tp_svc_account_emit_account_property_changed (test->account_service, change);
809   g_hash_table_remove_all (change);
810 
811   tp_tests_proxy_run_until_dbus_queue_processed (test->account);
812 
813   g_assert_cmpuint (test_get_times_notified (test, "connection"), ==, 0);
814   conn = tp_account_get_connection (test->account);
815   g_assert_cmpstr (tp_proxy_get_object_path (conn), ==, conn1_path);
816   g_assert_cmpuint (test_get_times_notified (test, "connection"), ==, 0);
817 
818   /* atomically flip from one connection to another (unlikely) */
819 
820   test_set_up_account_notify (test);
821   tp_asv_set_object_path (change, "Connection", conn2_path);
822   tp_asv_set_uint32 (change, "ConnectionStatus",
823       TP_CONNECTION_STATUS_CONNECTED);
824   tp_asv_set_uint32 (change, "ConnectionStatusReason",
825       TP_CONNECTION_STATUS_REASON_REQUESTED);
826   tp_svc_account_emit_account_property_changed (test->account_service, change);
827   g_hash_table_remove_all (change);
828 
829   while (test_get_times_notified (test, "connection") < 1)
830     g_main_context_iteration (NULL, TRUE);
831 
832   g_assert_cmpuint (test_get_times_notified (test, "connection"), ==, 1);
833   conn = tp_account_get_connection (test->account);
834   g_assert_cmpstr (tp_proxy_get_object_path (conn), ==, conn2_path);
835   g_assert_cmpuint (test_get_times_notified (test, "connection"), ==, 1);
836 
837   /* no more connection for you */
838 
839   test_set_up_account_notify (test);
840   tp_asv_set_object_path (change, "Connection", "/");
841   tp_asv_set_uint32 (change, "ConnectionStatus",
842       TP_CONNECTION_STATUS_DISCONNECTED);
843   tp_asv_set_uint32 (change, "ConnectionStatusReason",
844       TP_CONNECTION_STATUS_REASON_ENCRYPTION_ERROR);
845   tp_svc_account_emit_account_property_changed (test->account_service, change);
846   g_hash_table_remove_all (change);
847 
848   while (test_get_times_notified (test, "connection") < 1)
849     g_main_context_iteration (NULL, TRUE);
850 
851   g_assert_cmpuint (test_get_times_notified (test, "connection"), ==, 1);
852   conn = tp_account_get_connection (test->account);
853   g_assert (conn == NULL);
854 
855   g_assert_cmpstr (tp_account_get_detailed_error (test->account, NULL), ==,
856       TP_ERROR_STR_ENCRYPTION_ERROR);
857 
858   /* another connection */
859 
860   test_set_up_account_notify (test);
861   tp_asv_set_object_path (change, "Connection", conn1_path);
862   tp_asv_set_uint32 (change, "ConnectionStatus",
863       TP_CONNECTION_STATUS_CONNECTING);
864   tp_asv_set_uint32 (change, "ConnectionStatusReason",
865       TP_CONNECTION_STATUS_REASON_REQUESTED);
866   tp_svc_account_emit_account_property_changed (test->account_service, change);
867   g_hash_table_remove_all (change);
868 
869   tp_tests_proxy_run_until_dbus_queue_processed (test->account);
870   g_assert_cmpuint (test_get_times_notified (test, "connection"), ==, 1);
871 
872   /* lose the connection again */
873 
874   test_set_up_account_notify (test);
875   tp_asv_set_object_path (change, "Connection", "/");
876   tp_asv_set_uint32 (change, "ConnectionStatus",
877       TP_CONNECTION_STATUS_DISCONNECTED);
878   tp_asv_set_uint32 (change, "ConnectionStatusReason",
879       TP_CONNECTION_STATUS_REASON_ENCRYPTION_ERROR);
880   tp_asv_set_static_string (change, "ConnectionError",
881       "org.debian.packages.OpenSSL.NotRandomEnough");
882   tp_asv_take_boxed (change, "ConnectionErrorDetails",
883       TP_HASH_TYPE_STRING_VARIANT_MAP,
884       tp_asv_new (
885         "bits-of-entropy", G_TYPE_UINT, 15,
886         "debug-message", G_TYPE_STRING, "shiiiiii-",
887         NULL));
888   tp_svc_account_emit_account_property_changed (test->account_service, change);
889   g_hash_table_remove_all (change);
890 
891   tp_tests_proxy_run_until_dbus_queue_processed (test->account);
892   g_assert_cmpuint (test_get_times_notified (test, "connection"), ==, 1);
893   g_assert_cmpuint (test_get_times_notified (test, "connection-error"), ==, 1);
894 
895   g_assert_cmpstr (tp_account_get_detailed_error (test->account, &details), ==,
896       "org.debian.packages.OpenSSL.NotRandomEnough");
897   g_assert_cmpuint (tp_asv_size (details), >=, 2);
898   g_assert_cmpstr (tp_asv_get_string (details, "debug-message"), ==,
899       "shiiiiii-");
900   g_assert_cmpuint (tp_asv_get_uint32 (details, "bits-of-entropy", NULL), ==,
901       15);
902 
903   s = tp_account_dup_detailed_error_vardict (test->account, &details_v);
904   g_assert_cmpstr (s, ==, "org.debian.packages.OpenSSL.NotRandomEnough");
905   g_free (s);
906   g_assert_cmpuint (g_variant_n_children (details_v), >=, 2);
907   g_assert_cmpstr (g_variant_get_type_string (details_v), ==, "a{sv}");
908   found = g_variant_lookup (details_v, "debug-message", "s", &s);
909   g_assert (found);
910   g_assert_cmpstr (s, ==, "shiiiiii-");
911   g_free (s);
912   found = g_variant_lookup (details_v, "bits-of-entropy", "u", &u);
913   g_assert (found);
914   g_assert_cmpint (u, ==, 15);
915   g_variant_unref (details_v);
916 
917   /* staple on a Connection (this is intended for use in e.g. observers,
918    * if they're told about a Connection that the Account hasn't told them
919    * about yet) */
920 
921   test_set_up_account_notify (test);
922   conn = tp_account_ensure_connection (test->account, conn1_path);
923   g_assert_cmpstr (tp_proxy_get_object_path (conn), ==, conn1_path);
924   g_assert_cmpuint (test_get_times_notified (test, "connection"), ==, 1);
925 
926   g_hash_table_unref (change);
927 }
928 
929 int
main(int argc,char ** argv)930 main (int argc,
931       char **argv)
932 {
933   tp_tests_abort_after (10);
934   tp_debug_set_flags ("all");
935 
936   g_test_init (&argc, &argv, NULL);
937   g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id=");
938 
939   g_test_add_data_func ("/account/parse/spaces",
940       "this is not an object path", test_parse_failure);
941   g_test_add_data_func ("/account/parse/no-prefix",
942       "/this/is/not/an/account/path", test_parse_failure);
943   g_test_add_data_func ("/account/parse/too-few-components",
944       "/org/freedesktop/Telepathy/Account/wrong", test_parse_failure);
945   g_test_add_data_func ("/account/parse/too-many-components",
946       "/org/freedesktop/Telepathy/Account/a/b/c/d", test_parse_failure);
947   g_test_add_data_func ("/account/parse/illegal-components",
948       "/org/freedesktop/Telepathy/Account/1/2/3", test_parse_failure);
949 
950   g_test_add_data_func ("/account/parse/legal",
951       test_parse_data_new (
952           TP_ACCOUNT_OBJECT_PATH_BASE "gabble/jabber/badgers",
953           "gabble", "jabber", "badgers"),
954       test_parse_success);
955   g_test_add_data_func ("/account/parse/hyphenated-protocol",
956       test_parse_data_new (
957           TP_ACCOUNT_OBJECT_PATH_BASE "salut/local_xmpp/badgers",
958           "salut", "local-xmpp", "badgers"),
959       test_parse_success);
960   g_test_add_data_func ("/account/parse/wrongly-escaped-protocol",
961       test_parse_data_new (
962           TP_ACCOUNT_OBJECT_PATH_BASE "salut/local_2dxmpp/badgers",
963           "salut", "local-xmpp", "badgers"),
964       test_parse_success);
965   g_test_add_data_func ("/account/parse/wrongly-escaped-corner-case",
966       test_parse_data_new (
967           TP_ACCOUNT_OBJECT_PATH_BASE "salut/local_2d/badgers",
968           "salut", "local-", "badgers"),
969       test_parse_success);
970   g_test_add_data_func ("/account/parse/underscored-account",
971       test_parse_data_new (
972           TP_ACCOUNT_OBJECT_PATH_BASE "haze/msn/_thisseemsunlikely",
973           "haze", "msn", "_thisseemsunlikely"),
974       test_parse_success);
975 
976   g_test_add ("/account/new", Test, NULL, setup, test_new, teardown);
977 
978   g_test_add ("/account/setters", Test, NULL, setup_service, test_setters,
979       teardown_service);
980 
981   g_test_add ("/account/reconnect", Test, NULL, setup_service, test_reconnect,
982       teardown_service);
983   g_test_add ("/account/reconnect", Test, "vardict", setup_service,
984       test_reconnect, teardown_service);
985 
986   g_test_add ("/account/prepare/success", Test, NULL, setup_service,
987               test_prepare_success, teardown_service);
988 
989   g_test_add ("/account/connection", Test, NULL, setup_service,
990               test_connection, teardown_service);
991 
992   g_test_add ("/account/storage", Test, "first", setup_service, test_storage,
993       teardown_service);
994   g_test_add ("/account/storage", Test, "later", setup_service, test_storage,
995       teardown_service);
996 
997   g_test_add ("/account/avatar", Test, NULL, setup_service, test_avatar,
998       teardown_service);
999 
1000   g_test_add ("/account/addressing", Test, "first", setup_service,
1001       test_addressing, teardown_service);
1002   g_test_add ("/account/addressing", Test, "later", setup_service,
1003       test_addressing, teardown_service);
1004 
1005   return tp_tests_run_with_bus ();
1006 }
1007