g_simple_async_result_is_valid: fix for NULL source tag
[platform/upstream/glib.git] / gio / tests / cancellable.c
1 /* GIO - GLib Input, Output and Streaming Library
2  *
3  * Copyright (C) 2011 Collabora Ltd.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
17  *
18  * Author: Stef Walter <stefw@collabora.co.uk>
19  */
20
21 #include <locale.h>
22
23 #include <gio/gio.h>
24
25 /* How long to wait in ms for each iteration */
26 #define WAIT_ITERATION (10)
27
28 static gint num_async_operations = 0;
29
30 typedef struct
31 {
32   guint iterations_requested;
33   guint iterations_done;
34 } MockOperationData;
35
36 static void
37 mock_operation_free (gpointer user_data)
38 {
39   MockOperationData *data = user_data;
40   g_free (data);
41 }
42
43 static void
44 mock_operation_thread (GTask        *task,
45                        gpointer      source_object,
46                        gpointer      task_data,
47                        GCancellable *cancellable)
48 {
49   MockOperationData *data = task_data;
50   guint i;
51
52   for (i = 0; i < data->iterations_requested; i++)
53     {
54       if (g_cancellable_is_cancelled (cancellable))
55         break;
56       if (g_test_verbose ())
57         g_printerr ("THRD: %u iteration %u\n", data->iterations_requested, i);
58       g_usleep (WAIT_ITERATION * 1000);
59     }
60
61   if (g_test_verbose ())
62     g_printerr ("THRD: %u stopped at %u\n", data->iterations_requested, i);
63   data->iterations_done = i;
64
65   g_task_return_boolean (task, TRUE);
66 }
67
68 static gboolean
69 mock_operation_timeout (gpointer user_data)
70 {
71   GTask *task;
72   MockOperationData *data;
73   gboolean done = FALSE;
74
75   task = G_TASK (user_data);
76   data = g_task_get_task_data (task);
77
78   if (data->iterations_done >= data->iterations_requested)
79       done = TRUE;
80
81   if (g_cancellable_is_cancelled (g_task_get_cancellable (task)))
82       done = TRUE;
83
84   if (done)
85     {
86       if (g_test_verbose ())
87         g_printerr ("LOOP: %u stopped at %u\n", data->iterations_requested,\
88                     data->iterations_done);
89       g_task_return_boolean (task, TRUE);
90       return FALSE; /* don't call timeout again */
91     }
92   else
93     {
94       data->iterations_done++;
95       if (g_test_verbose ())
96         g_printerr ("LOOP: %u iteration %u\n", data->iterations_requested,
97                     data->iterations_done);
98       return TRUE; /* call timeout */
99     }
100 }
101
102 static void
103 mock_operation_async (guint                wait_iterations,
104                       gboolean             run_in_thread,
105                       GCancellable        *cancellable,
106                       GAsyncReadyCallback  callback,
107                       gpointer             user_data)
108 {
109   GTask *task;
110   MockOperationData *data;
111
112   task = g_task_new (NULL, cancellable, callback, user_data);
113   data = g_new0 (MockOperationData, 1);
114   data->iterations_requested = wait_iterations;
115   g_task_set_task_data (task, data, mock_operation_free);
116
117   if (run_in_thread)
118     {
119       g_task_run_in_thread (task, mock_operation_thread);
120       if (g_test_verbose ())
121         g_printerr ("THRD: %d started\n", wait_iterations);
122     }
123   else
124     {
125       g_timeout_add_full (G_PRIORITY_DEFAULT, WAIT_ITERATION, mock_operation_timeout,
126                           g_object_ref (task), g_object_unref);
127       if (g_test_verbose ())
128         g_printerr ("LOOP: %d started\n", wait_iterations);
129     }
130
131   g_object_unref (task);
132 }
133
134 static guint
135 mock_operation_finish (GAsyncResult  *result,
136                        GError       **error)
137 {
138   MockOperationData *data;
139   GTask *task;
140
141   g_assert (g_task_is_valid (result, NULL));
142
143   /* This test expects the return value to be iterations_done even
144    * when an error is set.
145    */
146   task = G_TASK (result);
147   data = g_task_get_task_data (task);
148
149   g_task_propagate_boolean (task, error);
150   return data->iterations_done;
151 }
152
153 GMainLoop *loop;
154
155 static void
156 on_mock_operation_ready (GObject      *source,
157                          GAsyncResult *result,
158                          gpointer      user_data)
159 {
160   guint iterations_requested;
161   guint iterations_done;
162   GError *error = NULL;
163
164   iterations_requested = GPOINTER_TO_UINT (user_data);
165   iterations_done = mock_operation_finish (result, &error);
166
167   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
168   g_error_free (error);
169
170   g_assert_cmpint (iterations_requested, >, iterations_done);
171   num_async_operations--;
172
173   if (!num_async_operations)
174     g_main_loop_quit (loop);
175 }
176
177 static gboolean
178 on_main_loop_timeout_quit (gpointer user_data)
179 {
180   GMainLoop *loop = user_data;
181   g_main_loop_quit (loop);
182   return FALSE;
183 }
184
185 static void
186 test_cancel_multiple_concurrent (void)
187 {
188   GCancellable *cancellable;
189   guint i, iterations;
190
191   cancellable = g_cancellable_new ();
192   loop = g_main_loop_new (NULL, FALSE);
193
194   for (i = 0; i < 45; i++)
195     {
196       iterations = i + 10;
197       mock_operation_async (iterations, g_random_boolean (), cancellable,
198                             on_mock_operation_ready, GUINT_TO_POINTER (iterations));
199       num_async_operations++;
200     }
201
202   /* Wait for two iterations, to give threads a chance to start up */
203   g_timeout_add (WAIT_ITERATION * 2, on_main_loop_timeout_quit, loop);
204   g_main_loop_run (loop);
205   g_assert_cmpint (num_async_operations, ==, 45);
206   if (g_test_verbose ())
207     g_printerr ("CANCEL: %d operations\n", num_async_operations);
208   g_cancellable_cancel (cancellable);
209   g_assert (g_cancellable_is_cancelled (cancellable));
210
211   /* Wait for all operations to be cancelled */
212   g_main_loop_run (loop);
213   g_assert_cmpint (num_async_operations, ==, 0);
214
215   g_object_unref (cancellable);
216   g_main_loop_unref (loop);
217 }
218
219 int
220 main (int argc, char *argv[])
221 {
222   g_test_init (&argc, &argv, NULL);
223
224   g_test_add_func ("/cancellable/multiple-concurrent", test_cancel_multiple_concurrent);
225
226   return g_test_run ();
227 }