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