Change LGPL-2.1+ to LGPL-2.1-or-later
[platform/upstream/glib.git] / gio / tests / appmonitor.c
1 /* GLib testing framework examples and tests
2  *
3  * Copyright © 2013 Red Hat, Inc.
4  * Copyright © 2015, 2017, 2018 Endless Mobile, Inc.
5  *
6  * SPDX-License-Identifier: LGPL-2.1-or-later
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.1 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
19  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include <gio/gio.h>
23 #include <gstdio.h>
24
25 #if defined (G_OS_UNIX) && !defined (__APPLE__)
26 #include <gio/gdesktopappinfo.h>
27 #endif
28
29 typedef struct
30 {
31   gchar *applications_dir;
32 } Fixture;
33
34 static void
35 setup (Fixture       *fixture,
36        gconstpointer  user_data)
37 {
38   fixture->applications_dir = g_build_filename (g_get_user_data_dir (), "applications", NULL);
39   g_assert_no_errno (g_mkdir_with_parents (fixture->applications_dir, 0755));
40
41   g_test_message ("Using data directory: %s", g_get_user_data_dir ());
42 }
43
44 static void
45 teardown (Fixture       *fixture,
46           gconstpointer  user_data)
47 {
48   g_assert_no_errno (g_rmdir (fixture->applications_dir));
49   g_clear_pointer (&fixture->applications_dir, g_free);
50 }
51
52 #if defined (G_OS_UNIX) && !defined (__APPLE__)
53 static gboolean
54 create_app (gpointer data)
55 {
56   const gchar *path = data;
57   GError *error = NULL;
58   const gchar *contents = 
59     "[Desktop Entry]\n"
60     "Name=Application\n"
61     "Version=1.0\n"
62     "Type=Application\n"
63     "Exec=true\n";
64
65   g_file_set_contents (path, contents, -1, &error);
66   g_assert_no_error (error);
67
68   return G_SOURCE_REMOVE;
69 }
70
71 static void
72 delete_app (gpointer data)
73 {
74   const gchar *path = data;
75
76   g_remove (path);
77 }
78
79 static void
80 changed_cb (GAppInfoMonitor *monitor,
81             gpointer         user_data)
82 {
83   gboolean *changed_fired = user_data;
84
85   *changed_fired = TRUE;
86   g_main_context_wakeup (g_main_context_get_thread_default ());
87 }
88
89 static gboolean
90 timeout_cb (gpointer user_data)
91 {
92   gboolean *timed_out = user_data;
93
94   g_assert (!timed_out);
95   *timed_out = TRUE;
96   g_main_context_wakeup (g_main_context_get_thread_default ());
97
98   return G_SOURCE_REMOVE;
99 }
100 #endif  /* defined (G_OS_UNIX) && !defined (__APPLE__) */
101
102 static void
103 test_app_monitor (Fixture       *fixture,
104                   gconstpointer  user_data)
105 {
106 #if defined (G_OS_UNIX) && !defined (__APPLE__)
107   gchar *app_path;
108   GAppInfoMonitor *monitor;
109   GMainContext *context = NULL;  /* use the global default main context */
110   GSource *timeout_source = NULL;
111   GDesktopAppInfo *app = NULL;
112   gboolean changed_fired = FALSE;
113   gboolean timed_out = FALSE;
114
115   app_path = g_build_filename (fixture->applications_dir, "app.desktop", NULL);
116
117   /* FIXME: this shouldn't be required */
118   g_list_free_full (g_app_info_get_all (), g_object_unref);
119
120   /* Create an app monitor and check that its ::changed signal is emitted when
121    * a new app is installed. */
122   monitor = g_app_info_monitor_get ();
123
124   g_signal_connect (monitor, "changed", G_CALLBACK (changed_cb), &changed_fired);
125
126   g_idle_add (create_app, app_path);
127   timeout_source = g_timeout_source_new_seconds (3);
128   g_source_set_callback (timeout_source, timeout_cb, &timed_out, NULL);
129   g_source_attach (timeout_source, NULL);
130
131   while (!changed_fired && !timed_out)
132     g_main_context_iteration (context, TRUE);
133
134   g_assert_true (changed_fired);
135   changed_fired = FALSE;
136
137   g_source_destroy (timeout_source);
138   g_clear_pointer (&timeout_source, g_source_unref);
139
140   /* Check that the app is now queryable. This has the side-effect of re-arming
141    * the #GAppInfoMonitor::changed signal for the next part of the test. */
142   app = g_desktop_app_info_new ("app.desktop");
143   g_assert_nonnull (app);
144   g_clear_object (&app);
145
146   /* Now check that ::changed is emitted when an app is uninstalled. */
147   timeout_source = g_timeout_source_new_seconds (3);
148   g_source_set_callback (timeout_source, timeout_cb, &timed_out, NULL);
149   g_source_attach (timeout_source, NULL);
150
151   delete_app (app_path);
152
153   while (!changed_fired && !timed_out)
154     g_main_context_iteration (context, TRUE);
155
156   g_assert_true (changed_fired);
157
158   g_source_destroy (timeout_source);
159   g_clear_pointer (&timeout_source, g_source_unref);
160   g_remove (app_path);
161
162   g_object_unref (monitor);
163
164   g_free (app_path);
165 #elif defined (__APPLE__)
166   g_test_skip (".desktop monitor on macos");
167 #else  /* if !(defined (G_OS_UNIX) && !defined (__APPLE__)) */
168   g_test_skip (".desktop monitor on win32");
169 #endif  /* !(defined (G_OS_UNIX) && !defined (__APPLE__)) */
170 }
171
172 int
173 main (int argc, char *argv[])
174 {
175   g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL);
176
177   g_test_add ("/monitor/app", Fixture, NULL, setup, test_app_monitor, teardown);
178
179   return g_test_run ();
180 }