Merge remote-tracking branch 'gvdb/master'
[platform/upstream/glib.git] / gio / tests / mimeapps.c
1 #include <glib/gstdio.h>
2 #include <gio/gio.h>
3 #include <gio/gdesktopappinfo.h>
4
5 static gboolean
6 strv_equal (gchar **strv, ...)
7 {
8   gint count;
9   va_list list;
10   const gchar *str;
11   gboolean res;
12
13   res = TRUE;
14   count = 0;
15   va_start (list, strv);
16   while (1)
17     {
18       str = va_arg (list, const gchar *);
19       if (str == NULL)
20         break;
21       if (g_strcmp0 (str, strv[count]) != 0)
22         {
23           res = FALSE;
24           break;
25         }
26       count++;
27     }
28   va_end (list);
29
30   if (res)
31     res = g_strv_length (strv) == count;
32
33   return res;
34 }
35
36 const gchar *myapp_data =
37   "[Desktop Entry]\n"
38   "Encoding=UTF-8\n"
39   "Version=1.0\n"
40   "Type=Application\n"
41   "Exec=my_app %f\n"
42   "Name=my app\n";
43
44 const gchar *myapp2_data =
45   "[Desktop Entry]\n"
46   "Encoding=UTF-8\n"
47   "Version=1.0\n"
48   "Type=Application\n"
49   "Exec=my_app2 %f\n"
50   "Name=my app 2\n";
51
52 const gchar *myapp3_data =
53   "[Desktop Entry]\n"
54   "Encoding=UTF-8\n"
55   "Version=1.0\n"
56   "Type=Application\n"
57   "Exec=my_app3 %f\n"
58   "Name=my app 3\n";
59
60 const gchar *myapp4_data =
61   "[Desktop Entry]\n"
62   "Encoding=UTF-8\n"
63   "Version=1.0\n"
64   "Type=Application\n"
65   "Exec=my_app4 %f\n"
66   "Name=my app 4\n"
67   "MimeType=image/bmp;";
68
69 const gchar *myapp5_data =
70   "[Desktop Entry]\n"
71   "Encoding=UTF-8\n"
72   "Version=1.0\n"
73   "Type=Application\n"
74   "Exec=my_app5 %f\n"
75   "Name=my app 5\n"
76   "MimeType=image/bmp;";
77
78 const gchar *defaults_data =
79   "[Default Applications]\n"
80   "image/bmp=myapp4.desktop;\n"
81   "image/png=myapp3.desktop;\n";
82
83 const gchar *mimecache_data =
84   "[MIME Cache]\n"
85   "image/bmp=myapp4.desktop;myapp5.desktop;\n";
86
87 /* Set up XDG_DATA_HOME and XDG_DATA_DIRS.
88  * XDG_DATA_DIRS/applications will contain defaults.list
89  * XDG_DATA_HOME/applications will contain myapp.desktop
90  * and myapp2.desktop, and no mimeapps.list
91  */
92 static void
93 setup (void)
94 {
95   gchar *dir;
96   gchar *xdgdatahome;
97   gchar *xdgdatadir;
98   gchar *appdir;
99   gchar *apphome;
100   gchar *mimeapps;
101   gchar *name;
102   gboolean res;
103   GError *error = NULL;
104
105   dir = g_get_current_dir ();
106   xdgdatahome = g_build_filename (dir, "xdgdatahome", NULL);
107   xdgdatadir = g_build_filename (dir, "xdgdatadir", NULL);
108   g_test_message ("setting XDG_DATA_HOME to '%s'\n", xdgdatahome);
109   g_setenv ("XDG_DATA_HOME", xdgdatahome, TRUE);
110   g_test_message ("setting XDG_DATA_DIRS to '%s'\n", xdgdatadir);
111   g_setenv ("XDG_DATA_DIRS", xdgdatadir, TRUE);
112
113   appdir = g_build_filename (xdgdatadir, "applications", NULL);
114   g_test_message ("creating '%s'\n", appdir);
115   res = g_mkdir_with_parents (appdir, 0700);
116   g_assert (res == 0);
117
118   name = g_build_filename (appdir, "defaults.list", NULL);
119   g_test_message ("creating '%s'\n", name);
120   g_file_set_contents (name, defaults_data, -1, &error);
121   g_assert_no_error (error);
122   g_free (name);
123
124   apphome = g_build_filename (xdgdatahome, "applications", NULL);
125   g_test_message ("creating '%s'\n", apphome);
126   res = g_mkdir_with_parents (apphome, 0700);
127   g_assert (res == 0);
128
129   name = g_build_filename (apphome, "myapp.desktop", NULL);
130   g_test_message ("creating '%s'\n", name);
131   g_file_set_contents (name, myapp_data, -1, &error);
132   g_assert_no_error (error);
133   g_free (name);
134
135   name = g_build_filename (apphome, "myapp2.desktop", NULL);
136   g_test_message ("creating '%s'\n", name);
137   g_file_set_contents (name, myapp2_data, -1, &error);
138   g_assert_no_error (error);
139   g_free (name);
140
141   name = g_build_filename (apphome, "myapp3.desktop", NULL);
142   g_test_message ("creating '%s'\n", name);
143   g_file_set_contents (name, myapp3_data, -1, &error);
144   g_assert_no_error (error);
145   g_free (name);
146
147   name = g_build_filename (apphome, "myapp4.desktop", NULL);
148   g_test_message ("creating '%s'\n", name);
149   g_file_set_contents (name, myapp4_data, -1, &error);
150   g_assert_no_error (error);
151   g_free (name);
152
153   name = g_build_filename (apphome, "myapp5.desktop", NULL);
154   g_test_message ("creating '%s'\n", name);
155   g_file_set_contents (name, myapp5_data, -1, &error);
156   g_assert_no_error (error);
157   g_free (name);
158
159   mimeapps = g_build_filename (apphome, "mimeapps.list", NULL);
160   g_test_message ("removing '%s'\n", mimeapps);
161   g_remove (mimeapps);
162
163   name = g_build_filename (apphome, "mimeinfo.cache", NULL);
164   g_test_message ("creating '%s'\n", name);
165   g_file_set_contents (name, mimecache_data, -1, &error);
166   g_assert_no_error (error);
167   g_free (name);
168
169   g_free (dir);
170   g_free (xdgdatahome);
171   g_free (xdgdatadir);
172   g_free (apphome);
173   g_free (appdir);
174   g_free (mimeapps);
175 }
176
177 static void
178 test_mime_api (void)
179 {
180   GAppInfo *appinfo;
181   GAppInfo *appinfo2;
182   GError *error = NULL;
183   GAppInfo *def;
184   GList *list;
185   const gchar *contenttype = "application/pdf";
186
187   /* clear things out */
188   g_app_info_reset_type_associations (contenttype);
189
190   appinfo = (GAppInfo*)g_desktop_app_info_new ("myapp.desktop");
191   appinfo2 = (GAppInfo*)g_desktop_app_info_new ("myapp2.desktop");
192
193   def = g_app_info_get_default_for_type (contenttype, FALSE);
194   list = g_app_info_get_recommended_for_type (contenttype);
195   g_assert (def == NULL);
196   g_assert (list == NULL);
197
198   /* 1. add a non-default association */
199   g_app_info_add_supports_type (appinfo, contenttype, &error);
200   g_assert_no_error (error);
201
202   def = g_app_info_get_default_for_type (contenttype, FALSE);
203   list = g_app_info_get_recommended_for_type (contenttype);
204   g_assert (g_app_info_equal (def, appinfo));
205   g_assert_cmpint (g_list_length (list), ==, 1);
206   g_assert (g_app_info_equal ((GAppInfo*)list->data, appinfo));
207   g_object_unref (def);
208   g_list_free_full (list, g_object_unref);
209
210   /* 2. add another non-default association */
211   g_app_info_add_supports_type (appinfo2, contenttype, &error);
212   g_assert_no_error (error);
213
214   def = g_app_info_get_default_for_type (contenttype, FALSE);
215   list = g_app_info_get_recommended_for_type (contenttype);
216   g_assert (g_app_info_equal (def, appinfo));
217   g_assert_cmpint (g_list_length (list), ==, 2);
218   g_assert (g_app_info_equal ((GAppInfo*)list->data, appinfo));
219   g_assert (g_app_info_equal ((GAppInfo*)list->next->data, appinfo2));
220   g_object_unref (def);
221   g_list_free_full (list, g_object_unref);
222
223   /* 3. make the first app the default */
224   g_app_info_set_as_default_for_type (appinfo, contenttype, &error);
225   g_assert_no_error (error);
226
227   def = g_app_info_get_default_for_type (contenttype, FALSE);
228   list = g_app_info_get_recommended_for_type (contenttype);
229   g_assert (g_app_info_equal (def, appinfo));
230   g_assert_cmpint (g_list_length (list), ==, 2);
231   g_assert (g_app_info_equal ((GAppInfo*)list->data, appinfo));
232   g_assert (g_app_info_equal ((GAppInfo*)list->next->data, appinfo2));
233   g_object_unref (def);
234   g_list_free_full (list, g_object_unref);
235
236   /* 4. make the second app the last used one */
237   g_app_info_set_as_last_used_for_type (appinfo2, contenttype, &error);
238   g_assert_no_error (error);
239
240   def = g_app_info_get_default_for_type (contenttype, FALSE);
241   list = g_app_info_get_recommended_for_type (contenttype);
242   g_assert (g_app_info_equal (def, appinfo));
243   g_assert_cmpint (g_list_length (list), ==, 2);
244   g_assert (g_app_info_equal ((GAppInfo*)list->data, appinfo2));
245   g_assert (g_app_info_equal ((GAppInfo*)list->next->data, appinfo));
246   g_object_unref (def);
247   g_list_free_full (list, g_object_unref);
248
249   /* 5. reset everything */
250   g_app_info_reset_type_associations (contenttype);
251
252   def = g_app_info_get_default_for_type (contenttype, FALSE);
253   list = g_app_info_get_recommended_for_type (contenttype);
254   g_assert (def == NULL);
255   g_assert (list == NULL);
256
257   g_object_unref (appinfo);
258   g_object_unref (appinfo2);
259 }
260
261 /* Repeat the same tests, this time checking that we handle
262  * mimeapps.list as expected. These tests are different from
263  * the ones in test_mime_api() in that we directly parse
264  * mimeapps.list to verify the results.
265  */
266 static void
267 test_mime_file (void)
268 {
269   gchar **assoc;
270   GAppInfo *appinfo;
271   GAppInfo *appinfo2;
272   GError *error = NULL;
273   GKeyFile *keyfile;
274   gchar *str;
275   gboolean res;
276   GAppInfo *def;
277   GList *list;
278   gchar *mimeapps;
279   gchar *dir;
280   const gchar *contenttype = "application/pdf";
281
282   dir = g_get_current_dir ();
283   mimeapps = g_build_filename (dir, "xdgdatahome", "applications", "mimeapps.list", NULL);
284
285   /* clear things out */
286   g_app_info_reset_type_associations (contenttype);
287
288   appinfo = (GAppInfo*)g_desktop_app_info_new ("myapp.desktop");
289   appinfo2 = (GAppInfo*)g_desktop_app_info_new ("myapp2.desktop");
290
291   def = g_app_info_get_default_for_type (contenttype, FALSE);
292   list = g_app_info_get_recommended_for_type (contenttype);
293   g_assert (def == NULL);
294   g_assert (list == NULL);
295
296   /* 1. add a non-default association */
297   g_app_info_add_supports_type (appinfo, contenttype, &error);
298   g_assert_no_error (error);
299
300   keyfile = g_key_file_new ();
301   g_key_file_load_from_file (keyfile, mimeapps, G_KEY_FILE_NONE, &error);
302   g_assert_no_error (error);
303
304   assoc = g_key_file_get_string_list (keyfile, "Added Associations", contenttype, NULL, &error);
305   g_assert_no_error (error);
306   g_assert (strv_equal (assoc, "myapp.desktop", NULL));
307   g_strfreev (assoc);
308
309   /* we've unset XDG_DATA_DIRS so there should be no default */
310   assoc = g_key_file_get_string_list (keyfile, "Default Applications", contenttype, NULL, &error);
311   g_assert (error != NULL);
312   g_clear_error (&error);
313
314   g_key_file_free (keyfile);
315
316   /* 2. add another non-default association */
317   g_app_info_add_supports_type (appinfo2, contenttype, &error);
318   g_assert_no_error (error);
319
320   keyfile = g_key_file_new ();
321   g_key_file_load_from_file (keyfile, mimeapps, G_KEY_FILE_NONE, &error);
322   g_assert_no_error (error);
323
324   assoc = g_key_file_get_string_list (keyfile, "Added Associations", contenttype, NULL, &error);
325   g_assert_no_error (error);
326   g_assert (strv_equal (assoc, "myapp.desktop", "myapp2.desktop", NULL));
327   g_strfreev (assoc);
328
329   assoc = g_key_file_get_string_list (keyfile, "Default Applications", contenttype, NULL, &error);
330   g_assert (error != NULL);
331   g_clear_error (&error);
332
333   g_key_file_free (keyfile);
334
335   /* 3. make the first app the default */
336   g_app_info_set_as_default_for_type (appinfo, contenttype, &error);
337   g_assert_no_error (error);
338
339   keyfile = g_key_file_new ();
340   g_key_file_load_from_file (keyfile, mimeapps, G_KEY_FILE_NONE, &error);
341   g_assert_no_error (error);
342
343   assoc = g_key_file_get_string_list (keyfile, "Added Associations", contenttype, NULL, &error);
344   g_assert_no_error (error);
345   g_assert (strv_equal (assoc, "myapp.desktop", "myapp2.desktop", NULL));
346   g_strfreev (assoc);
347
348   str = g_key_file_get_string (keyfile, "Default Applications", contenttype, &error);
349   g_assert_no_error (error);
350   g_assert_cmpstr (str, ==, "myapp.desktop");
351
352   g_key_file_free (keyfile);
353
354   /* 4. make the second app the last used one */
355   g_app_info_set_as_last_used_for_type (appinfo2, contenttype, &error);
356   g_assert_no_error (error);
357
358   keyfile = g_key_file_new ();
359   g_key_file_load_from_file (keyfile, mimeapps, G_KEY_FILE_NONE, &error);
360   g_assert_no_error (error);
361
362   assoc = g_key_file_get_string_list (keyfile, "Added Associations", contenttype, NULL, &error);
363   g_assert_no_error (error);
364   g_assert (strv_equal (assoc, "myapp2.desktop", "myapp.desktop", NULL));
365   g_strfreev (assoc);
366
367   g_key_file_free (keyfile);
368
369   /* 5. reset everything */
370   g_app_info_reset_type_associations (contenttype);
371
372   keyfile = g_key_file_new ();
373   g_key_file_load_from_file (keyfile, mimeapps, G_KEY_FILE_NONE, &error);
374   g_assert_no_error (error);
375
376   res = g_key_file_has_key (keyfile, "Added Associations", contenttype, NULL);
377   g_assert (!res);
378
379   res = g_key_file_has_key (keyfile, "Default Applications", contenttype, NULL);
380   g_assert (!res);
381
382   g_key_file_free (keyfile);
383
384   g_object_unref (appinfo);
385   g_object_unref (appinfo2);
386
387   g_free (mimeapps);
388   g_free (dir);
389 }
390
391 /* test interaction between defaults.list and mimeapps.list */
392 static void
393 test_mime_default (void)
394 {
395   GAppInfo *appinfo;
396   GAppInfo *appinfo2;
397   GAppInfo *appinfo3;
398   GError *error = NULL;
399   GAppInfo *def;
400   GList *list;
401   const gchar *contenttype = "image/png";
402
403   /* clear things out */
404   g_app_info_reset_type_associations (contenttype);
405
406   appinfo = (GAppInfo*)g_desktop_app_info_new ("myapp.desktop");
407   appinfo2 = (GAppInfo*)g_desktop_app_info_new ("myapp2.desktop");
408   appinfo3 = (GAppInfo*)g_desktop_app_info_new ("myapp3.desktop");
409
410   /* myapp3 is set as the default in defaults.list */
411   def = g_app_info_get_default_for_type (contenttype, FALSE);
412   list = g_app_info_get_recommended_for_type (contenttype);
413   g_assert (g_app_info_equal (def, appinfo3));
414   g_assert_cmpint (g_list_length (list), ==, 1);
415   g_assert (g_app_info_equal ((GAppInfo*)list->data, appinfo3));
416   g_object_unref (def);
417   g_list_free_full (list, g_object_unref);
418
419   /* 1. add a non-default association */
420   g_app_info_add_supports_type (appinfo, contenttype, &error);
421   g_assert_no_error (error);
422
423   def = g_app_info_get_default_for_type (contenttype, FALSE);
424   list = g_app_info_get_recommended_for_type (contenttype);
425   g_assert (g_app_info_equal (def, appinfo3)); /* default is unaffected */
426   g_assert_cmpint (g_list_length (list), ==, 2);
427   g_assert (g_app_info_equal ((GAppInfo*)list->data, appinfo));
428   g_assert (g_app_info_equal ((GAppInfo*)list->next->data, appinfo3));
429   g_object_unref (def);
430   g_list_free_full (list, g_object_unref);
431
432   /* 2. add another non-default association */
433   g_app_info_add_supports_type (appinfo2, contenttype, &error);
434   g_assert_no_error (error);
435
436   def = g_app_info_get_default_for_type (contenttype, FALSE);
437   list = g_app_info_get_recommended_for_type (contenttype);
438   g_assert (g_app_info_equal (def, appinfo3));
439   g_assert_cmpint (g_list_length (list), ==, 3);
440   g_assert (g_app_info_equal ((GAppInfo*)list->data, appinfo));
441   g_assert (g_app_info_equal ((GAppInfo*)list->next->data, appinfo2));
442   g_assert (g_app_info_equal ((GAppInfo*)list->next->next->data, appinfo3));
443   g_object_unref (def);
444   g_list_free_full (list, g_object_unref);
445
446   /* 3. make the first app the default */
447   g_app_info_set_as_default_for_type (appinfo, contenttype, &error);
448   g_assert_no_error (error);
449
450   def = g_app_info_get_default_for_type (contenttype, FALSE);
451   list = g_app_info_get_recommended_for_type (contenttype);
452   g_assert (g_app_info_equal (def, appinfo));
453   g_assert_cmpint (g_list_length (list), ==, 3);
454   g_assert (g_app_info_equal ((GAppInfo*)list->data, appinfo));
455   g_assert (g_app_info_equal ((GAppInfo*)list->next->data, appinfo2));
456   g_assert (g_app_info_equal ((GAppInfo*)list->next->next->data, appinfo3));
457   g_object_unref (def);
458   g_list_free_full (list, g_object_unref);
459
460   g_object_unref (appinfo);
461   g_object_unref (appinfo2);
462   g_object_unref (appinfo3);
463 }
464
465 /* test interaction between mimeinfo.cache, defaults.list and mimeapps.list
466  * to ensure g_app_info_set_as_last_used_for_type doesn't incorrectly
467  * change the default
468  */
469 static void
470 test_mime_default_last_used (void)
471 {
472   GAppInfo *appinfo4;
473   GAppInfo *appinfo5;
474   GError *error = NULL;
475   GAppInfo *def;
476   GList *list;
477   const gchar *contenttype = "image/bmp";
478
479   /* clear things out */
480   g_app_info_reset_type_associations (contenttype);
481
482   appinfo4 = (GAppInfo*)g_desktop_app_info_new ("myapp4.desktop");
483   appinfo5 = (GAppInfo*)g_desktop_app_info_new ("myapp5.desktop");
484
485   /* myapp4 is set as the default in defaults.list */
486   /* myapp4 and myapp5 can both handle image/bmp */
487   def = g_app_info_get_default_for_type (contenttype, FALSE);
488   list = g_app_info_get_recommended_for_type (contenttype);
489   g_assert (g_app_info_equal (def, appinfo4));
490   g_assert_cmpint (g_list_length (list), ==, 2);
491   g_assert (g_app_info_equal ((GAppInfo*)list->data, appinfo4));
492   g_assert (g_app_info_equal ((GAppInfo*)list->next->data, appinfo5));
493   g_object_unref (def);
494   g_list_free_full (list, g_object_unref);
495
496   /* 1. set default (myapp4) as last used */
497   g_app_info_set_as_last_used_for_type (appinfo4, contenttype, &error);
498   g_assert_no_error (error);
499
500   def = g_app_info_get_default_for_type (contenttype, FALSE);
501   list = g_app_info_get_recommended_for_type (contenttype);
502   g_assert (g_app_info_equal (def, appinfo4)); /* default is unaffected */
503   g_assert_cmpint (g_list_length (list), ==, 2);
504   g_assert (g_app_info_equal ((GAppInfo*)list->data, appinfo4));
505   g_assert (g_app_info_equal ((GAppInfo*)list->next->data, appinfo5));
506   g_object_unref (def);
507   g_list_free_full (list, g_object_unref);
508
509   /* 2. set other (myapp5) as last used */
510   g_app_info_set_as_last_used_for_type (appinfo5, contenttype, &error);
511   g_assert_no_error (error);
512
513   def = g_app_info_get_default_for_type (contenttype, FALSE);
514   list = g_app_info_get_recommended_for_type (contenttype);
515   g_assert (g_app_info_equal (def, appinfo4));
516   g_assert_cmpint (g_list_length (list), ==, 2);
517   g_assert (g_app_info_equal ((GAppInfo*)list->data, appinfo5));
518   g_assert (g_app_info_equal ((GAppInfo*)list->next->data, appinfo4));
519   g_object_unref (def);
520   g_list_free_full (list, g_object_unref);
521
522   /* 3. change the default to myapp5 */
523   g_app_info_set_as_default_for_type (appinfo5, contenttype, &error);
524   g_assert_no_error (error);
525
526   def = g_app_info_get_default_for_type (contenttype, FALSE);
527   list = g_app_info_get_recommended_for_type (contenttype);
528   g_assert (g_app_info_equal (def, appinfo5));
529   g_assert_cmpint (g_list_length (list), ==, 2);
530   g_assert (g_app_info_equal ((GAppInfo*)list->data, appinfo5));
531   g_assert (g_app_info_equal ((GAppInfo*)list->next->data, appinfo4));
532   g_object_unref (def);
533   g_list_free_full (list, g_object_unref);
534
535   /* 4. set myapp4 as last used */
536   g_app_info_set_as_last_used_for_type (appinfo4, contenttype, &error);
537   g_assert_no_error (error);
538
539   def = g_app_info_get_default_for_type (contenttype, FALSE);
540   list = g_app_info_get_recommended_for_type (contenttype);
541   g_assert (g_app_info_equal (def, appinfo5));
542   g_assert_cmpint (g_list_length (list), ==, 2);
543   g_assert (g_app_info_equal ((GAppInfo*)list->data, appinfo4));
544   g_assert (g_app_info_equal ((GAppInfo*)list->next->data, appinfo5));
545   g_object_unref (def);
546   g_list_free_full (list, g_object_unref);
547
548   /* 5. set myapp5 as last used again */
549   g_app_info_set_as_last_used_for_type (appinfo5, contenttype, &error);
550   g_assert_no_error (error);
551
552   def = g_app_info_get_default_for_type (contenttype, FALSE);
553   list = g_app_info_get_recommended_for_type (contenttype);
554   g_assert (g_app_info_equal (def, appinfo5));
555   g_assert_cmpint (g_list_length (list), ==, 2);
556   g_assert (g_app_info_equal ((GAppInfo*)list->data, appinfo5));
557   g_assert (g_app_info_equal ((GAppInfo*)list->next->data, appinfo4));
558   g_object_unref (def);
559   g_list_free_full (list, g_object_unref);
560
561   g_object_unref (appinfo4);
562   g_object_unref (appinfo5);
563 }
564
565 int
566 main (int argc, char *argv[])
567 {
568   g_type_init ();
569   g_test_init (&argc, &argv, NULL);
570
571   setup ();
572
573   g_test_add_func ("/appinfo/mime/api", test_mime_api);
574   g_test_add_func ("/appinfo/mime/default", test_mime_default);
575   g_test_add_func ("/appinfo/mime/file", test_mime_file);
576   g_test_add_func ("/appinfo/mime/default_last_used", test_mime_default_last_used);
577
578   return g_test_run ();
579 }