gio/tests/gsubprocess.c: Fix on Windows
[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, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author: Stef Walter <stefw@collabora.co.uk>
21  */
22
23 #include <locale.h>
24
25 #include <gio/gio.h>
26
27 /* How long to wait in ms for each iteration */
28 #define WAIT_ITERATION (10)
29
30 static gint num_async_operations = 0;
31
32 typedef struct
33 {
34   guint iterations_requested;
35   guint iterations_done;
36 } MockOperationData;
37
38 static void
39 mock_operation_free (gpointer user_data)
40 {
41   MockOperationData *data = user_data;
42   g_free (data);
43 }
44
45 static void
46 mock_operation_thread (GTask        *task,
47                        gpointer      source_object,
48                        gpointer      task_data,
49                        GCancellable *cancellable)
50 {
51   MockOperationData *data = task_data;
52   guint i;
53
54   for (i = 0; i < data->iterations_requested; i++)
55     {
56       if (g_cancellable_is_cancelled (cancellable))
57         break;
58       if (g_test_verbose ())
59         g_printerr ("THRD: %u iteration %u\n", data->iterations_requested, i);
60       g_usleep (WAIT_ITERATION * 1000);
61     }
62
63   if (g_test_verbose ())
64     g_printerr ("THRD: %u stopped at %u\n", data->iterations_requested, i);
65   data->iterations_done = i;
66
67   g_task_return_boolean (task, TRUE);
68 }
69
70 static gboolean
71 mock_operation_timeout (gpointer user_data)
72 {
73   GTask *task;
74   MockOperationData *data;
75   gboolean done = FALSE;
76
77   task = G_TASK (user_data);
78   data = g_task_get_task_data (task);
79
80   if (data->iterations_done >= data->iterations_requested)
81       done = TRUE;
82
83   if (g_cancellable_is_cancelled (g_task_get_cancellable (task)))
84       done = TRUE;
85
86   if (done)
87     {
88       if (g_test_verbose ())
89         g_printerr ("LOOP: %u stopped at %u\n", data->iterations_requested,\
90                     data->iterations_done);
91       g_task_return_boolean (task, TRUE);
92       return FALSE; /* don't call timeout again */
93     }
94   else
95     {
96       data->iterations_done++;
97       if (g_test_verbose ())
98         g_printerr ("LOOP: %u iteration %u\n", data->iterations_requested,
99                     data->iterations_done);
100       return TRUE; /* call timeout */
101     }
102 }
103
104 static void
105 mock_operation_async (guint                wait_iterations,
106                       gboolean             run_in_thread,
107                       GCancellable        *cancellable,
108                       GAsyncReadyCallback  callback,
109                       gpointer             user_data)
110 {
111   GTask *task;
112   MockOperationData *data;
113
114   task = g_task_new (NULL, cancellable, callback, user_data);
115   data = g_new0 (MockOperationData, 1);
116   data->iterations_requested = wait_iterations;
117   g_task_set_task_data (task, data, mock_operation_free);
118
119   if (run_in_thread)
120     {
121       g_task_run_in_thread (task, mock_operation_thread);
122       if (g_test_verbose ())
123         g_printerr ("THRD: %d started\n", wait_iterations);
124     }
125   else
126     {
127       g_timeout_add_full (G_PRIORITY_DEFAULT, WAIT_ITERATION, mock_operation_timeout,
128                           g_object_ref (task), g_object_unref);
129       if (g_test_verbose ())
130         g_printerr ("LOOP: %d started\n", wait_iterations);
131     }
132
133   g_object_unref (task);
134 }
135
136 static guint
137 mock_operation_finish (GAsyncResult  *result,
138                        GError       **error)
139 {
140   MockOperationData *data;
141   GTask *task;
142
143   g_assert (g_task_is_valid (result, NULL));
144
145   /* This test expects the return value to be iterations_done even
146    * when an error is set.
147    */
148   task = G_TASK (result);
149   data = g_task_get_task_data (task);
150
151   g_task_propagate_boolean (task, error);
152   return data->iterations_done;
153 }
154
155 GMainLoop *loop;
156
157 static void
158 on_mock_operation_ready (GObject      *source,
159                          GAsyncResult *result,
160                          gpointer      user_data)
161 {
162   guint iterations_requested;
163   guint iterations_done;
164   GError *error = NULL;
165
166   iterations_requested = GPOINTER_TO_UINT (user_data);
167   iterations_done = mock_operation_finish (result, &error);
168
169   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
170   g_error_free (error);
171
172   g_assert_cmpint (iterations_requested, >, iterations_done);
173   num_async_operations--;
174
175   if (!num_async_operations)
176     g_main_loop_quit (loop);
177 }
178
179 static gboolean
180 on_main_loop_timeout_quit (gpointer user_data)
181 {
182   GMainLoop *loop = user_data;
183   g_main_loop_quit (loop);
184   return FALSE;
185 }
186
187 static void
188 test_cancel_multiple_concurrent (void)
189 {
190   GCancellable *cancellable;
191   guint i, iterations;
192
193   cancellable = g_cancellable_new ();
194   loop = g_main_loop_new (NULL, FALSE);
195
196   for (i = 0; i < 45; i++)
197     {
198       iterations = i + 10;
199       mock_operation_async (iterations, g_random_boolean (), cancellable,
200                             on_mock_operation_ready, GUINT_TO_POINTER (iterations));
201       num_async_operations++;
202     }
203
204   /* Wait for two iterations, to give threads a chance to start up */
205   g_timeout_add (WAIT_ITERATION * 2, on_main_loop_timeout_quit, loop);
206   g_main_loop_run (loop);
207   g_assert_cmpint (num_async_operations, ==, 45);
208   if (g_test_verbose ())
209     g_printerr ("CANCEL: %d operations\n", num_async_operations);
210   g_cancellable_cancel (cancellable);
211   g_assert (g_cancellable_is_cancelled (cancellable));
212
213   /* Wait for all operations to be cancelled */
214   g_main_loop_run (loop);
215   g_assert_cmpint (num_async_operations, ==, 0);
216
217   g_object_unref (cancellable);
218   g_main_loop_unref (loop);
219 }
220
221 int
222 main (int argc, char *argv[])
223 {
224   g_test_init (&argc, &argv, NULL);
225
226   g_test_add_func ("/cancellable/multiple-concurrent", test_cancel_multiple_concurrent);
227
228   return g_test_run ();
229 }