1 | /* |
2 | * Copyright © 2009 Codethink 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 | * See the included COPYING file for more information. |
10 | * |
11 | * Author: Ryan Lortie <desrt@desrt.ca> |
12 | */ |
13 | |
14 | #include <string.h> |
15 | #include <glib/glib.h> |
16 | #include <gio/gio.h> |
17 | |
18 | /* GFilterInputStream and GFilterOutputStream are abstract, so define |
19 | * minimal subclasses for testing. (This used to use |
20 | * GBufferedInputStream and GBufferedOutputStream, but those have |
21 | * their own test program, and they override some methods, meaning the |
22 | * core filter stream functionality wasn't getting fully tested.) |
23 | */ |
24 | |
25 | GType test_filter_input_stream_get_type (void); |
26 | GType test_filter_output_stream_get_type (void); |
27 | |
28 | #define TEST_TYPE_FILTER_INPUT_STREAM (test_filter_input_stream_get_type ()) |
29 | #define TEST_FILTER_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TEST_TYPE_FILTER_INPUT_STREAM, TestFilterInputStream)) |
30 | #define TEST_TYPE_FILTER_OUTPUT_STREAM (test_filter_output_stream_get_type ()) |
31 | #define TEST_FILTER_OUTPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TEST_TYPE_FILTER_OUTPUT_STREAM, TestFilterOutputStream)) |
32 | |
33 | typedef GFilterInputStream TestFilterInputStream; |
34 | typedef GFilterInputStreamClass TestFilterInputStreamClass; |
35 | typedef GFilterOutputStream TestFilterOutputStream; |
36 | typedef GFilterOutputStreamClass TestFilterOutputStreamClass; |
37 | |
38 | G_DEFINE_TYPE (TestFilterInputStream, test_filter_input_stream, G_TYPE_FILTER_INPUT_STREAM) |
39 | G_DEFINE_TYPE (TestFilterOutputStream, test_filter_output_stream, G_TYPE_FILTER_OUTPUT_STREAM) |
40 | |
41 | static void |
42 | test_filter_input_stream_init (TestFilterInputStream *stream) |
43 | { |
44 | } |
45 | |
46 | static void |
47 | test_filter_input_stream_class_init (TestFilterInputStreamClass *klass) |
48 | { |
49 | } |
50 | |
51 | static void |
52 | test_filter_output_stream_init (TestFilterOutputStream *stream) |
53 | { |
54 | } |
55 | |
56 | static void |
57 | test_filter_output_stream_class_init (TestFilterOutputStreamClass *klass) |
58 | { |
59 | } |
60 | |
61 | /* Now the tests */ |
62 | |
63 | static void |
64 | test_input_filter (void) |
65 | { |
66 | GInputStream *base, *f1, *f2, *s; |
67 | gboolean close_base; |
68 | gchar buf[1024]; |
69 | GError *error = NULL; |
70 | |
71 | g_test_bug (bug_uri_snippet: "568394" ); |
72 | base = g_memory_input_stream_new_from_data (data: "abcdefghijk" , len: -1, NULL); |
73 | f1 = g_object_new (TEST_TYPE_FILTER_INPUT_STREAM, |
74 | first_property_name: "base-stream" , base, |
75 | "close-base-stream" , FALSE, |
76 | NULL); |
77 | f2 = g_object_new (TEST_TYPE_FILTER_INPUT_STREAM, |
78 | first_property_name: "base-stream" , base, |
79 | NULL); |
80 | |
81 | g_assert (g_filter_input_stream_get_base_stream (G_FILTER_INPUT_STREAM (f1)) == base); |
82 | g_assert (g_filter_input_stream_get_base_stream (G_FILTER_INPUT_STREAM (f2)) == base); |
83 | |
84 | g_assert (!g_input_stream_is_closed (base)); |
85 | g_assert (!g_input_stream_is_closed (f1)); |
86 | g_assert (!g_input_stream_is_closed (f2)); |
87 | |
88 | g_object_get (object: f1, |
89 | first_property_name: "close-base-stream" , &close_base, |
90 | "base-stream" , &s, |
91 | NULL); |
92 | g_assert (!close_base); |
93 | g_assert (s == base); |
94 | g_object_unref (object: s); |
95 | |
96 | g_object_unref (object: f1); |
97 | |
98 | g_assert (!g_input_stream_is_closed (base)); |
99 | g_assert (!g_input_stream_is_closed (f2)); |
100 | |
101 | g_input_stream_skip (stream: f2, count: 3, NULL, error: &error); |
102 | g_assert_no_error (error); |
103 | |
104 | memset (s: buf, c: 0, n: 1024); |
105 | g_input_stream_read_all (stream: f2, buffer: buf, count: 1024, NULL, NULL, error: &error); |
106 | g_assert_no_error (error); |
107 | g_assert_cmpstr (buf, ==, "defghijk" ); |
108 | |
109 | g_object_unref (object: f2); |
110 | |
111 | g_assert (g_input_stream_is_closed (base)); |
112 | |
113 | g_object_unref (object: base); |
114 | } |
115 | |
116 | static void |
117 | test_output_filter (void) |
118 | { |
119 | GOutputStream *base, *f1, *f2; |
120 | |
121 | base = g_memory_output_stream_new (NULL, size: 0, realloc_function: g_realloc, destroy_function: g_free); |
122 | f1 = g_object_new (TEST_TYPE_FILTER_OUTPUT_STREAM, |
123 | first_property_name: "base-stream" , base, |
124 | "close-base-stream" , FALSE, |
125 | NULL); |
126 | f2 = g_object_new (TEST_TYPE_FILTER_OUTPUT_STREAM, |
127 | first_property_name: "base-stream" , base, |
128 | NULL); |
129 | |
130 | g_assert (g_filter_output_stream_get_base_stream (G_FILTER_OUTPUT_STREAM (f1)) == base); |
131 | g_assert (g_filter_output_stream_get_base_stream (G_FILTER_OUTPUT_STREAM (f2)) == base); |
132 | |
133 | g_assert (!g_output_stream_is_closed (base)); |
134 | g_assert (!g_output_stream_is_closed (f1)); |
135 | g_assert (!g_output_stream_is_closed (f2)); |
136 | |
137 | g_object_unref (object: f1); |
138 | |
139 | g_assert (!g_output_stream_is_closed (base)); |
140 | g_assert (!g_output_stream_is_closed (f2)); |
141 | |
142 | g_object_unref (object: f2); |
143 | |
144 | g_assert (g_output_stream_is_closed (base)); |
145 | |
146 | g_object_unref (object: base); |
147 | } |
148 | |
149 | gpointer expected_obj; |
150 | gpointer expected_data; |
151 | gboolean callback_happened; |
152 | GMainLoop *loop; |
153 | |
154 | static void |
155 | return_result_cb (GObject *object, |
156 | GAsyncResult *result, |
157 | gpointer user_data) |
158 | { |
159 | GAsyncResult **ret = user_data; |
160 | |
161 | *ret = g_object_ref (result); |
162 | g_main_loop_quit (loop); |
163 | } |
164 | |
165 | static void |
166 | in_cb (GObject *object, |
167 | GAsyncResult *result, |
168 | gpointer user_data) |
169 | { |
170 | GError *error = NULL; |
171 | |
172 | g_assert (object == expected_obj); |
173 | g_assert (user_data == expected_data); |
174 | g_assert (callback_happened == FALSE); |
175 | |
176 | g_input_stream_close_finish (stream: expected_obj, result, error: &error); |
177 | g_assert (error == NULL); |
178 | |
179 | callback_happened = TRUE; |
180 | g_main_loop_quit (loop); |
181 | } |
182 | |
183 | static void |
184 | test_input_async (void) |
185 | { |
186 | GInputStream *base, *f1, *f2; |
187 | char buf[20]; |
188 | GAsyncResult *result = NULL; |
189 | GError *error = NULL; |
190 | |
191 | loop = g_main_loop_new (NULL, FALSE); |
192 | |
193 | base = g_memory_input_stream_new_from_data (data: "abcdefghijklmnopqrstuvwxyz" , len: -1, NULL); |
194 | f1 = g_object_new (TEST_TYPE_FILTER_INPUT_STREAM, |
195 | first_property_name: "base-stream" , base, |
196 | "close-base-stream" , FALSE, |
197 | NULL); |
198 | f2 = g_object_new (TEST_TYPE_FILTER_INPUT_STREAM, |
199 | first_property_name: "base-stream" , base, |
200 | NULL); |
201 | |
202 | g_assert (g_filter_input_stream_get_base_stream (G_FILTER_INPUT_STREAM (f1)) == base); |
203 | g_assert (g_filter_input_stream_get_base_stream (G_FILTER_INPUT_STREAM (f2)) == base); |
204 | |
205 | |
206 | memset (s: buf, c: 0, n: sizeof (buf)); |
207 | g_input_stream_read_async (stream: f1, buffer: buf, count: 10, G_PRIORITY_DEFAULT, |
208 | NULL, callback: return_result_cb, user_data: &result); |
209 | g_main_loop_run (loop); |
210 | g_assert_cmpint (g_input_stream_read_finish (f1, result, &error), ==, 10); |
211 | g_assert_cmpstr (buf, ==, "abcdefghij" ); |
212 | g_assert_no_error (error); |
213 | g_clear_object (&result); |
214 | |
215 | g_assert_cmpint (g_seekable_tell (G_SEEKABLE (base)), ==, 10); |
216 | |
217 | g_input_stream_skip_async (stream: f2, count: 10, G_PRIORITY_DEFAULT, |
218 | NULL, callback: return_result_cb, user_data: &result); |
219 | g_main_loop_run (loop); |
220 | g_assert_cmpint (g_input_stream_skip_finish (f2, result, &error), ==, 10); |
221 | g_assert_no_error (error); |
222 | g_clear_object (&result); |
223 | |
224 | g_assert_cmpint (g_seekable_tell (G_SEEKABLE (base)), ==, 20); |
225 | |
226 | memset (s: buf, c: 0, n: sizeof (buf)); |
227 | g_input_stream_read_async (stream: f1, buffer: buf, count: 10, G_PRIORITY_DEFAULT, |
228 | NULL, callback: return_result_cb, user_data: &result); |
229 | g_main_loop_run (loop); |
230 | g_assert_cmpint (g_input_stream_read_finish (f1, result, &error), ==, 6); |
231 | g_assert_cmpstr (buf, ==, "uvwxyz" ); |
232 | g_assert_no_error (error); |
233 | g_clear_object (&result); |
234 | |
235 | g_assert_cmpint (g_seekable_tell (G_SEEKABLE (base)), ==, 26); |
236 | |
237 | |
238 | g_assert (!g_input_stream_is_closed (base)); |
239 | g_assert (!g_input_stream_is_closed (f1)); |
240 | g_assert (!g_input_stream_is_closed (f2)); |
241 | |
242 | expected_obj = f1; |
243 | expected_data = g_malloc (n_bytes: 20); |
244 | callback_happened = FALSE; |
245 | g_input_stream_close_async (stream: f1, io_priority: 0, NULL, callback: in_cb, user_data: expected_data); |
246 | |
247 | g_assert (callback_happened == FALSE); |
248 | g_main_loop_run (loop); |
249 | g_assert (callback_happened == TRUE); |
250 | |
251 | g_assert (!g_input_stream_is_closed (base)); |
252 | g_assert (!g_input_stream_is_closed (f2)); |
253 | g_free (mem: expected_data); |
254 | g_object_unref (object: f1); |
255 | g_assert (!g_input_stream_is_closed (base)); |
256 | g_assert (!g_input_stream_is_closed (f2)); |
257 | |
258 | expected_obj = f2; |
259 | expected_data = g_malloc (n_bytes: 20); |
260 | callback_happened = FALSE; |
261 | g_input_stream_close_async (stream: f2, io_priority: 0, NULL, callback: in_cb, user_data: expected_data); |
262 | |
263 | g_assert (callback_happened == FALSE); |
264 | g_main_loop_run (loop); |
265 | g_assert (callback_happened == TRUE); |
266 | |
267 | g_assert (g_input_stream_is_closed (base)); |
268 | g_assert (g_input_stream_is_closed (f2)); |
269 | g_free (mem: expected_data); |
270 | g_object_unref (object: f2); |
271 | |
272 | g_assert (g_input_stream_is_closed (base)); |
273 | g_object_unref (object: base); |
274 | g_main_loop_unref (loop); |
275 | } |
276 | |
277 | static void |
278 | out_cb (GObject *object, |
279 | GAsyncResult *result, |
280 | gpointer user_data) |
281 | { |
282 | GError *error = NULL; |
283 | |
284 | g_assert (object == expected_obj); |
285 | g_assert (user_data == expected_data); |
286 | g_assert (callback_happened == FALSE); |
287 | |
288 | g_output_stream_close_finish (stream: expected_obj, result, error: &error); |
289 | g_assert (error == NULL); |
290 | |
291 | callback_happened = TRUE; |
292 | g_main_loop_quit (loop); |
293 | } |
294 | |
295 | static void |
296 | test_output_async (void) |
297 | { |
298 | GOutputStream *base, *f1, *f2; |
299 | GAsyncResult *result = NULL; |
300 | GError *error = NULL; |
301 | |
302 | loop = g_main_loop_new (NULL, FALSE); |
303 | |
304 | base = g_memory_output_stream_new (NULL, size: 0, realloc_function: g_realloc, destroy_function: g_free); |
305 | f1 = g_object_new (TEST_TYPE_FILTER_OUTPUT_STREAM, |
306 | first_property_name: "base-stream" , base, |
307 | "close-base-stream" , FALSE, |
308 | NULL); |
309 | f2 = g_object_new (TEST_TYPE_FILTER_OUTPUT_STREAM, |
310 | first_property_name: "base-stream" , base, |
311 | NULL); |
312 | |
313 | g_assert (g_filter_output_stream_get_base_stream (G_FILTER_OUTPUT_STREAM (f1)) == base); |
314 | g_assert (g_filter_output_stream_get_base_stream (G_FILTER_OUTPUT_STREAM (f2)) == base); |
315 | |
316 | |
317 | g_output_stream_write_async (stream: f1, buffer: "abcdefghijklm" , count: 13, G_PRIORITY_DEFAULT, |
318 | NULL, callback: return_result_cb, user_data: &result); |
319 | g_main_loop_run (loop); |
320 | g_assert_cmpint (g_output_stream_write_finish (f1, result, &error), ==, 13); |
321 | g_assert_no_error (error); |
322 | g_clear_object (&result); |
323 | |
324 | g_assert_cmpint (g_seekable_tell (G_SEEKABLE (base)), ==, 13); |
325 | |
326 | g_output_stream_write_async (stream: f2, buffer: "nopqrstuvwxyz" , count: 13, G_PRIORITY_DEFAULT, |
327 | NULL, callback: return_result_cb, user_data: &result); |
328 | g_main_loop_run (loop); |
329 | g_assert_cmpint (g_output_stream_write_finish (f2, result, &error), ==, 13); |
330 | g_assert_no_error (error); |
331 | g_clear_object (&result); |
332 | |
333 | g_assert_cmpint (g_seekable_tell (G_SEEKABLE (base)), ==, 26); |
334 | |
335 | g_assert_cmpint (g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (base)), ==, 26); |
336 | g_output_stream_write (stream: base, buffer: "\0" , count: 1, NULL, error: &error); |
337 | g_assert_no_error (error); |
338 | g_assert_cmpstr (g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (base)), ==, "abcdefghijklmnopqrstuvwxyz" ); |
339 | |
340 | |
341 | g_assert (!g_output_stream_is_closed (base)); |
342 | g_assert (!g_output_stream_is_closed (f1)); |
343 | g_assert (!g_output_stream_is_closed (f2)); |
344 | |
345 | expected_obj = f1; |
346 | expected_data = g_malloc (n_bytes: 20); |
347 | callback_happened = FALSE; |
348 | g_output_stream_close_async (stream: f1, io_priority: 0, NULL, callback: out_cb, user_data: expected_data); |
349 | |
350 | g_assert (callback_happened == FALSE); |
351 | g_main_loop_run (loop); |
352 | g_assert (callback_happened == TRUE); |
353 | |
354 | g_assert (!g_output_stream_is_closed (base)); |
355 | g_assert (!g_output_stream_is_closed (f2)); |
356 | g_free (mem: expected_data); |
357 | g_object_unref (object: f1); |
358 | g_assert (!g_output_stream_is_closed (base)); |
359 | g_assert (!g_output_stream_is_closed (f2)); |
360 | |
361 | expected_obj = f2; |
362 | expected_data = g_malloc (n_bytes: 20); |
363 | callback_happened = FALSE; |
364 | g_output_stream_close_async (stream: f2, io_priority: 0, NULL, callback: out_cb, user_data: expected_data); |
365 | |
366 | g_assert (callback_happened == FALSE); |
367 | g_main_loop_run (loop); |
368 | g_assert (callback_happened == TRUE); |
369 | |
370 | g_assert (g_output_stream_is_closed (base)); |
371 | g_assert (g_output_stream_is_closed (f2)); |
372 | g_free (mem: expected_data); |
373 | g_object_unref (object: f2); |
374 | |
375 | g_assert (g_output_stream_is_closed (base)); |
376 | g_object_unref (object: base); |
377 | g_main_loop_unref (loop); |
378 | } |
379 | |
380 | int |
381 | main (int argc, char **argv) |
382 | { |
383 | g_test_init (argc: &argc, argv: &argv, NULL); |
384 | g_test_bug_base (uri_pattern: "http://bugzilla.gnome.org/" ); |
385 | |
386 | g_test_add_func (testpath: "/filter-stream/input" , test_func: test_input_filter); |
387 | g_test_add_func (testpath: "/filter-stream/output" , test_func: test_output_filter); |
388 | g_test_add_func (testpath: "/filter-stream/async-input" , test_func: test_input_async); |
389 | g_test_add_func (testpath: "/filter-stream/async-output" , test_func: test_output_async); |
390 | |
391 | return g_test_run(); |
392 | } |
393 | |