1 | /* GLib testing framework examples and tests |
2 | * Authors: Jesse van den Kieboom <jessevdk@gnome.org> |
3 | * |
4 | * This work is provided "as is"; redistribution and modification |
5 | * in whole or in part, in any medium, physical or electronic is |
6 | * permitted without restriction. |
7 | * |
8 | * This work is distributed in the hope that it will be useful, |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
11 | * |
12 | * In no event shall the authors or contributors be liable for any |
13 | * direct, indirect, incidental, special, exemplary, or consequential |
14 | * damages (including, but not limited to, procurement of substitute |
15 | * goods or services; loss of use, data, or profits; or business |
16 | * interruption) however caused and on any theory of liability, whether |
17 | * in contract, strict liability, or tort (including negligence or |
18 | * otherwise) arising in any way out of the use of this software, even |
19 | * if advised of the possibility of such damage. |
20 | */ |
21 | |
22 | #include <glib/glib.h> |
23 | #include <gio/gio.h> |
24 | #include <stdlib.h> |
25 | #include <string.h> |
26 | |
27 | #define DATA_TO_WRITE "Hello world\n" |
28 | |
29 | typedef struct |
30 | { |
31 | GOutputStream *conv_stream; |
32 | GOutputStream *data_stream; |
33 | gchar *expected_output; |
34 | gsize expected_size; |
35 | GMainLoop *main_loop; |
36 | } SetupData; |
37 | |
38 | static void |
39 | create_streams (SetupData *data) |
40 | { |
41 | GConverter *converter; |
42 | |
43 | converter = G_CONVERTER (g_zlib_compressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP, -1)); |
44 | |
45 | data->data_stream = g_memory_output_stream_new (NULL, size: 0, realloc_function: g_realloc, destroy_function: g_free); |
46 | data->conv_stream = g_converter_output_stream_new (base_stream: data->data_stream, |
47 | converter); |
48 | |
49 | g_object_unref (object: converter); |
50 | } |
51 | |
52 | static void |
53 | destroy_streams (SetupData *data) |
54 | { |
55 | g_object_unref (object: data->data_stream); |
56 | g_object_unref (object: data->conv_stream); |
57 | } |
58 | |
59 | static void |
60 | write_data_to_stream (SetupData *data) |
61 | { |
62 | gsize bytes_written; |
63 | GError *error = NULL; |
64 | |
65 | /* just write the data synchronously */ |
66 | g_output_stream_write_all (stream: data->conv_stream, |
67 | DATA_TO_WRITE, |
68 | count: sizeof (DATA_TO_WRITE), |
69 | bytes_written: &bytes_written, |
70 | NULL, |
71 | error: &error); |
72 | |
73 | g_assert_no_error (error); |
74 | g_assert_cmpint (sizeof (DATA_TO_WRITE), ==, bytes_written); |
75 | } |
76 | |
77 | static void |
78 | setup_data (SetupData *data, |
79 | gconstpointer user_data) |
80 | { |
81 | data->main_loop = g_main_loop_new (NULL, FALSE); |
82 | create_streams (data); |
83 | } |
84 | |
85 | static void |
86 | teardown_data (SetupData *data, |
87 | gconstpointer user_data) |
88 | { |
89 | /* cleanup */ |
90 | g_main_loop_unref (loop: data->main_loop); |
91 | |
92 | destroy_streams (data); |
93 | |
94 | g_free (mem: data->expected_output); |
95 | } |
96 | |
97 | static void |
98 | compare_output (SetupData *data) |
99 | { |
100 | gsize size; |
101 | gpointer written; |
102 | |
103 | written = g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (data->data_stream)); |
104 | size = g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (data->data_stream)); |
105 | |
106 | g_assert_cmpmem (written, size, data->expected_output, data->expected_size); |
107 | } |
108 | |
109 | static void |
110 | async_close_ready (GOutputStream *stream, |
111 | GAsyncResult *result, |
112 | SetupData *data) |
113 | { |
114 | GError *error = NULL; |
115 | |
116 | /* finish the close */ |
117 | g_output_stream_close_finish (stream, result, error: &error); |
118 | |
119 | g_assert_no_error (error); |
120 | |
121 | /* compare the output with the desired output */ |
122 | compare_output (data); |
123 | |
124 | g_main_loop_quit (loop: data->main_loop); |
125 | } |
126 | |
127 | static void |
128 | prepare_data (SetupData *data, |
129 | gboolean manual_flush) |
130 | { |
131 | GError *error = NULL; |
132 | gpointer written; |
133 | |
134 | write_data_to_stream (data); |
135 | |
136 | if (manual_flush) |
137 | { |
138 | g_output_stream_flush (stream: data->conv_stream, NULL, error: &error); |
139 | g_assert_no_error (error); |
140 | } |
141 | |
142 | g_output_stream_close (stream: data->conv_stream, NULL, error: &error); |
143 | |
144 | g_assert_no_error (error); |
145 | |
146 | written = g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (data->data_stream)); |
147 | |
148 | data->expected_size = g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (data->data_stream)); |
149 | |
150 | g_assert_cmpuint (data->expected_size, >, 0); |
151 | |
152 | data->expected_output = g_memdup2 (mem: written, byte_size: data->expected_size); |
153 | |
154 | /* then recreate the streams and prepare them for the asynchronous close */ |
155 | destroy_streams (data); |
156 | create_streams (data); |
157 | |
158 | write_data_to_stream (data); |
159 | } |
160 | |
161 | static void |
162 | test_without_flush (SetupData *data, |
163 | gconstpointer user_data) |
164 | { |
165 | prepare_data (data, FALSE); |
166 | |
167 | g_test_bug (bug_uri_snippet: "617937" ); |
168 | |
169 | /* just close asynchronously */ |
170 | g_output_stream_close_async (stream: data->conv_stream, |
171 | G_PRIORITY_DEFAULT, |
172 | NULL, |
173 | callback: (GAsyncReadyCallback)async_close_ready, |
174 | user_data: data); |
175 | |
176 | g_main_loop_run (loop: data->main_loop); |
177 | } |
178 | |
179 | static void |
180 | test_with_flush (SetupData *data, gconstpointer user_data) |
181 | { |
182 | GError *error = NULL; |
183 | |
184 | g_test_bug (bug_uri_snippet: "617937" ); |
185 | |
186 | prepare_data (data, TRUE); |
187 | |
188 | g_output_stream_flush (stream: data->conv_stream, NULL, error: &error); |
189 | |
190 | g_assert_no_error (error); |
191 | |
192 | /* then close asynchronously */ |
193 | g_output_stream_close_async (stream: data->conv_stream, |
194 | G_PRIORITY_DEFAULT, |
195 | NULL, |
196 | callback: (GAsyncReadyCallback)async_close_ready, |
197 | user_data: data); |
198 | |
199 | g_main_loop_run (loop: data->main_loop); |
200 | } |
201 | |
202 | static void |
203 | async_flush_ready (GOutputStream *stream, |
204 | GAsyncResult *result, |
205 | SetupData *data) |
206 | { |
207 | GError *error = NULL; |
208 | |
209 | g_output_stream_flush_finish (stream, result, error: &error); |
210 | |
211 | g_assert_no_error (error); |
212 | |
213 | /* then close async after the flush */ |
214 | g_output_stream_close_async (stream: data->conv_stream, |
215 | G_PRIORITY_DEFAULT, |
216 | NULL, |
217 | callback: (GAsyncReadyCallback)async_close_ready, |
218 | user_data: data); |
219 | } |
220 | |
221 | static void |
222 | test_with_async_flush (SetupData *data, |
223 | gconstpointer user_data) |
224 | { |
225 | g_test_bug (bug_uri_snippet: "617937" ); |
226 | |
227 | prepare_data (data, TRUE); |
228 | |
229 | /* first flush async */ |
230 | g_output_stream_flush_async (stream: data->conv_stream, |
231 | G_PRIORITY_DEFAULT, |
232 | NULL, |
233 | callback: (GAsyncReadyCallback)async_flush_ready, |
234 | user_data: data); |
235 | |
236 | g_main_loop_run (loop: data->main_loop); |
237 | } |
238 | |
239 | int |
240 | main (int argc, |
241 | char *argv[]) |
242 | { |
243 | SetupData *data; |
244 | |
245 | g_test_init (argc: &argc, argv: &argv, NULL); |
246 | |
247 | g_test_bug_base (uri_pattern: "http://bugzilla.gnome.org/" ); |
248 | |
249 | data = g_slice_new (SetupData); |
250 | |
251 | /* test closing asynchronously without flushing manually */ |
252 | g_test_add ("/close-async/without-flush" , |
253 | SetupData, |
254 | data, |
255 | setup_data, |
256 | test_without_flush, |
257 | teardown_data); |
258 | |
259 | /* test closing asynchronously with a synchronous manually flush */ |
260 | g_test_add ("/close-async/with-flush" , |
261 | SetupData, |
262 | data, |
263 | setup_data, |
264 | test_with_flush, |
265 | teardown_data); |
266 | |
267 | /* test closing asynchronously with an asynchronous manually flush */ |
268 | g_test_add ("/close-async/with-async-flush" , |
269 | SetupData, |
270 | data, |
271 | setup_data, |
272 | test_with_async_flush, |
273 | teardown_data); |
274 | |
275 | g_slice_free (SetupData, data); |
276 | |
277 | return g_test_run(); |
278 | } |
279 | |