Merge remote-tracking branch 'gvdb/master'
[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_source_destroy (source);
68   g_main_context_unref (ctx);
69
70   ctx = g_main_context_default ();
71   source = g_source_new (&funcs, sizeof (GSource));
72   g_source_set_funcs (source, &funcs);
73   g_source_set_callback (source, cb, data, NULL);
74   id = g_source_attach (source, ctx);
75   g_source_set_name_by_id (id, "e");
76   g_assert_cmpstr (g_source_get_name (source), ==, "e");
77   g_assert (g_source_get_context (source) == ctx);
78   g_assert (g_source_remove_by_funcs_user_data (&funcs, data));
79 }
80
81 static void
82 test_mainloop_basic (void)
83 {
84   GMainLoop *loop;
85   GMainContext *ctx;
86
87   loop = g_main_loop_new (NULL, FALSE);
88
89   g_assert (!g_main_loop_is_running (loop));
90
91   g_main_loop_ref (loop);
92
93   ctx = g_main_loop_get_context (loop);
94   g_assert (ctx == g_main_context_default ());
95
96   g_main_loop_unref (loop);
97
98   g_assert (g_main_depth () == 0);
99
100   g_main_loop_unref (loop);
101 }
102
103 static gint a;
104 static gint b;
105 static gint c;
106
107 static gboolean
108 count_calls (gpointer data)
109 {
110   gint *i = data;
111
112   (*i)++;
113
114   return TRUE;
115 }
116
117 static void
118 test_timeouts (void)
119 {
120   GMainContext *ctx;
121   GMainLoop *loop;
122   GSource *source;
123
124   a = b = c = 0;
125
126   ctx = g_main_context_new ();
127   loop = g_main_loop_new (ctx, FALSE);
128
129   source = g_timeout_source_new (100);
130   g_source_set_callback (source, count_calls, &a, NULL);
131   g_source_attach (source, ctx);
132   g_source_unref (source);
133
134   source = g_timeout_source_new (250);
135   g_source_set_callback (source, count_calls, &b, NULL);
136   g_source_attach (source, ctx);
137   g_source_unref (source);
138
139   source = g_timeout_source_new (330);
140   g_source_set_callback (source, count_calls, &c, NULL);
141   g_source_attach (source, ctx);
142   g_source_unref (source);
143
144   source = g_timeout_source_new (1050);
145   g_source_set_callback (source, (GSourceFunc)g_main_loop_quit, loop, NULL);
146   g_source_attach (source, ctx);
147   g_source_unref (source);
148
149   g_main_loop_run (loop);
150
151   g_assert (a == 10);
152   g_assert (b == 4);
153   g_assert (c == 3);
154
155   g_main_loop_unref (loop);
156   g_main_context_unref (ctx);
157 }
158
159 static void
160 test_priorities (void)
161 {
162   GMainContext *ctx;
163   GSource *sourcea;
164   GSource *sourceb;
165
166   a = b = c = 0;
167
168   ctx = g_main_context_new ();
169
170   sourcea = g_idle_source_new ();
171   g_source_set_callback (sourcea, count_calls, &a, NULL);
172   g_source_set_priority (sourcea, 1);
173   g_source_attach (sourcea, ctx);
174   g_source_unref (sourcea);
175
176   sourceb = g_idle_source_new ();
177   g_source_set_callback (sourceb, count_calls, &b, NULL);
178   g_source_set_priority (sourceb, 0);
179   g_source_attach (sourceb, ctx);
180   g_source_unref (sourceb);
181
182   g_assert (g_main_context_pending (ctx));
183   g_assert (g_main_context_iteration (ctx, FALSE));
184   g_assert (a == 0);
185   g_assert (b == 1);
186
187   g_assert (g_main_context_iteration (ctx, FALSE));
188   g_assert (a == 0);
189   g_assert (b == 2);
190
191   g_source_destroy (sourceb);
192
193   g_assert (g_main_context_iteration (ctx, FALSE));
194   g_assert (a == 1);
195   g_assert (b == 2);
196
197   g_assert (g_main_context_pending (ctx));
198   g_source_destroy (sourcea);
199   g_assert (!g_main_context_pending (ctx));
200
201   g_main_context_unref (ctx);
202 }
203
204 static gint count;
205
206 static gboolean
207 func (gpointer data)
208 {
209   if (data != NULL)
210     g_assert (data == g_thread_self ());
211
212   count++;
213
214   return FALSE;
215 }
216
217 static gboolean
218 call_func (gpointer data)
219 {
220   func (g_thread_self ());
221
222   return FALSE;
223 }
224
225 static gpointer
226 thread_func (gpointer data)
227 {
228   GMainContext *ctx = data;
229   GSource *source;
230
231   g_main_context_push_thread_default (ctx);
232
233   source = g_timeout_source_new (500);
234   g_source_set_callback (source, (GSourceFunc)g_thread_exit, NULL, NULL);
235   g_source_attach (source, ctx);
236   g_source_unref (source);
237
238   while (TRUE)
239     g_main_context_iteration (ctx, TRUE);
240
241   return NULL;
242 }
243
244 static void
245 test_invoke (void)
246 {
247   GMainContext *ctx;
248   GThread *thread;
249
250   count = 0;
251
252   /* this one gets invoked directly */
253   g_main_context_invoke (NULL, func, g_thread_self ());
254   g_assert (count == 1);
255
256   /* invoking out of an idle works too */
257   g_idle_add (call_func, NULL);
258   g_main_context_iteration (g_main_context_default (), FALSE);
259   g_assert (count == 2);
260
261   /* test thread-default forcing the invocation to go
262    * to another thread
263    */
264   ctx = g_main_context_new ();
265   thread = g_thread_new ("worker", thread_func, ctx);
266
267   g_usleep (1000); /* give some time to push the thread-default */
268
269   g_main_context_invoke (ctx, func, thread);
270   g_assert (count == 2);
271
272   g_thread_join (thread);
273   g_assert (count == 3);
274 }
275
276 int
277 main (int argc, char *argv[])
278 {
279   g_test_init (&argc, &argv, NULL);
280
281   g_test_add_func ("/maincontext/basic", test_maincontext_basic);
282   g_test_add_func ("/mainloop/basic", test_mainloop_basic);
283   g_test_add_func ("/mainloop/timeouts", test_timeouts);
284   g_test_add_func ("/mainloop/priorities", test_priorities);
285   g_test_add_func ("/mainloop/invoke", test_invoke);
286
287   return g_test_run ();
288 }