1 /* Tests of TpTextChannel
2  *
3  * Copyright © 2010 Collabora Ltd. <http://www.collabora.co.uk/>
4  *
5  * Copying and distribution of this file, with or without modification,
6  * are permitted in any medium without royalty provided the copyright
7  * notice and this notice are preserved.
8  */
9 
10 #include "config.h"
11 
12 #include <string.h>
13 
14 #include <telepathy-glib/telepathy-glib.h>
15 #include <telepathy-glib/message-mixin.h>
16 
17 #include "examples/cm/contactlist/conn.h"
18 
19 #include "tests/lib/util.h"
20 
21 typedef struct {
22     GMainLoop *mainloop;
23     TpDBusDaemon *dbus;
24 
25     /* Service side objects */
26     TpBaseConnection *base_connection;
27     TpHandleRepoIface *contact_repo;
28 
29     /* Client side objects */
30     TpConnection *connection;
31     TpTextChannel *channel;
32     TpTextChannel *sms_channel;
33 
34     GPtrArray *blocked_added;
35     GPtrArray *blocked_removed;
36     TpContact *contact;
37 
38     GError *error /* initialized where needed */;
39     gint wait;
40 } Test;
41 
42 static void
setup(Test * test,gconstpointer data)43 setup (Test *test,
44        gconstpointer data)
45 {
46   gchar *conn_name, *conn_path;
47   GQuark conn_features[] = { TP_CONNECTION_FEATURE_CONNECTED, 0 };
48 
49   test->mainloop = g_main_loop_new (NULL, FALSE);
50   test->dbus = tp_tests_dbus_daemon_dup_or_die ();
51 
52   test->error = NULL;
53 
54   /* Create (service and client sides) connection objects */
55   test->base_connection = tp_tests_object_new_static_class (
56         EXAMPLE_TYPE_CONTACT_LIST_CONNECTION,
57         "account", "me@test.com",
58         "simulation-delay", 0,
59         "protocol", "test",
60         NULL);
61 
62   g_assert (tp_base_connection_register (test->base_connection, "example",
63         &conn_name, &conn_path, &test->error));
64   g_assert_no_error (test->error);
65 
66   test->connection = tp_connection_new (test->dbus, conn_name, conn_path,
67       &test->error);
68   g_assert_no_error (test->error);
69 
70   test->contact_repo = tp_base_connection_get_handles (test->base_connection,
71       TP_HANDLE_TYPE_CONTACT);
72   g_assert (test->contact_repo != NULL);
73 
74   /* Connect the connection */
75   tp_cli_connection_call_connect (test->connection, -1, NULL, NULL, NULL, NULL);
76   tp_tests_proxy_run_until_prepared (test->connection, conn_features);
77 
78   g_free (conn_name);
79   g_free (conn_path);
80 }
81 
82 static void
teardown(Test * test,gconstpointer data)83 teardown (Test *test,
84           gconstpointer data)
85 {
86   g_clear_error (&test->error);
87 
88   tp_clear_object (&test->dbus);
89   g_main_loop_unref (test->mainloop);
90   test->mainloop = NULL;
91 
92   tp_tests_connection_assert_disconnect_succeeds (test->connection);
93   g_object_unref (test->connection);
94   g_object_unref (test->base_connection);
95 
96   tp_clear_pointer (&test->blocked_added, g_ptr_array_unref);
97   tp_clear_pointer (&test->blocked_removed, g_ptr_array_unref);
98   g_clear_object (&test->contact);
99 }
100 
101 static void
block_contacts_cb(GObject * source,GAsyncResult * result,gpointer user_data)102 block_contacts_cb (GObject *source,
103     GAsyncResult *result,
104     gpointer user_data)
105 {
106   Test *test = user_data;
107 
108   tp_connection_block_contacts_finish (TP_CONNECTION (source), result,
109       &test->error);
110   g_assert_no_error (test->error);
111 
112   test->wait--;
113   if (test->wait <= 0)
114     g_main_loop_quit (test->mainloop);
115 }
116 
117 static void
unblock_contacts_cb(GObject * source,GAsyncResult * result,gpointer user_data)118 unblock_contacts_cb (GObject *source,
119     GAsyncResult *result,
120     gpointer user_data)
121 {
122   Test *test = user_data;
123 
124   tp_connection_unblock_contacts_finish (TP_CONNECTION (source), result,
125       &test->error);
126   g_assert_no_error (test->error);
127 
128   test->wait--;
129   if (test->wait <= 0)
130     g_main_loop_quit (test->mainloop);
131 }
132 
133 static void
contact_block_cb(GObject * source,GAsyncResult * result,gpointer user_data)134 contact_block_cb (GObject *source,
135     GAsyncResult *result,
136     gpointer user_data)
137 {
138   Test *test = user_data;
139 
140   tp_contact_block_finish (TP_CONTACT (source), result, &test->error);
141   g_assert_no_error (test->error);
142 
143   test->wait--;
144   if (test->wait <= 0)
145     g_main_loop_quit (test->mainloop);
146 }
147 
148 static void
contact_unblock_cb(GObject * source,GAsyncResult * result,gpointer user_data)149 contact_unblock_cb (GObject *source,
150     GAsyncResult *result,
151     gpointer user_data)
152 {
153   Test *test = user_data;
154 
155   tp_contact_unblock_finish (TP_CONTACT (source), result, &test->error);
156   g_assert_no_error (test->error);
157 
158   test->wait--;
159   if (test->wait <= 0)
160     g_main_loop_quit (test->mainloop);
161 }
162 
163 static TpContact *
create_contact(Test * test,const gchar * id)164 create_contact (Test *test,
165     const gchar *id)
166 {
167   TpHandle handle;
168   TpContact *contact;
169 
170   handle = tp_handle_ensure (test->contact_repo, id, NULL, &test->error);
171   g_assert_no_error (test->error);
172 
173   contact = tp_connection_dup_contact_if_possible (test->connection, handle,
174       id);
175   g_assert (contact != NULL);
176 
177   return contact;
178 }
179 
180 static void
test_block_unblock(Test * test,gconstpointer data G_GNUC_UNUSED)181 test_block_unblock (Test *test,
182     gconstpointer data G_GNUC_UNUSED)
183 {
184   TpContact *alice, *bob;
185   GPtrArray *arr;
186 
187   alice = create_contact (test, "alice");
188   bob = create_contact (test, "bob");
189 
190   arr = g_ptr_array_sized_new (2);
191   g_ptr_array_add (arr, alice);
192   g_ptr_array_add (arr, bob);
193 
194   /* Block contacts */
195   tp_connection_block_contacts_async (test->connection,
196       arr->len, (TpContact * const *) arr->pdata, FALSE,
197       block_contacts_cb, test);
198 
199   test->wait = 1;
200   g_main_loop_run (test->mainloop);
201   g_assert_no_error (test->error);
202 
203   /* Unblock contacts */
204   tp_connection_unblock_contacts_async (test->connection,
205       arr->len, (TpContact * const *) arr->pdata,
206       unblock_contacts_cb, test);
207 
208   test->wait = 1;
209   g_main_loop_run (test->mainloop);
210   g_assert_no_error (test->error);
211 
212   g_object_unref (alice);
213   g_object_unref (bob);
214   g_ptr_array_unref (arr);
215 }
216 
217 static void
proxy_prepare_cb(GObject * source,GAsyncResult * result,gpointer user_data)218 proxy_prepare_cb (GObject *source,
219     GAsyncResult *result,
220     gpointer user_data)
221 {
222   Test *test = user_data;
223 
224   tp_proxy_prepare_finish (source, result, &test->error);
225 
226   test->wait--;
227   if (test->wait <= 0)
228     g_main_loop_quit (test->mainloop);
229 }
230 
231 static void
test_can_report_abusive(Test * test,gconstpointer data G_GNUC_UNUSED)232 test_can_report_abusive (Test *test,
233     gconstpointer data G_GNUC_UNUSED)
234 {
235   GQuark features[] = { TP_CONNECTION_FEATURE_CONTACT_BLOCKING, 0 };
236   gboolean abuse;
237 
238   /* Feature is not prepared yet */
239   g_object_get (test->connection, "can-report-abusive", &abuse, NULL);
240   g_assert (!abuse);
241   g_assert (!tp_connection_can_report_abusive (test->connection));
242 
243   tp_proxy_prepare_async (test->connection, features,
244       proxy_prepare_cb, test);
245 
246   test->wait = 1;
247   g_main_loop_run (test->mainloop);
248   g_assert_no_error (test->error);
249 
250   g_assert (tp_proxy_is_prepared (test->connection,
251         TP_CONNECTION_FEATURE_CONTACT_BLOCKING));
252 
253   g_object_get (test->connection, "can-report-abusive", &abuse, NULL);
254   g_assert (abuse);
255   g_assert (tp_connection_can_report_abusive (test->connection));
256 }
257 
258 static void
blocked_contacts_changed_cb(TpConnection * conn,GPtrArray * added,GPtrArray * removed,Test * test)259 blocked_contacts_changed_cb (TpConnection *conn,
260     GPtrArray *added,
261     GPtrArray *removed,
262     Test *test)
263 {
264   tp_clear_pointer (&test->blocked_added, g_ptr_array_unref);
265   tp_clear_pointer (&test->blocked_removed, g_ptr_array_unref);
266 
267   test->blocked_added = g_ptr_array_ref (added);
268   test->blocked_removed = g_ptr_array_ref (removed);
269 
270   test->wait--;
271   if (test->wait <= 0)
272     g_main_loop_quit (test->mainloop);
273 }
274 
275 static void
test_blocked_contacts(Test * test,gconstpointer data G_GNUC_UNUSED)276 test_blocked_contacts (Test *test,
277     gconstpointer data G_GNUC_UNUSED)
278 {
279   GQuark features[] = { TP_CONNECTION_FEATURE_CONTACT_BLOCKING, 0 };
280   GPtrArray *blocked;
281   TpContact *alice, *bill, *guillaume, *sjoerd, *steve;
282   gboolean use_contact_api = GPOINTER_TO_UINT (data);
283 
284   sjoerd = create_contact (test, "sjoerd@example.com");
285   steve = create_contact (test, "steve@example.com");
286 
287   /* Feature is not prepared yet */
288   g_object_get (test->connection, "blocked-contacts", &blocked, NULL);
289   g_assert_cmpuint (blocked->len, == , 0);
290   g_ptr_array_unref (blocked);
291 
292   blocked = tp_connection_get_blocked_contacts (test->connection);
293   g_assert_cmpuint (blocked->len, == , 0);
294 
295   /* Prepare the feature */
296   tp_proxy_prepare_async (test->connection, features,
297       proxy_prepare_cb, test);
298 
299   test->wait = 1;
300   g_main_loop_run (test->mainloop);
301   g_assert_no_error (test->error);
302 
303   /* 2 contacts are already blocked in the CM */
304   g_object_get (test->connection, "blocked-contacts", &blocked, NULL);
305   g_assert_cmpuint (blocked->len, == , 2);
306   g_ptr_array_unref (blocked);
307 
308   blocked = tp_connection_get_blocked_contacts (test->connection);
309   g_assert_cmpuint (blocked->len, == , 2);
310 
311   /* Preparing TP_CONNECTION_FEATURE_CONTACT_BLOCKING gives us
312    * TP_CONTACT_FEATURE_CONTACT_BLOCKING for free. Test that this works with
313    * existing and newly created TpContact. */
314   bill = create_contact (test, "bill@example.com");
315   guillaume = create_contact (test, "guillaume@example.com");
316 
317   g_assert (tp_contact_has_feature (sjoerd,
318         TP_CONTACT_FEATURE_CONTACT_BLOCKING));
319   g_assert (!tp_contact_is_blocked (sjoerd));
320 
321   g_assert (tp_contact_has_feature (steve,
322         TP_CONTACT_FEATURE_CONTACT_BLOCKING));
323   g_assert (tp_contact_is_blocked (steve));
324 
325   g_assert (tp_contact_has_feature (bill, TP_CONTACT_FEATURE_CONTACT_BLOCKING));
326   g_assert (tp_contact_is_blocked (bill));
327 
328   g_assert (tp_contact_has_feature (guillaume,
329         TP_CONTACT_FEATURE_CONTACT_BLOCKING));
330   g_assert (!tp_contact_is_blocked (guillaume));
331 
332   g_object_unref (steve);
333   g_object_unref (sjoerd);
334   g_object_unref (bill);
335   g_object_unref (guillaume);
336 
337   /* Let's block another contact */
338   alice = create_contact (test, "alice");
339 
340   g_signal_connect (test->connection, "blocked-contacts-changed",
341       G_CALLBACK (blocked_contacts_changed_cb), test);
342 
343   if (use_contact_api)
344     {
345       tp_contact_block_async (alice, FALSE, contact_block_cb, test);
346     }
347   else
348     {
349       tp_connection_block_contacts_async (test->connection,
350           1,  &alice, FALSE, block_contacts_cb, test);
351     }
352 
353   g_object_unref (alice);
354 
355   test->wait = 2;
356   g_main_loop_run (test->mainloop);
357   g_assert_no_error (test->error);
358 
359   g_assert_cmpuint (test->blocked_added->len, ==, 1);
360   g_assert_cmpuint (test->blocked_removed->len, ==, 0);
361 
362   alice = g_ptr_array_index (test->blocked_added, 0);
363   g_assert (TP_IS_CONTACT (alice));
364   g_assert_cmpstr (tp_contact_get_identifier (alice), ==, "alice");
365 
366   blocked = tp_connection_get_blocked_contacts (test->connection);
367   g_assert_cmpuint (blocked->len, == , 3);
368 
369   /* Cool, now unblock the poor Alice */
370   if (use_contact_api)
371     {
372       tp_contact_unblock_async (alice, contact_unblock_cb, test);
373     }
374   else
375     {
376       tp_connection_unblock_contacts_async (test->connection,
377           1,  &alice, unblock_contacts_cb, test);
378     }
379 
380   test->wait = 2;
381   g_main_loop_run (test->mainloop);
382   g_assert_no_error (test->error);
383 
384   g_assert_cmpuint (test->blocked_added->len, ==, 0);
385   g_assert_cmpuint (test->blocked_removed->len, ==, 1);
386 
387   alice = g_ptr_array_index (test->blocked_removed, 0);
388   g_assert (TP_IS_CONTACT (alice));
389   g_assert_cmpstr (tp_contact_get_identifier (alice), ==, "alice");
390 
391   blocked = tp_connection_get_blocked_contacts (test->connection);
392   g_assert_cmpuint (blocked->len, == , 2);
393 }
394 
395 static void
get_contacts_by_id_cb(TpConnection * connection,guint n_contacts,TpContact * const * contacts,const gchar * const * requested_ids,GHashTable * failed_id_errors,const GError * error,gpointer user_data,GObject * weak_object)396 get_contacts_by_id_cb (TpConnection *connection,
397     guint n_contacts,
398     TpContact * const *contacts,
399     const gchar * const *requested_ids,
400     GHashTable *failed_id_errors,
401     const GError *error,
402     gpointer user_data,
403     GObject *weak_object)
404 {
405   Test *test = user_data;
406 
407   g_clear_object (&test->contact);
408 
409   if (error != NULL)
410     {
411       test->error = g_error_copy (error);
412     }
413   else
414     {
415       test->contact = g_object_ref (contacts[0]);
416     }
417 
418   test->wait--;
419   if (test->wait <= 0)
420     g_main_loop_quit (test->mainloop);
421 }
422 
423 static void
contact_list_state_change_cb(GObject * object,GParamSpec * pspec,gpointer user_data)424 contact_list_state_change_cb (GObject *object,
425     GParamSpec *pspec,
426     gpointer user_data)
427 {
428   TpConnection *conn = (TpConnection *) object;
429   Test *test = user_data;
430 
431   if (tp_connection_get_contact_list_state (conn) !=
432       TP_CONTACT_LIST_STATE_SUCCESS)
433     return;
434 
435   test->wait--;
436   if (test->wait <= 0)
437     g_main_loop_quit (test->mainloop);
438 }
439 
440 static void
property_change_cb(GObject * object,GParamSpec * pspec,gpointer user_data)441 property_change_cb (GObject *object,
442     GParamSpec *pspec,
443     gpointer user_data)
444 {
445   Test *test = user_data;
446 
447   test->wait--;
448   if (test->wait <= 0)
449     g_main_loop_quit (test->mainloop);
450 }
451 
452 static void
test_is_blocked(Test * test,gconstpointer data G_GNUC_UNUSED)453 test_is_blocked (Test *test,
454     gconstpointer data G_GNUC_UNUSED)
455 {
456   const gchar *id = "bill@example.com";
457   TpContactFeature features[] = { TP_CONTACT_FEATURE_CONTACT_BLOCKING };
458   GQuark conn_features[] = { TP_CONNECTION_FEATURE_CONTACT_LIST, 0 };
459 
460   tp_proxy_prepare_async (test->connection, conn_features,
461       proxy_prepare_cb, test);
462 
463   test->wait = 1;
464 
465   /* We have to wait that the ContactList has been fetched by the CM */
466   if (tp_connection_get_contact_list_state (test->connection) !=
467       TP_CONTACT_LIST_STATE_SUCCESS)
468     {
469       g_signal_connect (test->connection, "notify::contact-list-state",
470           G_CALLBACK (contact_list_state_change_cb), test);
471 
472       test->wait++;
473     }
474 
475   g_main_loop_run (test->mainloop);
476   g_assert_no_error (test->error);
477 
478   /* Bill is already blocked in the CM */
479   tp_connection_get_contacts_by_id (test->connection, 1, &id,
480       G_N_ELEMENTS (features), features, get_contacts_by_id_cb, test,
481       NULL, NULL);
482 
483   test->wait = 1;
484   g_main_loop_run (test->mainloop);
485   g_assert_no_error (test->error);
486 
487   g_assert (TP_IS_CONTACT (test->contact));
488 
489   g_assert (tp_contact_has_feature (test->contact,
490         TP_CONTACT_FEATURE_CONTACT_BLOCKING));
491   g_assert (tp_contact_is_blocked (test->contact));
492 
493   /* Unblock Bill */
494   g_signal_connect (test->contact, "notify::is-blocked",
495       G_CALLBACK (property_change_cb), test);
496 
497   tp_contact_unblock_async (test->contact, contact_unblock_cb, test);
498 
499   test->wait = 2;
500   g_main_loop_run (test->mainloop);
501   g_assert_no_error (test->error);
502 
503   g_assert (!tp_contact_is_blocked (test->contact));
504 }
505 
506 static void
test_contact_list_properties(Test * test,gconstpointer data G_GNUC_UNUSED)507 test_contact_list_properties (Test *test,
508     gconstpointer data G_GNUC_UNUSED)
509 {
510   gboolean props_only = GPOINTER_TO_UINT (data);
511   GQuark conn_features[] = { 0, 0 };
512   GPtrArray *contacts;
513 
514   if (props_only)
515     conn_features[0] = TP_CONNECTION_FEATURE_CONTACT_LIST_PROPERTIES;
516   else
517     conn_features[0] = TP_CONNECTION_FEATURE_CONTACT_LIST;
518 
519   /* Feature isn't prepared yet */
520   g_assert (!tp_proxy_is_prepared (test->connection,
521         TP_CONNECTION_FEATURE_CONTACT_LIST));
522   g_assert (!tp_proxy_is_prepared (test->connection,
523         TP_CONNECTION_FEATURE_CONTACT_LIST_PROPERTIES));
524 
525   g_assert_cmpuint (tp_connection_get_contact_list_state (test->connection), ==,
526       TP_CONTACT_LIST_STATE_NONE);
527   g_assert (!tp_connection_get_contact_list_persists (test->connection));
528   g_assert (!tp_connection_get_can_change_contact_list (test->connection));
529   g_assert (!tp_connection_get_request_uses_message (test->connection));
530 
531   tp_proxy_prepare_async (test->connection, conn_features,
532       proxy_prepare_cb, test);
533 
534   test->wait = 1;
535   g_main_loop_run (test->mainloop);
536   g_assert_no_error (test->error);
537 
538   g_assert (tp_proxy_is_prepared (test->connection,
539         TP_CONNECTION_FEATURE_CONTACT_LIST) == !props_only);
540   g_assert (tp_proxy_is_prepared (test->connection,
541         TP_CONNECTION_FEATURE_CONTACT_LIST_PROPERTIES));
542 
543   g_assert (tp_connection_get_contact_list_persists (test->connection));
544   g_assert (tp_connection_get_can_change_contact_list (test->connection));
545   g_assert (tp_connection_get_request_uses_message (test->connection));
546 
547   contacts = tp_connection_dup_contact_list (test->connection);
548   if (props_only)
549     {
550       /* Contacts haven't be fetched */
551       g_assert_cmpuint (contacts->len, ==, 0);
552     }
553   else
554     {
555       g_assert_cmpuint (contacts->len, >, 0);
556     }
557   g_ptr_array_unref (contacts);
558 }
559 
560 int
main(int argc,char ** argv)561 main (int argc,
562       char **argv)
563 {
564   tp_tests_init (&argc, &argv);
565   g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id=");
566 
567   g_test_add ("/contact-list-client/blocking/block-unblock", Test, NULL, setup,
568       test_block_unblock, teardown);
569   g_test_add ("/contact-list-client/blocking/can-report-abusive", Test, NULL,
570       setup, test_can_report_abusive, teardown);
571   g_test_add ("/contact-list-client/blocking/connection/blocked-contacts", Test,
572       GUINT_TO_POINTER (FALSE), setup, test_blocked_contacts, teardown);
573   g_test_add ("/contact-list-client/blocking/contact/blocked-contacts", Test,
574       GUINT_TO_POINTER (TRUE), setup, test_blocked_contacts, teardown);
575   g_test_add ("/contact-list-client/blocking/is-blocked", Test, NULL,
576       setup, test_is_blocked, teardown);
577 
578   g_test_add ("/contact-list-client/contact-list/properties", Test,
579       GUINT_TO_POINTER (FALSE), setup, test_contact_list_properties, teardown);
580   g_test_add ("/contact-list-client/contact-list/properties", Test,
581       GUINT_TO_POINTER (TRUE), setup, test_contact_list_properties, teardown);
582 
583   return tp_tests_run_with_bus ();
584 }
585