ESourceRegistry: Do not mandate builtin sources.
[platform/upstream/evolution-data-server.git] / tests / libebook / client / client-test-utils.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2011, 2012 Red Hat, Inc. (www.redhat.com)
4  * Copyright (C) 2012 Intel Corporation
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of version 2 of the GNU Lesser General Public
8  * License as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this program; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  *
20  * Authors: Milan Crha <mcrha@redhat.com>
21  *          Matthew Barnes <mbarnes@redhat.com>
22  *          Tristan Van Berkom <tristanvb@openismus.com>
23  */
24
25 #include <stdio.h>
26 #include <stdlib.h>
27
28 #include <libedataserver/libedataserver.h>
29
30 #include "client-test-utils.h"
31
32 void
33 report_error (const gchar *operation,
34               GError **error)
35 {
36         g_return_if_fail (operation != NULL);
37
38         g_printerr ("Failed to %s: %s\n", operation, (error && *error) ? (*error)->message : "Unknown error");
39
40         g_clear_error (error);
41 }
42
43 void
44 print_email (EContact *contact)
45 {
46         const gchar *file_as = e_contact_get_const (contact, E_CONTACT_FILE_AS);
47         const gchar *name_or_org = e_contact_get_const (contact, E_CONTACT_NAME_OR_ORG);
48         GList *emails, *e;
49
50         g_print ("   Contact: %s\n", file_as);
51         g_print ("   Name or org: %s\n", name_or_org);
52         g_print ("   Email addresses:\n");
53         emails = e_contact_get (contact, E_CONTACT_EMAIL);
54         for (e = emails; e; e = e->next) {
55                 g_print ("\t%s\n",  (gchar *) e->data);
56         }
57         g_list_foreach (emails, (GFunc) g_free, NULL);
58         g_list_free (emails);
59
60         g_print ("\n");
61 }
62
63 EBookClient *
64 open_system_book (ESourceRegistry *registry,
65                   gboolean only_if_exists)
66 {
67         ESource *source;
68         EBookClient *book_client;
69         GError *error = NULL;
70
71         main_initialize ();
72
73         source = e_source_registry_ref_builtin_address_book (registry);
74         g_return_val_if_fail (source != NULL, NULL);
75         book_client = e_book_client_new (source, &error);
76         g_object_unref (source);
77
78         if (error) {
79                 report_error ("create system addressbook", &error);
80                 return NULL;
81         }
82
83         if (!e_client_open_sync (E_CLIENT (book_client), only_if_exists, NULL, &error)) {
84                 g_object_unref (book_client);
85                 report_error ("open client sync", &error);
86                 return NULL;
87         }
88
89         return book_client;
90 }
91
92 void
93 main_initialize (void)
94 {
95         static gboolean initialized = FALSE;
96
97         if (initialized)
98                 return;
99
100         g_type_init ();
101         e_gdbus_templates_init_main_thread ();
102
103         initialized = TRUE;
104 }
105
106 struct IdleData {
107         GThreadFunc func;
108         gpointer data;
109         gboolean run_in_thread; /* FALSE to run in idle callback */
110 };
111
112 static gboolean
113 idle_cb (gpointer data)
114 {
115         struct IdleData *idle = data;
116
117         g_return_val_if_fail (idle != NULL, FALSE);
118         g_return_val_if_fail (idle->func != NULL, FALSE);
119
120         if (idle->run_in_thread) {
121                 GThread *thread;
122
123                 thread = g_thread_new (NULL, idle->func, idle->data);
124                 g_thread_unref (thread);
125         } else {
126                 idle->func (idle->data);
127         }
128
129         g_free (idle);
130
131         return FALSE;
132 }
133
134 static GMainLoop *loop = NULL;
135 static gint main_stop_result = 0;
136
137 static void
138 do_start (GThreadFunc func,
139           gpointer data)
140 {
141         main_initialize ();
142
143         g_return_if_fail (loop == NULL);
144
145         loop = g_main_loop_new (NULL, FALSE);
146
147         if (func)
148                 func (data);
149
150         g_main_loop_run (loop);
151
152         g_main_loop_unref (loop);
153         loop = NULL;
154 }
155
156 /* Starts new main-loop, but just before that calls 'func'.
157  * Main-loop is kept running, and this function blocks,
158  * until call of stop_main_loop (). */
159 void
160 start_main_loop (GThreadFunc func,
161                  gpointer data)
162 {
163         g_return_if_fail (loop == NULL);
164
165         do_start (func, data);
166 }
167
168 /* Starts new main-loop and then invokes func in a new thread.
169  * Main-loop is kept running, and this function blocks,
170  * until call of stop_main_loop (). */
171 void
172 start_in_thread_with_main_loop (GThreadFunc func,
173                                 gpointer data)
174 {
175         struct IdleData *idle;
176
177         g_return_if_fail (func != NULL);
178         g_return_if_fail (loop == NULL);
179
180         main_initialize ();
181
182         idle = g_new0 (struct IdleData, 1);
183         idle->func = func;
184         idle->data = data;
185         idle->run_in_thread = TRUE;
186
187         g_idle_add (idle_cb, idle);
188
189         do_start (NULL, NULL);
190 }
191
192 /* Starts new main-loop and then invokes func in an idle callback.
193  * Main-loop is kept running, and this function blocks,
194  * until call of stop_main_loop (). */
195 void
196 start_in_idle_with_main_loop (GThreadFunc func,
197                               gpointer data)
198 {
199         struct IdleData *idle;
200
201         g_return_if_fail (func != NULL);
202         g_return_if_fail (loop == NULL);
203
204         main_initialize ();
205
206         idle = g_new0 (struct IdleData, 1);
207         idle->func = func;
208         idle->data = data;
209         idle->run_in_thread = FALSE;
210
211         g_idle_add (idle_cb, idle);
212
213         do_start (NULL, NULL);
214 }
215
216 /* Stops main-loop previously run by start_main_loop,
217  * start_in_thread_with_main_loop or start_in_idle_with_main_loop.
218 */
219 void
220 stop_main_loop (gint stop_result)
221 {
222         g_return_if_fail (loop != NULL);
223
224         main_stop_result = stop_result;
225         g_main_loop_quit (loop);
226 }
227
228 /* returns value used in stop_main_loop() */
229 gint
230 get_main_loop_stop_result (void)
231 {
232         return main_stop_result;
233 }
234
235 void
236 foreach_configured_source (ESourceRegistry *registry,
237                            void (*func) (ESource *source))
238 {
239         gpointer foreach_async_data;
240         ESource *source = NULL;
241
242         g_return_if_fail (func != NULL);
243
244         main_initialize ();
245
246         foreach_async_data = foreach_configured_source_async_start (registry, &source);
247         if (!foreach_async_data)
248                 return;
249
250         do {
251                 func (source);
252         } while (foreach_configured_source_async_next (&foreach_async_data, &source));
253 }
254
255 struct ForeachConfiguredData {
256         GList *list;
257 };
258
259 gpointer
260 foreach_configured_source_async_start (ESourceRegistry *registry,
261                                        ESource **source)
262 {
263         struct ForeachConfiguredData *async_data;
264         const gchar *extension_name;
265         GList *list;
266
267         g_return_val_if_fail (source != NULL, NULL);
268
269         main_initialize ();
270
271         extension_name = E_SOURCE_EXTENSION_ADDRESS_BOOK;
272         list = e_source_registry_list_sources (registry, extension_name);
273
274         async_data = g_new0 (struct ForeachConfiguredData, 1);
275         async_data->list = list;
276
277         *source = async_data->list->data;
278
279         return async_data;
280 }
281
282 gboolean
283 foreach_configured_source_async_next (gpointer *foreach_async_data,
284                                       ESource **source)
285 {
286         struct ForeachConfiguredData *async_data;
287
288         g_return_val_if_fail (foreach_async_data != NULL, FALSE);
289         g_return_val_if_fail (source != NULL, FALSE);
290
291         async_data = *foreach_async_data;
292         g_return_val_if_fail (async_data != NULL, FALSE);
293
294         if (async_data->list) {
295                 g_object_unref (async_data->list->data);
296                 async_data->list = async_data->list->next;
297         }
298         if (async_data->list) {
299                 *source = async_data->list->data;
300                 return TRUE;
301         }
302
303         g_free (async_data);
304
305         *foreach_async_data = NULL;
306
307         return FALSE;
308 }
309
310 typedef struct {
311         GMainLoop       *loop;
312         const gchar     *uid;
313         ESourceRegistry *registry;
314         ESource         *scratch;
315         ESource         *source;
316         EBookClient     *book;
317 } CreateBookData;
318
319 static gboolean
320 quit_idle (CreateBookData *data)
321 {
322         g_main_loop_quit (data->loop);
323         return FALSE;
324 }
325
326 static gboolean
327 create_book_idle (CreateBookData *data)
328 {
329         GError *error = NULL;
330
331         data->source = e_source_registry_ref_source (data->registry, data->uid);
332         if (!data->source)
333                 g_error ("Unable to fetch newly created source uid '%s' from the registry", data->uid);
334
335         data->book = e_book_client_new (data->source, &error);
336         if (!data->book)
337                 g_error ("Unable to create the book: %s", error->message);
338
339         g_idle_add ((GSourceFunc) quit_idle, data);
340
341         return FALSE;
342 }
343
344 static gboolean
345 register_source_idle (CreateBookData *data)
346 {
347         GError *error = NULL;
348         ESourceBackend  *backend;
349
350         data->registry = e_source_registry_new_sync (NULL, &error);
351         if (!data->registry)
352                 g_error ("Unable to create the registry: %s", error->message);
353
354         data->scratch = e_source_new_with_uid (data->uid, NULL, &error);
355         if (!data->scratch)
356                 g_error ("Failed to create source with uid '%s': %s", data->uid, error->message);
357
358         backend = e_source_get_extension (data->scratch, E_SOURCE_EXTENSION_ADDRESS_BOOK);
359         e_source_backend_set_backend_name (backend, "local");
360
361         if (!e_source_registry_commit_source_sync (data->registry, data->scratch, NULL, &error))
362                 g_error ("Unable to add new source to the registry for uid %s: %s", data->uid, error->message);
363
364         /* XXX e_source_registry_commit_source_sync isnt really sync... or else
365          * we could call e_source_registry_ref_source() immediately
366          */
367         g_timeout_add (20, (GSourceFunc) create_book_idle, data);
368
369         return FALSE;
370 }
371
372 static EBookClient *
373 ebook_test_utils_book_with_uid (const gchar *uid)
374 {
375         CreateBookData data = { 0, };
376
377         data.uid = uid;
378
379         data.loop = g_main_loop_new (NULL, FALSE);
380         g_idle_add ((GSourceFunc) register_source_idle, &data);
381         g_main_loop_run (data.loop);
382         g_main_loop_unref (data.loop);
383
384         g_object_unref (data.scratch);
385         g_object_unref (data.source);
386         g_object_unref (data.registry);
387
388         return data.book;
389 }
390
391 EBookClient *
392 new_temp_client (gchar **uri)
393 {
394         EBookClient     *book;
395         gchar           *uid;
396         guint64          real_time = g_get_real_time ();
397
398         uid  = g_strdup_printf ("test-book-%" G_GINT64_FORMAT, real_time);
399         book = ebook_test_utils_book_with_uid (uid);
400
401         if (uri)
402                 *uri = g_strdup (uid);
403
404         g_free (uid);
405
406         return book;
407 }
408
409 gchar *
410 new_vcard_from_test_case (const gchar *case_name)
411 {
412         gchar *filename;
413         gchar *case_filename;
414         GFile * file;
415         GError *error = NULL;
416         gchar *vcard;
417
418         case_filename = g_strdup_printf ("%s.vcf", case_name);
419         filename = g_build_filename (SRCDIR, "..", "data", "vcards", case_filename, NULL);
420         file = g_file_new_for_path (filename);
421         if (!g_file_load_contents (file, NULL, &vcard, NULL, NULL, &error)) {
422                 g_warning (
423                         "failed to read test contact file '%s': %s",
424                                 filename, error->message);
425                 exit (1);
426         }
427
428         g_free (case_filename);
429         g_free (filename);
430         g_object_unref (file);
431
432         return vcard;
433 }
434
435 static gboolean
436 contacts_are_equal_shallow (EContact *a,
437                             EContact *b)
438 {
439         const gchar *uid_a, *uid_b;
440
441         /* Avoid warnings if one or more are NULL, to make this function
442          * "NULL-friendly" */
443         if (!a && !b)
444                 return TRUE;
445
446         if (!E_IS_CONTACT (a) || !E_IS_CONTACT (b))
447                 return FALSE;
448
449         uid_a = e_contact_get_const (a, E_CONTACT_UID);
450         uid_b = e_contact_get_const (b, E_CONTACT_UID);
451
452         return g_strcmp0 (uid_a, uid_b) == 0;
453 }
454
455 gboolean
456 add_contact_from_test_case_verify (EBookClient *book_client,
457                                    const gchar *case_name,
458                                    EContact **contact)
459 {
460         gchar *vcard;
461         EContact *contact_orig;
462         EContact *contact_final;
463         gchar *uid;
464         GError *error = NULL;
465
466         vcard = new_vcard_from_test_case (case_name);
467         contact_orig = e_contact_new_from_vcard (vcard);
468         g_free (vcard);
469         if (!e_book_client_add_contact_sync (book_client, contact_orig, &uid, NULL, &error)) {
470                 report_error ("add contact sync", &error);
471                 g_object_unref (contact_orig);
472                 return FALSE;
473         }
474
475         e_contact_set (contact_orig, E_CONTACT_UID, uid);
476
477         if (!e_book_client_get_contact_sync (book_client, uid, &contact_final, NULL, &error)) {
478                 report_error ("get contact sync", &error);
479                 g_object_unref (contact_orig);
480                 g_free (uid);
481                 return FALSE;
482         }
483
484         /* verify the contact was added "successfully" (not thorough) */
485         g_assert (contacts_are_equal_shallow (contact_orig, contact_final));
486
487         if (contact)
488                 *contact = contact_final;
489         else
490                 g_object_unref (contact_final);
491         g_object_unref (contact_orig);
492         g_free (uid);
493
494         return TRUE;
495 }
496
497 gboolean
498 add_contact_verify (EBookClient *book_client,
499                     EContact *contact)
500 {
501         EContact *contact_final;
502         gchar *uid;
503         GError *error = NULL;
504
505         if (!e_book_client_add_contact_sync (book_client, contact, &uid, NULL, &error)) {
506                 report_error ("add contact sync", &error);
507                 return FALSE;
508         }
509
510         e_contact_set (contact, E_CONTACT_UID, uid);
511
512         if (!e_book_client_get_contact_sync (book_client, uid, &contact_final, NULL, &error)) {
513                 report_error ("get contact sync", &error);
514                 g_free (uid);
515                 return FALSE;
516         }
517
518         /* verify the contact was added "successfully" (not thorough) */
519         g_assert (contacts_are_equal_shallow (contact, contact_final));
520
521         g_object_unref (contact_final);
522         g_free (uid);
523
524         return TRUE;
525 }