kdbus: Fixup signal subscription
[platform/upstream/glib.git] / gio / tests / sleepy-stream.c
1 /*
2  * Copyright © 2009 Codethink Limited
3  *
4  * SPDX-License-Identifier: LGPL-2.1-or-later
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * See the included COPYING file for more information.
12  *
13  * Author: Ryan Lortie <desrt@desrt.ca>
14  */
15
16 #include <gio/gio.h>
17 #include <string.h>
18
19 #define MAX_PIECE_SIZE  100
20 #define MAX_PIECES       60
21
22 static gchar *
23 cook_piece (void)
24 {
25   char buffer[MAX_PIECE_SIZE * 2];
26   gint symbols, i = 0;
27
28   symbols = g_test_rand_int_range (1, MAX_PIECE_SIZE + 1);
29
30   while (symbols--)
31     {
32       gint c = g_test_rand_int_range (0, 30);
33
34       switch (c)
35         {
36          case 26:
37           buffer[i++] = '\n';
38           G_GNUC_FALLTHROUGH;
39          case 27:
40           buffer[i++] = '\r';
41           break;
42
43          case 28:
44           buffer[i++] = '\r';
45           G_GNUC_FALLTHROUGH;
46          case 29:
47           buffer[i++] = '\n';
48           break;
49
50          default:
51           buffer[i++] = c + 'a';
52           break;
53         }
54
55       g_assert_cmpint (i, <=, sizeof buffer);
56     }
57
58   return g_strndup (buffer, i);
59 }
60
61 static gchar **
62 cook_pieces (void)
63 {
64   gchar **array;
65   gint pieces;
66
67   pieces = g_test_rand_int_range (0, MAX_PIECES + 1);
68   array = g_new (char *, pieces + 1);
69   array[pieces] = NULL;
70
71   while (pieces--)
72     array[pieces] = cook_piece ();
73
74   return array;
75 }
76
77 typedef struct
78 {
79   GInputStream parent_instance;
80
81   gboolean built_to_fail;
82   gchar **pieces;
83   gint index;
84
85   const gchar *current;
86 } SleepyStream;
87
88 typedef GInputStreamClass SleepyStreamClass;
89
90 GType sleepy_stream_get_type (void);
91
92 G_DEFINE_TYPE (SleepyStream, sleepy_stream, G_TYPE_INPUT_STREAM)
93
94 static gssize
95 sleepy_stream_read (GInputStream  *stream,
96                     void          *buffer,
97                     gsize          length,
98                     GCancellable  *cancellable,
99                     GError       **error)
100 {
101   SleepyStream *sleepy = (SleepyStream *) stream;
102
103   if (sleepy->pieces[sleepy->index] == NULL)
104     {
105       if (sleepy->built_to_fail)
106         {
107           g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "fail");
108           return -1;
109         }
110       else
111         return 0;
112     }
113   else
114     {
115       if (!sleepy->current)
116         sleepy->current = sleepy->pieces[sleepy->index++];
117
118       length = MIN (strlen (sleepy->current), length);
119       memcpy (buffer, sleepy->current, length);
120
121       sleepy->current += length;
122       if (*sleepy->current == '\0')
123         sleepy->current = NULL;
124
125       return length;
126     }
127 }
128
129 static void
130 sleepy_stream_init (SleepyStream *sleepy)
131 {
132   sleepy->pieces = cook_pieces ();
133   sleepy->built_to_fail = FALSE;
134   sleepy->index = 0;
135 }
136
137 static void
138 sleepy_stream_finalize (GObject *object)
139 {
140   SleepyStream *sleepy = (SleepyStream *) object;
141
142   g_strfreev (sleepy->pieces);
143   G_OBJECT_CLASS (sleepy_stream_parent_class)
144     ->finalize (object);
145 }
146
147 static void
148 sleepy_stream_class_init (SleepyStreamClass *class)
149 {
150   G_OBJECT_CLASS (class)->finalize = sleepy_stream_finalize;
151   class->read_fn = sleepy_stream_read;
152
153   /* no read_async implementation.
154    * main thread will sleep while read runs in a worker.
155    */
156 }
157
158 static SleepyStream *
159 sleepy_stream_new (void)
160 {
161   return g_object_new (sleepy_stream_get_type (), NULL);
162 }
163
164 static gboolean
165 read_line (GDataInputStream  *stream,
166            GString           *string,
167            const gchar       *eol,
168            GError           **error)
169 {
170   gsize length;
171   char *str;
172
173   str = g_data_input_stream_read_line (stream, &length, NULL, error);
174
175   if (str == NULL)
176     return FALSE;
177
178   g_assert (strstr (str, eol) == NULL);
179   g_assert (strlen (str) == length);
180
181   g_string_append (string, str);
182   g_string_append (string, eol);
183   g_free (str);
184
185   return TRUE;
186 }
187
188 static void
189 build_comparison (GString      *str,
190                   SleepyStream *stream)
191 {
192   /* build this for comparison */
193   gint i;
194
195   for (i = 0; stream->pieces[i]; i++)
196     g_string_append (str, stream->pieces[i]);
197
198   if (str->len && str->str[str->len - 1] != '\n')
199     g_string_append_c (str, '\n');
200 }
201
202
203 static void
204 test (void)
205 {
206   SleepyStream *stream = sleepy_stream_new ();
207   GDataInputStream *data;
208   GError *error = NULL;
209   GString *one;
210   GString *two;
211
212   one = g_string_new (NULL);
213   two = g_string_new (NULL);
214
215   data = g_data_input_stream_new (G_INPUT_STREAM (stream));
216   g_data_input_stream_set_newline_type (data, G_DATA_STREAM_NEWLINE_TYPE_LF);
217   build_comparison (one, stream);
218
219   while (read_line (data, two, "\n", &error));
220
221   g_assert_cmpstr (one->str, ==, two->str);
222   g_string_free (one, TRUE);
223   g_string_free (two, TRUE);
224   g_object_unref (stream);
225   g_object_unref (data);
226 }
227
228 static GDataInputStream *data;
229 static GString *one, *two;
230 static GMainLoop *loop;
231 static const gchar *eol;
232
233 static void
234 asynch_ready (GObject      *object,
235               GAsyncResult *result,
236               gpointer      user_data)
237 {
238   GError *error = NULL;
239   gsize length;
240   gchar *str;
241
242   g_assert (data == G_DATA_INPUT_STREAM (object));
243
244   str = g_data_input_stream_read_line_finish (data, result, &length, &error);
245
246   if (str == NULL)
247     {
248       g_main_loop_quit (loop);
249       if (error)
250         g_error_free (error);
251     }
252   else
253     {
254       g_assert (length == strlen (str));
255       g_string_append (two, str);
256       g_string_append (two, eol);
257       g_free (str);
258
259       /* MOAR!! */
260       g_data_input_stream_read_line_async (data, 0, NULL, asynch_ready, NULL);
261     }
262 }
263
264
265 static void
266 asynch (void)
267 {
268   SleepyStream *sleepy = sleepy_stream_new ();
269
270   data = g_data_input_stream_new (G_INPUT_STREAM (sleepy));
271   one = g_string_new (NULL);
272   two = g_string_new (NULL);
273   eol = "\n";
274
275   build_comparison (one, sleepy);
276   g_data_input_stream_read_line_async (data, 0, NULL, asynch_ready, NULL);
277   g_main_loop_run (loop = g_main_loop_new (NULL, FALSE));
278
279   g_assert_cmpstr (one->str, ==, two->str);
280   g_string_free (one, TRUE);
281   g_string_free (two, TRUE);
282   g_object_unref (sleepy);
283   g_object_unref (data);
284 }
285
286 int
287 main (int argc, char **argv)
288 {
289   g_test_init (&argc, &argv, NULL);
290
291   g_test_add_func ("/filter-stream/input", test);
292   g_test_add_func ("/filter-stream/async", asynch);
293
294   return g_test_run();
295 }