Add some more mainloop tests
[platform/upstream/glib.git] / glib / tests / mainloop.c
1 /* Unit tests for GMainLoop
2  * Copyright (C) 2011 Red Hat, Inc
3  * Author: Matthias Clasen
4  *
5  * This work is provided "as is"; redistribution and modification
6  * in whole or in part, in any medium, physical or electronic is
7  * permitted without restriction.
8  *
9  * This work is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12  *
13  * In no event shall the authors or contributors be liable for any
14  * direct, indirect, incidental, special, exemplary, or consequential
15  * damages (including, but not limited to, procurement of substitute
16  * goods or services; loss of use, data, or profits; or business
17  * interruption) however caused and on any theory of liability, whether
18  * in contract, strict liability, or tort (including negligence or
19  * otherwise) arising in any way out of the use of this software, even
20  * if advised of the possibility of such damage.
21  */
22
23 #include <glib.h>
24
25 static gboolean cb (gpointer data)
26 {
27   return FALSE;
28 }
29
30 static void
31 test_maincontext_basic (void)
32 {
33   GMainContext *ctx;
34   GSource *source;
35   GSourceFuncs funcs;
36   guint id;
37   gpointer data = &funcs;
38
39   ctx = g_main_context_new ();
40
41   g_assert (!g_main_context_pending (ctx));
42   g_assert (!g_main_context_iteration (ctx, FALSE));
43
44   source = g_source_new (&funcs, sizeof (GSource));
45   g_assert (g_source_get_priority (source) == G_PRIORITY_DEFAULT);
46   g_assert (!g_source_is_destroyed (source));
47
48   g_assert (!g_source_get_can_recurse (source));
49   g_assert (g_source_get_name (source) == NULL);
50
51   g_source_set_can_recurse (source, TRUE);
52   g_source_set_name (source, "d");
53
54   g_assert (g_source_get_can_recurse (source));
55   g_assert_cmpstr (g_source_get_name (source), ==, "d");
56
57   g_assert (g_main_context_find_source_by_user_data (ctx, NULL) == NULL);
58   g_assert (g_main_context_find_source_by_funcs_user_data (ctx, &funcs, NULL) == NULL);
59
60   id = g_source_attach (source, ctx);
61   g_assert_cmpint (g_source_get_id (source), ==, id);
62   g_assert (g_main_context_find_source_by_id (ctx, id) == source);
63
64   g_source_set_priority (source, G_PRIORITY_HIGH);
65   g_assert (g_source_get_priority (source) == G_PRIORITY_HIGH);
66
67   g_main_context_unref (ctx);
68
69   ctx = g_main_context_default ();
70   source = g_source_new (&funcs, sizeof (GSource));
71   g_source_set_funcs (source, &funcs);
72   g_source_set_callback (source, cb, data, NULL);
73   id = g_source_attach (source, ctx);
74   g_source_set_name_by_id (id, "e");
75   g_assert_cmpstr (g_source_get_name (source), ==, "e");
76   g_assert (g_source_get_context (source) == ctx);
77   g_assert (g_source_remove_by_funcs_user_data (&funcs, data));
78 }
79
80 static void
81 test_mainloop_basic (void)
82 {
83   GMainLoop *loop;
84   GMainContext *ctx;
85
86   loop = g_main_loop_new (NULL, FALSE);
87
88   g_assert (!g_main_loop_is_running (loop));
89
90   g_main_loop_ref (loop);
91
92   ctx = g_main_loop_get_context (loop);
93   g_assert (ctx == g_main_context_default ());
94
95   g_main_loop_unref (loop);
96
97   g_assert (g_main_depth () == 0);
98 }
99
100 static gint a;
101 static gint b;
102 static gint c;
103
104 static gboolean
105 count_calls (gpointer data)
106 {
107   gint *i = data;
108
109   (*i)++;
110
111   return TRUE;
112 }
113
114 static void
115 test_timeouts (void)
116 {
117   GMainContext *ctx;
118   GMainLoop *loop;
119   GSource *source;
120
121   a = b = c = 0;
122
123   ctx = g_main_context_new ();
124   loop = g_main_loop_new (ctx, FALSE);
125
126   source = g_timeout_source_new (100);
127   g_source_set_callback (source, count_calls, &a, NULL);
128   g_source_attach (source, ctx);
129   g_source_unref (source);
130
131   source = g_timeout_source_new (250);
132   g_source_set_callback (source, count_calls, &b, NULL);
133   g_source_attach (source, ctx);
134   g_source_unref (source);
135
136   source = g_timeout_source_new (330);
137   g_source_set_callback (source, count_calls, &c, NULL);
138   g_source_attach (source, ctx);
139   g_source_unref (source);
140
141   source = g_timeout_source_new (1050);
142   g_source_set_callback (source, (GSourceFunc)g_main_loop_quit, loop, NULL);
143   g_source_attach (source, ctx);
144   g_source_unref (source);
145
146   g_main_loop_run (loop);
147
148   g_assert (a == 10);
149   g_assert (b == 4);
150   g_assert (c == 3);
151
152   g_main_loop_unref (loop);
153   g_main_context_unref (ctx);
154 }
155
156 static void
157 test_priorities (void)
158 {
159   GMainContext *ctx;
160   GSource *sourcea;
161   GSource *sourceb;
162
163   a = b = c = 0;
164
165   ctx = g_main_context_new ();
166
167   sourcea = g_idle_source_new ();
168   g_source_set_callback (sourcea, count_calls, &a, NULL);
169   g_source_set_priority (sourcea, 1);
170   g_source_attach (sourcea, ctx);
171   g_source_unref (sourcea);
172
173   sourceb = g_idle_source_new ();
174   g_source_set_callback (sourceb, count_calls, &b, NULL);
175   g_source_set_priority (sourceb, 0);
176   g_source_attach (sourceb, ctx);
177   g_source_unref (sourceb);
178
179   g_assert (g_main_context_pending (ctx));
180   g_assert (g_main_context_iteration (ctx, FALSE));
181   g_assert (a == 0);
182   g_assert (b == 1);
183
184   g_assert (g_main_context_iteration (ctx, FALSE));
185   g_assert (a == 0);
186   g_assert (b == 2);
187
188   g_source_destroy (sourceb);
189
190   g_assert (g_main_context_iteration (ctx, FALSE));
191   g_assert (a == 1);
192   g_assert (b == 2);
193
194   g_assert (g_main_context_pending (ctx));
195   g_source_destroy (sourcea);
196   g_assert (!g_main_context_pending (ctx));
197
198   g_main_context_unref (ctx);
199 }
200
201 static gint count;
202
203 static gboolean
204 func (gpointer data)
205 {
206   if (data != NULL)
207     g_assert (data == g_thread_self ());
208
209   count++;
210
211   return FALSE;
212 }
213
214 static gboolean
215 call_func (gpointer data)
216 {
217   func (g_thread_self ());
218
219   return FALSE;
220 }
221
222 static gpointer
223 thread_func (gpointer data)
224 {
225   GMainContext *ctx = data;
226   GSource *source;
227
228   g_main_context_push_thread_default (ctx);
229
230   source = g_timeout_source_new (500);
231   g_source_set_callback (source, (GSourceFunc)g_thread_exit, NULL, NULL);
232   g_source_attach (source, ctx);
233   g_source_unref (source);
234
235   while (TRUE)
236     g_main_context_iteration (ctx, TRUE);
237
238   return NULL;
239 }
240
241 static void
242 test_invoke (void)
243 {
244   GMainContext *ctx;
245   GThread *thread;
246
247   count = 0;
248
249   /* this one gets invoked directly */
250   g_main_context_invoke (NULL, func, g_thread_self ());
251   g_assert (count == 1);
252
253   /* invoking out of an idle works too */
254   g_idle_add (call_func, NULL);
255   g_main_context_iteration (g_main_context_default (), FALSE);
256   g_assert (count == 2);
257
258   /* test thread-default forcing the invocation to go
259    * to another thread
260    */
261   ctx = g_main_context_new ();
262   thread = g_thread_new ("worker", thread_func, ctx);
263
264   g_usleep (1000); /* give some time to push the thread-default */
265
266   g_main_context_invoke (ctx, func, thread);
267   g_assert (count == 2);
268
269   g_thread_join (thread);
270   g_assert (count == 3);
271 }
272
273 int
274 main (int argc, char *argv[])
275 {
276   g_test_init (&argc, &argv, NULL);
277
278   g_test_add_func ("/maincontext/basic", test_maincontext_basic);
279   g_test_add_func ("/mainloop/basic", test_mainloop_basic);
280   g_test_add_func ("/mainloop/timeouts", test_timeouts);
281   g_test_add_func ("/mainloop/priorities", test_priorities);
282   g_test_add_func ("/mainloop/invoke", test_invoke);
283
284   return g_test_run ();
285 }