1 | /* |
2 | * Copyright © 2014 Canonical Limited |
3 | * |
4 | * This library is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Lesser General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2.1 of the License, or (at your option) any later version. |
8 | * |
9 | * This library 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. See the GNU |
12 | * Lesser General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU Lesser General |
15 | * Public License along with this library; if not, see <http://www.gnu.org/licenses/>. |
16 | * |
17 | * Authors: Ryan Lortie <desrt@desrt.ca> |
18 | */ |
19 | |
20 | #include <gio/gio.h> |
21 | #include <string.h> |
22 | |
23 | static gboolean expected_read_success; |
24 | static guint expected_read; |
25 | static gboolean got_read_done; |
26 | |
27 | static void |
28 | read_done (GObject *source, |
29 | GAsyncResult *result, |
30 | gpointer user_data) |
31 | { |
32 | gboolean success; |
33 | gsize read; |
34 | |
35 | success = g_input_stream_read_all_finish (G_INPUT_STREAM (source), result, bytes_read: &read, NULL); |
36 | g_assert_cmpint (expected_read_success, ==, success); |
37 | g_assert_cmpint (expected_read, ==, read); |
38 | got_read_done = TRUE; |
39 | } |
40 | |
41 | static void |
42 | wait_for_read (gboolean success, |
43 | gsize read) |
44 | { |
45 | g_assert (!got_read_done); |
46 | expected_read_success = success; |
47 | expected_read = read; |
48 | |
49 | while (!got_read_done) |
50 | g_main_context_iteration (NULL, TRUE); |
51 | |
52 | got_read_done = FALSE; |
53 | } |
54 | |
55 | static gboolean expected_write_success; |
56 | static guint expected_written; |
57 | static gboolean got_write_done; |
58 | |
59 | static void |
60 | write_done (GObject *source, |
61 | GAsyncResult *result, |
62 | gpointer user_data) |
63 | { |
64 | gboolean success; |
65 | gsize written; |
66 | |
67 | success = g_output_stream_write_all_finish (G_OUTPUT_STREAM (source), result, bytes_written: &written, NULL); |
68 | g_assert_cmpint (expected_write_success, ==, success); |
69 | g_assert_cmpint (expected_written, ==, written); |
70 | got_write_done = TRUE; |
71 | } |
72 | |
73 | static void |
74 | wait_for_write (gboolean success, |
75 | gsize written) |
76 | { |
77 | g_assert (!got_write_done); |
78 | expected_write_success = success; |
79 | expected_written = written; |
80 | |
81 | while (!got_write_done) |
82 | g_main_context_iteration (NULL, TRUE); |
83 | |
84 | got_write_done = FALSE; |
85 | } |
86 | |
87 | static void |
88 | test_write_all_async_memory (void) |
89 | { |
90 | GOutputStream *ms; |
91 | gchar b[24]; |
92 | |
93 | ms = g_memory_output_stream_new (data: b, size: sizeof b, NULL, NULL); |
94 | |
95 | g_output_stream_write_all_async (stream: ms, buffer: "0123456789" , count: 10, io_priority: 0, NULL, callback: write_done, NULL); |
96 | wait_for_write (TRUE, written: 10); |
97 | |
98 | g_output_stream_write_all_async (stream: ms, buffer: "0123456789" , count: 10, io_priority: 0, NULL, callback: write_done, NULL); |
99 | wait_for_write (TRUE, written: 10); |
100 | |
101 | /* this will trigger an out-of-space error, but we will see the |
102 | * partial write... |
103 | */ |
104 | g_output_stream_write_all_async (stream: ms, buffer: "0123456789" , count: 10, io_priority: 0, NULL, callback: write_done, NULL); |
105 | wait_for_write (FALSE, written: 4); |
106 | |
107 | /* and still an error, but no further bytes written */ |
108 | g_output_stream_write_all_async (stream: ms, buffer: "0123456789" , count: 10, io_priority: 0, NULL, callback: write_done, NULL); |
109 | wait_for_write (FALSE, written: 0); |
110 | |
111 | g_assert (!memcmp (b, "012345678901234567890123" , 24)); |
112 | |
113 | g_object_unref (object: ms); |
114 | } |
115 | |
116 | static void |
117 | test_read_all_async_memory (void) |
118 | { |
119 | GInputStream *ms; |
120 | gchar b[24] = "0123456789ABCDEFGHIJ!@#$" ; |
121 | gchar buf[10]; |
122 | |
123 | ms = g_memory_input_stream_new_from_data (data: b, len: sizeof b, NULL); |
124 | |
125 | g_input_stream_read_all_async (stream: ms, buffer: buf, count: 10, io_priority: 0, NULL, callback: read_done, NULL); |
126 | wait_for_read (TRUE, read: 10); |
127 | g_assert (!memcmp (buf, "0123456789" , 10)); |
128 | |
129 | g_input_stream_read_all_async (stream: ms, buffer: buf, count: 10, io_priority: 0, NULL, callback: read_done, NULL); |
130 | wait_for_read (TRUE, read: 10); |
131 | g_assert (!memcmp (buf, "ABCDEFGHIJ" , 10)); |
132 | |
133 | /* partial read... */ |
134 | g_input_stream_read_all_async (stream: ms, buffer: buf, count: 10, io_priority: 0, NULL, callback: read_done, NULL); |
135 | wait_for_read (TRUE, read: 4); |
136 | g_assert (!memcmp (buf, "!@#$" , 4)); |
137 | |
138 | /* EOF */ |
139 | g_input_stream_read_all_async (stream: ms, buffer: buf, count: 10, io_priority: 0, NULL, callback: read_done, NULL); |
140 | wait_for_read (TRUE, read: 0); |
141 | |
142 | g_object_unref (object: ms); |
143 | } |
144 | |
145 | #ifdef G_OS_UNIX |
146 | #include <errno.h> |
147 | #include <sys/types.h> |
148 | #include <sys/socket.h> |
149 | #include <gio/gunixinputstream.h> |
150 | #include <gio/gunixoutputstream.h> |
151 | |
152 | static void |
153 | test_read_write_all_async_pipe (void) |
154 | { |
155 | GCancellable *cancellable; |
156 | GError *error = NULL; |
157 | GOutputStream *out; |
158 | GInputStream *in; |
159 | gsize in_flight; |
160 | gsize s; |
161 | gchar wbuf[100] = { 0, }; |
162 | gchar rbuf[100]; |
163 | |
164 | { |
165 | gint sv[2]; |
166 | gint s; |
167 | |
168 | s = socketpair (AF_UNIX, SOCK_STREAM, protocol: 0, fds: sv); |
169 | g_assert (s == 0); |
170 | |
171 | out = g_unix_output_stream_new (fd: sv[0], TRUE); |
172 | in = g_unix_input_stream_new (fd: sv[1], TRUE); |
173 | } |
174 | |
175 | /* Try to fill up the buffer */ |
176 | in_flight = 0; |
177 | while (g_pollable_output_stream_is_writable (G_POLLABLE_OUTPUT_STREAM (out))) |
178 | { |
179 | s = g_output_stream_write (stream: out, buffer: wbuf, count: sizeof wbuf, NULL, error: &error); |
180 | g_assert_no_error (error); |
181 | g_assert (s > 0); |
182 | in_flight += s; |
183 | } |
184 | |
185 | /* Now start a blocking write_all; nothing should happen. */ |
186 | cancellable = g_cancellable_new (); |
187 | g_output_stream_write_all_async (stream: out, buffer: "0123456789" , count: 10, io_priority: 0, cancellable, callback: write_done, NULL); |
188 | while (g_main_context_iteration (NULL, FALSE)) |
189 | ; |
190 | g_assert (!got_write_done); |
191 | |
192 | /* Cancel that to make sure it works */ |
193 | g_cancellable_cancel (cancellable); |
194 | g_object_unref (object: cancellable); |
195 | wait_for_write (FALSE, written: 0); |
196 | |
197 | /* Start it again */ |
198 | g_output_stream_write_all_async (stream: out, buffer: "0123456789" , count: 10, io_priority: 0, NULL, callback: write_done, NULL); |
199 | while (g_main_context_iteration (NULL, FALSE)) |
200 | ; |
201 | g_assert (!got_write_done); |
202 | |
203 | /* Now drain as much as we originally put in the buffer to make it |
204 | * block -- this will unblock the writer. |
205 | */ |
206 | while (in_flight) |
207 | { |
208 | s = g_input_stream_read (stream: in, buffer: rbuf, MIN (sizeof wbuf, in_flight), NULL, error: &error); |
209 | g_assert_no_error (error); |
210 | g_assert (s > 0); |
211 | in_flight -= s; |
212 | } |
213 | |
214 | /* That will have caused some writing to start happening. Do a |
215 | * read_all as well, for more bytes than was written. |
216 | */ |
217 | g_input_stream_read_all_async (stream: in, buffer: rbuf, count: sizeof rbuf, io_priority: 0, NULL, callback: read_done, NULL); |
218 | |
219 | /* The write is surely finished by now */ |
220 | wait_for_write (TRUE, written: 10); |
221 | /* ...but the read will not yet be satisfied */ |
222 | g_assert (!got_read_done); |
223 | |
224 | /* Feed the read more than it asked for; this really should not block |
225 | * since the buffer is so small... |
226 | */ |
227 | g_output_stream_write_all (stream: out, buffer: wbuf, count: sizeof wbuf, bytes_written: 0, NULL, error: &error); |
228 | g_assert_no_error (error); |
229 | |
230 | /* Read will have finished now */ |
231 | wait_for_read (TRUE, read: sizeof rbuf); |
232 | |
233 | /* Close the writer end to make an EOF condition */ |
234 | g_output_stream_close (stream: out, NULL, NULL); |
235 | |
236 | /* ... and we should have exactly 10 extra bytes left in the buffer */ |
237 | g_input_stream_read_all_async (stream: in, buffer: rbuf, count: sizeof rbuf, io_priority: 0, NULL, callback: read_done, NULL); |
238 | wait_for_read (TRUE, read: 10); |
239 | |
240 | g_object_unref (object: out); |
241 | g_object_unref (object: in); |
242 | } |
243 | #endif |
244 | |
245 | int |
246 | main (int argc, |
247 | char **argv) |
248 | { |
249 | g_test_init (argc: &argc, argv: &argv, NULL); |
250 | |
251 | g_test_add_func (testpath: "/stream/read_all_async/memory" , test_func: test_read_all_async_memory); |
252 | g_test_add_func (testpath: "/stream/write_all_async/memory" , test_func: test_write_all_async_memory); |
253 | #ifdef G_OS_UNIX |
254 | g_test_add_func (testpath: "/stream/read_write_all_async/pipe" , test_func: test_read_write_all_async_pipe); |
255 | #endif |
256 | |
257 | return g_test_run(); |
258 | } |
259 | |