tests/mainloop: add a test for child sources

https://bugzilla.gnome.org/show_bug.cgi?id=669260
This commit is contained in:
Dan Winship 2012-04-13 11:44:34 -04:00
parent a49568cecc
commit bdbb531340

View File

@ -312,6 +312,103 @@ test_invoke (void)
g_assert_cmpint (count, ==, 3);
}
static gboolean
run_inner_loop (gpointer user_data)
{
GMainContext *ctx = user_data;
GMainLoop *inner;
GSource *timeout;
a++;
inner = g_main_loop_new (ctx, FALSE);
timeout = g_timeout_source_new (100);
g_source_set_callback (timeout, (GSourceFunc)g_main_loop_quit, inner, NULL);
g_source_attach (timeout, ctx);
g_main_loop_run (inner);
g_main_loop_unref (inner);
return TRUE;
}
static void
test_child_sources (void)
{
GMainContext *ctx;
GMainLoop *loop;
GSource *parent, *child_b, *child_c, *end;
ctx = g_main_context_new ();
loop = g_main_loop_new (ctx, FALSE);
a = b = c = 0;
parent = g_timeout_source_new (2000);
g_source_set_callback (parent, run_inner_loop, ctx, NULL);
g_source_set_priority (parent, G_PRIORITY_LOW);
g_source_attach (parent, ctx);
child_b = g_timeout_source_new (250);
g_source_set_callback (child_b, count_calls, &b, NULL);
g_source_add_child_source (parent, child_b);
child_c = g_timeout_source_new (330);
g_source_set_callback (child_c, count_calls, &c, NULL);
g_source_set_priority (child_c, G_PRIORITY_HIGH);
g_source_add_child_source (parent, child_c);
/* Child sources always have the priority of the parent */
g_assert_cmpint (g_source_get_priority (parent), ==, G_PRIORITY_LOW);
g_assert_cmpint (g_source_get_priority (child_b), ==, G_PRIORITY_LOW);
g_assert_cmpint (g_source_get_priority (child_c), ==, G_PRIORITY_LOW);
g_source_set_priority (parent, G_PRIORITY_DEFAULT);
g_assert_cmpint (g_source_get_priority (parent), ==, G_PRIORITY_DEFAULT);
g_assert_cmpint (g_source_get_priority (child_b), ==, G_PRIORITY_DEFAULT);
g_assert_cmpint (g_source_get_priority (child_c), ==, G_PRIORITY_DEFAULT);
end = g_timeout_source_new (1050);
g_source_set_callback (end, (GSourceFunc)g_main_loop_quit, loop, NULL);
g_source_attach (end, ctx);
g_source_unref (end);
g_main_loop_run (loop);
/* The parent source's own timeout will never trigger, so "a" will
* only get incremented when "b" or "c" does. And when timeouts get
* blocked, they still wait the full interval next time rather than
* "catching up". So the timing is:
*
* 250 - b++ -> a++, run_inner_loop
* 330 - (c is blocked)
* 350 - inner_loop ends
* 350 - c++ belatedly -> a++, run_inner_loop
* 450 - inner loop ends
* 500 - b++ -> a++, run_inner_loop
* 600 - inner_loop ends
* 680 - c++ -> a++, run_inner_loop
* 750 - (b is blocked)
* 780 - inner loop ends
* 780 - b++ belatedly -> a++, run_inner_loop
* 880 - inner loop ends
* 1010 - c++ -> a++, run_inner_loop
* 1030 - (b is blocked)
* 1050 - end runs, quits outer loop, which has no effect yet
* 1110 - inner loop ends, a returns, outer loop exits
*/
g_assert_cmpint (a, ==, 6);
g_assert_cmpint (b, ==, 3);
g_assert_cmpint (c, ==, 3);
g_source_unref (parent);
g_source_unref (child_b);
g_source_unref (child_c);
g_main_loop_unref (loop);
g_main_context_unref (ctx);
}
int
main (int argc, char *argv[])
{
@ -322,6 +419,7 @@ main (int argc, char *argv[])
g_test_add_func ("/mainloop/timeouts", test_timeouts);
g_test_add_func ("/mainloop/priorities", test_priorities);
g_test_add_func ("/mainloop/invoke", test_invoke);
g_test_add_func ("/mainloop/child_sources", test_child_sources);
return g_test_run ();
}