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