]> Pileus Git - ~andy/gtk/blob - tests/autotestfilesystem.c
Replace a lot of idle and timeout calls by the new gdk_threads api.
[~andy/gtk] / tests / autotestfilesystem.c
1 /* GTK - The GIMP Toolkit
2  * autotestfilesystem.c: Automated tests for GtkFileSystem implementations
3  * Copyright (C) 2005, Novell, Inc.
4  *
5  * Authors:
6  *   Federico Mena-Quintero <federico@novell.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 #define GTK_FILE_SYSTEM_ENABLE_UNSUPPORTED
25
26 #include <config.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <glib/gprintf.h>
30 #include <gtk/gtk.h>
31 #include <gtk/gtkfilesystem.h>
32
33 #define CALLBACK_TIMEOUT_MS 3000        /* Period after which the callback must have been called */
34 #define CANCEL_TIMEOUT_MS 100           /* We'll sleep for this much time before cancelling */
35
36 #define GET_FOLDER_FILENAME "/etc"
37 #define GET_INFO_FILENAME "/etc/passwd"
38 #define CREATE_FOLDER_FILENAME "/tmp/autotestfilesystem-tmp"
39 #define VOLUME_MOUNT_FILENAME "/"
40
41 /* This is stolen from gtkfilechooserdefault.c:set_file_system_backend() */
42 static GtkFileSystem *
43 get_file_system (void)
44 {
45   GtkFileSystem *file_system = NULL;
46
47 #if 1
48   file_system = gtk_file_system_create ("gnome-vfs");
49 #else
50   GtkSettings *settings = gtk_settings_get_default ();
51   gchar *default_backend = NULL;
52
53   g_object_get (settings, "gtk-file-chooser-backend", &default_backend, NULL);
54   if (default_backend)
55     {
56       file_system = gtk_file_system_create (default_backend);
57       g_free (default_backend);
58     }
59
60   if (!file_system)
61     {
62 #if defined (G_OS_UNIX)
63       file_system = gtk_file_system_unix_new ();
64 #elif defined (G_OS_WIN32)
65       file_system = gtk_file_system_win32_new ();
66 #else
67 #error "No default filesystem implementation on the platform"
68 #endif
69     }
70
71 #endif
72
73   return file_system;
74 }
75
76 \f
77
78 /***** Testing infrastructure *****/
79
80 typedef struct {
81   gboolean callback_was_called;
82   gboolean timeout_was_called;
83 } TestCallbackClosure;
84
85 static void
86 notify_callback_called (TestCallbackClosure *closure)
87 {
88   closure->callback_was_called = TRUE;
89   gtk_main_quit ();
90 }
91
92 static gboolean
93 timeout_cb (gpointer data)
94 {
95   TestCallbackClosure *closure;
96
97   closure = data;
98
99   closure->timeout_was_called = TRUE;
100   gtk_main_quit ();
101
102   return FALSE;
103 }
104
105 static void
106 wait_for_callback (TestCallbackClosure *closure)
107 {
108   gdk_threads_add_timeout (CALLBACK_TIMEOUT_MS, timeout_cb, closure);
109   gtk_main ();
110 }
111
112 typedef struct {
113   const char *test_name;
114   gboolean callback_must_be_called;
115   gpointer (* setup_fn) (GtkFileSystem *file_system, gboolean *success, char **failure_reason,
116                          TestCallbackClosure *callback_closure);
117   void (* cleanup_fn) (gpointer data, gboolean *success, char **failure_reason);
118 } TestSpec;
119
120 static gboolean
121 run_test (TestSpec *test_spec)
122 {
123   GtkFileSystem *file_system;
124   TestCallbackClosure closure;
125   gboolean success_setup, success_cleanup;
126   gpointer test_data;
127   gboolean callback_success;
128   gboolean passed;
129   char *setup_failure_reason;
130   char *cleanup_failure_reason;
131
132   file_system = get_file_system ();
133   if (!file_system)
134     {
135       printf ("FAIL: test \"%s\"\n", test_spec->test_name);
136       printf ("      could not create file system!\n");
137       return FALSE;
138     }
139
140   closure.callback_was_called = FALSE;
141   closure.timeout_was_called = FALSE;
142
143   success_setup = success_cleanup = callback_success = FALSE;
144   setup_failure_reason = cleanup_failure_reason = NULL;
145
146   test_data = test_spec->setup_fn (file_system, &success_setup, &setup_failure_reason, &closure);
147   if (success_setup)
148     {
149       wait_for_callback (&closure);
150
151       test_spec->cleanup_fn (test_data, &success_cleanup, &cleanup_failure_reason);
152
153       callback_success = (test_spec->callback_must_be_called == closure.callback_was_called);
154     }
155
156   g_object_unref (file_system);
157
158   passed = (success_setup && success_cleanup && callback_success);
159
160   printf ("%s: test \"%s\"\n", passed ? "PASS" : "FAIL", test_spec->test_name);
161
162   if (!passed)
163     {
164       if (!success_setup)
165         printf ("      failure during setup: %s\n",
166                 setup_failure_reason ? setup_failure_reason : "unknown failure");
167       else
168         {
169           if (!success_cleanup)
170             printf ("      failure during cleanup: %s\n",
171                     cleanup_failure_reason ? cleanup_failure_reason : "unknown failure");
172
173           if (!callback_success)
174             printf ("      callback %s called but it %s called\n",
175                     test_spec->callback_must_be_called ? "MUST BE" : "MUST NOT BE",
176                     closure.callback_was_called ? "WAS" : "WAS NOT");
177         }
178     }
179
180   g_free (setup_failure_reason);
181   g_free (cleanup_failure_reason);
182
183   return passed;
184 }
185
186 static gboolean
187 run_tests (TestSpec *test_specs, int num_tests)
188 {
189   int i;
190   int num_passed;
191
192   num_passed = 0;
193
194   for (i = 0; i < num_tests; i++)
195     if (run_test (test_specs + i))
196       num_passed++;
197
198   if (num_passed == num_tests)
199     printf ("ALL TESTS PASSED\n");
200   else
201     printf ("%d of %d tests FAILED\n", (num_tests - num_passed), num_tests);
202
203   return (num_passed == num_tests);
204 }
205
206 \f
207
208 /***** Test functions *****/
209
210 static void
211 sleep_and_cancel_handle (GtkFileSystemHandle *handle)
212 {
213   g_usleep (CANCEL_TIMEOUT_MS * 1000);
214   gtk_file_system_cancel_operation (handle);
215 }
216
217 /* get_folder */
218
219 struct get_folder_data {
220   TestCallbackClosure *callback_closure;
221   GtkFileSystemHandle *handle;
222   GtkFileFolder *folder;
223 };
224
225 static void
226 get_folder_cb (GtkFileSystemHandle *handle,
227                GtkFileFolder       *folder,
228                const GError        *error,
229                gpointer             data)
230 {
231   struct get_folder_data *get_folder_data;
232
233   get_folder_data = data;
234   get_folder_data->folder = folder;
235   notify_callback_called (get_folder_data->callback_closure);
236 }
237
238 static gpointer
239 get_folder_generic_setup (GtkFileSystem *file_system, gboolean *success, char **failure_reason,
240                           TestCallbackClosure *callback_closure)
241 {
242   struct get_folder_data *get_folder_data;
243   GtkFilePath *path;
244
245   path = gtk_file_system_filename_to_path (file_system, GET_FOLDER_FILENAME);
246   if (!path)
247     {
248       *success = FALSE;
249       *failure_reason = g_strdup_printf ("could not turn \"%s\" into a GtkFilePath", GET_FOLDER_FILENAME);
250       return NULL;
251     }
252
253   get_folder_data = g_new (struct get_folder_data, 1);
254
255   get_folder_data->callback_closure = callback_closure;
256   get_folder_data->folder = NULL;
257
258   get_folder_data->handle = gtk_file_system_get_folder (file_system,
259                                                         path,
260                                                         GTK_FILE_INFO_ALL,
261                                                         get_folder_cb,
262                                                         get_folder_data);
263   gtk_file_path_free (path);
264
265   if (!get_folder_data->handle)
266     {
267       g_free (get_folder_data);
268       *success = FALSE;
269       *failure_reason = g_strdup ("gtk_file_system_get_folder() returned a NULL handle");
270       return NULL;
271     }
272
273   *success = TRUE;
274
275   return get_folder_data;
276 }
277
278 static gpointer
279 get_folder_no_cancel_setup (GtkFileSystem *file_system, gboolean *success, char **failure_reason,
280                             TestCallbackClosure *callback_closure)
281 {
282   return get_folder_generic_setup (file_system, success, failure_reason, callback_closure);
283 }
284
285 static void
286 get_folder_cleanup (gpointer data, gboolean *success, char **failure_reason)
287 {
288   struct get_folder_data *get_folder_data;
289
290   get_folder_data = data;
291
292   if (get_folder_data->folder)
293     g_object_unref (get_folder_data->folder);
294
295   g_free (get_folder_data);
296
297   *success = TRUE;
298 }
299
300 static gpointer
301 get_folder_with_cancel_setup (GtkFileSystem *file_system, gboolean *success, char **failure_reason,
302                               TestCallbackClosure *callback_closure)
303 {
304   struct get_folder_data *get_folder_data;
305
306   get_folder_data = get_folder_generic_setup (file_system, success, failure_reason, callback_closure);
307
308   if (*success)
309     sleep_and_cancel_handle (get_folder_data->handle);
310
311   return get_folder_data;
312 }
313
314 /* get_info */
315
316 struct get_info_data {
317   TestCallbackClosure *callback_closure;
318   GtkFileSystemHandle *handle;
319 };
320
321 static void
322 get_info_cb (GtkFileSystemHandle *handle,
323              const GtkFileInfo   *file_info,
324              const GError        *error,
325              gpointer             data)
326 {
327   struct get_info_data *get_info_data;
328
329   get_info_data = data;
330   notify_callback_called (get_info_data->callback_closure);
331 }
332
333 static gpointer
334 get_info_generic_setup (GtkFileSystem *file_system, gboolean *success, char **failure_reason,
335                         TestCallbackClosure *callback_closure)
336 {
337   GtkFilePath *path;
338   struct get_info_data *get_info_data;
339
340   path = gtk_file_system_filename_to_path (file_system, GET_INFO_FILENAME);
341   if (!path)
342     {
343       *success = FALSE;
344       *failure_reason = g_strdup_printf ("could not turn \"%s\" into a GtkFilePath", GET_INFO_FILENAME);
345       return NULL;
346     }
347
348   get_info_data = g_new (struct get_info_data, 1);
349
350   get_info_data->callback_closure = callback_closure;
351   get_info_data->handle = gtk_file_system_get_info (file_system,
352                                                     path,
353                                                     GTK_FILE_INFO_ALL,
354                                                     get_info_cb,
355                                                     get_info_data);
356   gtk_file_path_free (path);
357
358   if (!get_info_data->handle)
359     {
360       g_free (get_info_data);
361       *success = FALSE;
362       *failure_reason = g_strdup ("gtk_file_system_get_info() returned a NULL handle");
363       return NULL;
364     }
365
366   *success = TRUE;
367   return get_info_data;
368 }
369
370 static gpointer
371 get_info_no_cancel_setup (GtkFileSystem *file_system, gboolean *success, char **failure_reason,
372                           TestCallbackClosure *callback_closure)
373 {
374   return get_info_generic_setup (file_system, success, failure_reason, callback_closure);
375 }
376
377 static void
378 get_info_cleanup (gpointer data, gboolean *success, char **failure_reason)
379 {
380   struct get_info_data *get_info_data;
381
382   get_info_data = data;
383   g_free (get_info_data);
384
385   *success = TRUE;
386 }
387
388 static gpointer
389 get_info_with_cancel_setup (GtkFileSystem *file_system, gboolean *success, char **failure_reason,
390                             TestCallbackClosure *callback_closure)
391 {
392   struct get_info_data *get_info_data;
393
394   get_info_data = get_info_generic_setup (file_system, success, failure_reason, callback_closure);
395
396   if (*success)
397     sleep_and_cancel_handle (get_info_data->handle);
398
399   return get_info_data;
400 }
401
402 /* create_folder */
403
404 struct create_folder_data {
405   TestCallbackClosure *callback_closure;
406   GtkFileSystemHandle *handle;
407 };
408
409 static void
410 create_folder_cb (GtkFileSystemHandle *handle,
411                   const GtkFilePath   *path,
412                   const GError        *error,
413                   gpointer             data)
414 {
415   struct get_folder_data *get_folder_data;
416
417   get_folder_data = data;
418   notify_callback_called (get_folder_data->callback_closure);
419 }
420
421 static gpointer
422 create_folder_generic_setup (GtkFileSystem *file_system, gboolean *success, char **failure_reason,
423                              TestCallbackClosure *callback_closure)
424 {
425   GtkFilePath *path;
426   struct create_folder_data *create_folder_data;
427
428   path = gtk_file_system_filename_to_path (file_system, CREATE_FOLDER_FILENAME);
429   if (!path)
430     {
431       *success = FALSE;
432       *failure_reason = g_strdup_printf ("could not turn \"%s\" into a GtkFilePath", CREATE_FOLDER_FILENAME);
433       return NULL;
434     }
435
436   create_folder_data = g_new (struct create_folder_data, 1);
437
438   create_folder_data->callback_closure = callback_closure;
439   create_folder_data->handle = gtk_file_system_create_folder (file_system,
440                                                               path,
441                                                               create_folder_cb,
442                                                               create_folder_data);
443   gtk_file_path_free (path);
444
445   if (!create_folder_data->handle)
446     {
447       g_free (create_folder_data);
448       *success = FALSE;
449       *failure_reason = g_strdup ("gtk_file_system_create_folder() returned a NULL handle");
450       return NULL;
451     }
452
453   *success = TRUE;
454   return create_folder_data;
455 }
456
457 static gpointer
458 create_folder_no_cancel_setup (GtkFileSystem *file_system, gboolean *success, char **failure_reason,
459                                TestCallbackClosure *callback_closure)
460 {
461   return create_folder_generic_setup (file_system, success, failure_reason, callback_closure);
462 }
463
464 static void
465 create_folder_cleanup (gpointer data, gboolean *success, char **failure_reason)
466 {
467   struct create_folder_data *create_folder_data;
468
469   create_folder_data = data;
470
471   rmdir (CREATE_FOLDER_FILENAME);
472
473   g_free (create_folder_data);
474
475   *success = TRUE;
476 }
477
478 static gpointer
479 create_folder_with_cancel_setup (GtkFileSystem *file_system, gboolean *success, char **failure_reason,
480                                  TestCallbackClosure *callback_closure)
481 {
482   struct create_folder_data *create_folder_data;
483
484   create_folder_data = create_folder_generic_setup (file_system, success, failure_reason, callback_closure);
485
486   if (*success)
487     sleep_and_cancel_handle (create_folder_data->handle);
488
489   return create_folder_data;
490 }
491
492 /* volume_mount */
493
494 struct volume_mount_data {
495   TestCallbackClosure *callback_closure;
496   GtkFileSystemVolume *volume;
497   GtkFileSystemHandle *handle;
498 };
499
500 static void
501 volume_mount_cb (GtkFileSystemHandle *handle,
502                  GtkFileSystemVolume *volume,
503                  const GError        *error,
504                  gpointer             data)
505 {
506   struct volume_mount_data *volume_mount_data;
507
508   volume_mount_data = data;
509   notify_callback_called (volume_mount_data->callback_closure);
510 }
511
512 static gpointer
513 volume_mount_generic_setup (GtkFileSystem *file_system, gboolean *success, char **failure_reason,
514                             TestCallbackClosure *callback_closure)
515 {
516   GtkFilePath *path;
517   struct volume_mount_data *volume_mount_data;
518
519   path = gtk_file_system_filename_to_path (file_system, VOLUME_MOUNT_FILENAME);
520   if (!path)
521     {
522       *success = FALSE;
523       *failure_reason = g_strdup_printf ("could not turn \"%s\" into a GtkFilePath", VOLUME_MOUNT_FILENAME);
524       return NULL;
525     }
526
527   volume_mount_data = g_new (struct volume_mount_data, 1);
528
529   volume_mount_data->callback_closure = callback_closure;
530   volume_mount_data->volume = gtk_file_system_get_volume_for_path (file_system, path);
531   gtk_file_path_free (path);
532
533   if (!volume_mount_data->volume)
534     {
535       g_free (volume_mount_data);
536       *success = FALSE;
537       *failure_reason = g_strdup ("gtk_file_system_get_volume_for_path() returned a NULL volume");
538       return NULL;
539     }
540
541   volume_mount_data->handle = gtk_file_system_volume_mount (file_system,
542                                                             volume_mount_data->volume,
543                                                             volume_mount_cb,
544                                                             volume_mount_data);
545   if (!volume_mount_data->handle)
546     {
547       g_object_unref (volume_mount_data->volume);
548       g_free (volume_mount_data);
549       *success = FALSE;
550       *failure_reason = g_strdup ("gtk_file_system_volume_mount() returned a NULL handle");
551       return NULL;
552     }
553
554   *success = TRUE;
555   return volume_mount_data;
556 }
557
558 static gpointer
559 volume_mount_no_cancel_setup (GtkFileSystem *file_system, gboolean *success, char **failure_reason,
560                               TestCallbackClosure *callback_closure)
561 {
562   return volume_mount_generic_setup (file_system, success, failure_reason, callback_closure);
563 }
564
565 static void
566 volume_mount_cleanup (gpointer data, gboolean *success, char **failure_reason)
567 {
568   struct volume_mount_data *volume_mount_data;
569
570   volume_mount_data = data;
571
572   g_object_unref (volume_mount_data->volume);
573   g_free (volume_mount_data);
574
575   *success = TRUE;
576 }
577
578 static gpointer
579 volume_mount_with_cancel_setup (GtkFileSystem *file_system, gboolean *success, char **failure_reason,
580                                 TestCallbackClosure *callback_closure)
581 {
582   struct volume_mount_data *volume_mount_data;
583
584   volume_mount_data = volume_mount_generic_setup (file_system, success, failure_reason, callback_closure);
585
586   if (*success)
587     sleep_and_cancel_handle (volume_mount_data->handle);
588
589   return volume_mount_data;
590 }
591
592 /* tests */
593
594 static TestSpec tests[] = {
595   {
596     "get_folder no cancel",
597     TRUE,
598     get_folder_no_cancel_setup,
599     get_folder_cleanup
600   },
601   {
602     "get_folder with cancel",
603     FALSE,
604     get_folder_with_cancel_setup,
605     get_folder_cleanup
606   },
607   {
608     "get_info no cancel",
609     TRUE,
610     get_info_no_cancel_setup,
611     get_info_cleanup
612   },
613   {
614     "get_info with cancel",
615     FALSE,
616     get_info_with_cancel_setup,
617     get_info_cleanup
618   },
619   {
620     "create_folder no cancel",
621     TRUE,
622     create_folder_no_cancel_setup,
623     create_folder_cleanup
624   },
625   {
626     "create_folder with cancel",
627     FALSE,
628     create_folder_with_cancel_setup,
629     create_folder_cleanup
630   },
631   {
632     "volume_mount no cancel",
633     TRUE,
634     volume_mount_no_cancel_setup,
635     volume_mount_cleanup
636   },
637   {
638     "volume_mount with cancel",
639     FALSE,
640     volume_mount_with_cancel_setup,
641     volume_mount_cleanup
642   }
643 };
644
645 \f
646
647 /***** main *****/
648
649 static GLogFunc default_log_handler;
650 static int num_warnings;
651 static int num_errors;
652 static int num_critical_errors;
653
654 static void
655 log_override_cb (const gchar   *log_domain,
656                  GLogLevelFlags log_level,
657                  const gchar   *message,
658                  gpointer       user_data)
659 {
660   if (log_level & G_LOG_LEVEL_WARNING)
661     num_warnings++;
662
663   if (log_level & G_LOG_LEVEL_ERROR)
664     num_errors++;
665
666   if (log_level & G_LOG_LEVEL_CRITICAL)
667     num_critical_errors++;
668
669   (* default_log_handler) (log_domain, log_level, message, user_data);
670 }
671
672 static void
673 log_test (gboolean passed, const char *test_name, ...)
674 {
675   va_list args;
676   char *str;
677
678   va_start (args, test_name);
679   str = g_strdup_vprintf (test_name, args);
680   va_end (args);
681
682   g_printf ("%s: %s\n", passed ? "PASSED" : "FAILED", str);
683   g_free (str);
684 }
685
686 int
687 main (int argc, char **argv)
688 {
689   gboolean passed;
690   gboolean zero_warnings;
691   gboolean zero_errors;
692   gboolean zero_critical_errors;
693
694   default_log_handler = g_log_set_default_handler (log_override_cb, NULL);
695
696   gtk_init (&argc, &argv);
697
698   /* Start tests */
699
700   passed = run_tests (tests, G_N_ELEMENTS (tests));
701
702   /* Warnings and errors */
703
704   zero_warnings = num_warnings == 0;
705   zero_errors = num_errors == 0;
706   zero_critical_errors = num_critical_errors == 0;
707
708   log_test (zero_warnings, "main(): zero warnings (actual number %d)", num_warnings);
709   log_test (zero_errors, "main(): zero errors (actual number %d)", num_errors);
710   log_test (zero_critical_errors, "main(): zero critical errors (actual number %d)", num_critical_errors);
711
712   /* Done */
713
714   passed = passed && zero_warnings && zero_errors && zero_critical_errors;
715
716   log_test (passed, "main(): ALL TESTS");
717
718   return 0;
719 }