1 | /* GLib testing framework examples and tests |
2 | * Copyright (C) 2008 Red Hat, Inc. |
3 | * Author: Matthias Clasen |
4 | * |
5 | * This work is provided "as is"; redistribution and modification |
6 | * in whole or in part, in any medium, physical or electronic is |
7 | * permitted without restriction. |
8 | * |
9 | * This work 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. |
12 | * |
13 | * In no event shall the authors or contributors be liable for any |
14 | * direct, indirect, incidental, special, exemplary, or consequential |
15 | * damages (including, but not limited to, procurement of substitute |
16 | * goods or services; loss of use, data, or profits; or business |
17 | * interruption) however caused and on any theory of liability, whether |
18 | * in contract, strict liability, or tort (including negligence or |
19 | * otherwise) arising in any way out of the use of this software, even |
20 | * if advised of the possibility of such damage. |
21 | */ |
22 | #include <glib/glib.h> |
23 | #include <gio/gio.h> |
24 | #include <stdlib.h> |
25 | #include <string.h> |
26 | |
27 | static void |
28 | test_truncate (void) |
29 | { |
30 | GOutputStream *mo; |
31 | GDataOutputStream *o; |
32 | int i; |
33 | GError *error = NULL; |
34 | guint8 *data; |
35 | |
36 | g_test_bug (bug_uri_snippet: "540423" ); |
37 | |
38 | mo = g_memory_output_stream_new_resizable (); |
39 | g_assert (g_seekable_can_truncate (G_SEEKABLE (mo))); |
40 | o = g_data_output_stream_new (base_stream: mo); |
41 | for (i = 0; i < 1000; i++) |
42 | { |
43 | g_data_output_stream_put_byte (stream: o, data: 1, NULL, error: &error); |
44 | g_assert_no_error (error); |
45 | } |
46 | g_assert_cmpint (g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (mo)), ==, 1000); |
47 | g_seekable_truncate (G_SEEKABLE (mo), offset: 0, NULL, error: &error); |
48 | g_assert_cmpuint (g_seekable_tell (G_SEEKABLE (mo)), ==, 1000); |
49 | |
50 | g_assert_no_error (error); |
51 | g_assert_cmpint (g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (mo)), ==, 0); |
52 | for (i = 0; i < 2000; i++) |
53 | { |
54 | g_data_output_stream_put_byte (stream: o, data: 2, NULL, error: &error); |
55 | g_assert_no_error (error); |
56 | } |
57 | g_assert_cmpint (g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (mo)), ==, 3000); |
58 | |
59 | data = (guint8 *)g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (mo)); |
60 | |
61 | /* The 1's written initially were lost when we truncated to 0 |
62 | * and then started writing at position 1000. |
63 | */ |
64 | for (i = 0; i < 1000; i++) |
65 | g_assert_cmpuint (data[i], ==, 0); |
66 | for (i = 1000; i < 3000; i++) |
67 | g_assert_cmpuint (data[i], ==, 2); |
68 | |
69 | g_test_bug (bug_uri_snippet: "720080" ); |
70 | |
71 | g_seekable_truncate (G_SEEKABLE (mo), offset: 8192, NULL, error: &error); |
72 | g_assert_cmpint (g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (mo)), ==, 8192); |
73 | |
74 | data = (guint8 *)g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (mo)); |
75 | for (i = 3000; i < 8192; i++) |
76 | g_assert_cmpuint (data[i], ==, 0); |
77 | |
78 | g_object_unref (object: o); |
79 | g_object_unref (object: mo); |
80 | } |
81 | |
82 | static void |
83 | test_seek_fixed (void) |
84 | { |
85 | GOutputStream *mo; |
86 | GError *error; |
87 | |
88 | mo = g_memory_output_stream_new (g_new (gchar, 100), size: 100, NULL, destroy_function: g_free); |
89 | |
90 | g_assert (G_IS_SEEKABLE (mo)); |
91 | g_assert (g_seekable_can_seek (G_SEEKABLE (mo))); |
92 | g_assert_cmpint (g_seekable_tell (G_SEEKABLE (mo)), ==, 0); |
93 | |
94 | error = NULL; |
95 | g_assert (!g_seekable_seek (G_SEEKABLE (mo), 222, G_SEEK_CUR, NULL, &error)); |
96 | g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT); |
97 | g_clear_error (err: &error); |
98 | g_assert_cmpint (g_seekable_tell (G_SEEKABLE (mo)), ==, 0); |
99 | |
100 | g_assert (g_seekable_seek (G_SEEKABLE (mo), 26, G_SEEK_SET, NULL, &error)); |
101 | g_assert_no_error (error); |
102 | g_assert_cmpint (g_seekable_tell (G_SEEKABLE (mo)), ==, 26); |
103 | |
104 | g_assert (g_seekable_seek (G_SEEKABLE (mo), 20, G_SEEK_CUR, NULL, &error)); |
105 | g_assert_cmpint (g_seekable_tell (G_SEEKABLE (mo)), ==, 46); |
106 | g_assert_no_error (error); |
107 | |
108 | g_assert (!g_seekable_seek (G_SEEKABLE (mo), 200, G_SEEK_CUR, NULL, &error)); |
109 | g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT); |
110 | g_clear_error (err: &error); |
111 | g_assert_cmpint (g_seekable_tell (G_SEEKABLE (mo)), ==, 46); |
112 | |
113 | g_assert (!g_seekable_seek (G_SEEKABLE (mo), 1, G_SEEK_END, NULL, &error)); |
114 | g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT); |
115 | g_clear_error (err: &error); |
116 | g_assert_cmpint (g_seekable_tell (G_SEEKABLE (mo)), ==, 46); |
117 | |
118 | g_assert (g_seekable_seek (G_SEEKABLE (mo), 0, G_SEEK_END, NULL, &error)); |
119 | g_assert_no_error (error); |
120 | g_assert_cmpint (g_seekable_tell (G_SEEKABLE (mo)), ==, 100); |
121 | |
122 | g_assert (g_seekable_seek (G_SEEKABLE (mo), -1, G_SEEK_END, NULL, &error)); |
123 | g_assert_no_error (error); |
124 | g_assert_cmpint (g_seekable_tell (G_SEEKABLE (mo)), ==, 99); |
125 | |
126 | g_object_unref (object: mo); |
127 | } |
128 | |
129 | static void |
130 | test_seek_resizable_stream (GOutputStream *mo) |
131 | { |
132 | GError *error; |
133 | |
134 | g_assert (G_IS_SEEKABLE (mo)); |
135 | g_assert (g_seekable_can_seek (G_SEEKABLE (mo))); |
136 | g_assert_cmpint (g_seekable_tell (G_SEEKABLE (mo)), ==, 0); |
137 | |
138 | error = NULL; |
139 | g_assert (g_seekable_seek (G_SEEKABLE (mo), 222, G_SEEK_CUR, NULL, &error)); |
140 | g_assert_no_error (error); |
141 | g_assert_cmpint (g_seekable_tell (G_SEEKABLE (mo)), ==, 222); |
142 | |
143 | g_assert (g_seekable_seek (G_SEEKABLE (mo), 26, G_SEEK_SET, NULL, &error)); |
144 | g_assert_no_error (error); |
145 | g_assert_cmpint (g_seekable_tell (G_SEEKABLE (mo)), ==, 26); |
146 | |
147 | g_assert (g_seekable_seek (G_SEEKABLE (mo), 20, G_SEEK_CUR, NULL, &error)); |
148 | g_assert_cmpint (g_seekable_tell (G_SEEKABLE (mo)), ==, 46); |
149 | g_assert_no_error (error); |
150 | |
151 | g_assert (g_seekable_seek (G_SEEKABLE (mo), 200, G_SEEK_CUR, NULL, &error)); |
152 | g_assert_cmpint (g_seekable_tell (G_SEEKABLE (mo)), ==, 246); |
153 | g_assert_no_error (error); |
154 | |
155 | g_assert (g_seekable_seek (G_SEEKABLE (mo), 1, G_SEEK_END, NULL, &error)); |
156 | g_assert_cmpint (g_seekable_tell (G_SEEKABLE (mo)), ==, 1); |
157 | g_assert_no_error (error); |
158 | |
159 | g_assert (g_seekable_seek (G_SEEKABLE (mo), 0, G_SEEK_END, NULL, &error)); |
160 | g_assert_no_error (error); |
161 | g_assert_cmpint (g_seekable_tell (G_SEEKABLE (mo)), ==, 0); |
162 | |
163 | /* The 'end' is still zero, so this should fail */ |
164 | g_assert (!g_seekable_seek (G_SEEKABLE (mo), -1, G_SEEK_END, NULL, &error)); |
165 | g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT); |
166 | g_clear_error (err: &error); |
167 | g_assert_cmpint (g_seekable_tell (G_SEEKABLE (mo)), ==, 0); |
168 | } |
169 | |
170 | static void |
171 | test_seek_resizable (void) |
172 | { |
173 | GOutputStream *mo; |
174 | gint i; |
175 | |
176 | /* For resizable streams, the initially allocated size is purely an |
177 | * implementation detail. We should not be able to tell the |
178 | * difference based on the seek API, so make a bunch of streams with |
179 | * different sizes and subject them to the same test. |
180 | */ |
181 | for (i = 0; i < 1024; i++) |
182 | { |
183 | mo = g_memory_output_stream_new (data: g_malloc (n_bytes: i), size: i, realloc_function: g_realloc, destroy_function: g_free); |
184 | |
185 | test_seek_resizable_stream (mo); |
186 | |
187 | g_assert_cmpint (g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (mo)), ==, 0); |
188 | /* No writes = no resizes */ |
189 | g_assert_cmpint (g_memory_output_stream_get_size (G_MEMORY_OUTPUT_STREAM (mo)), ==, i); |
190 | |
191 | g_object_unref (object: mo); |
192 | } |
193 | } |
194 | |
195 | static void |
196 | test_data_size (void) |
197 | { |
198 | GOutputStream *mo; |
199 | GDataOutputStream *o; |
200 | int pos; |
201 | |
202 | g_test_bug (bug_uri_snippet: "540459" ); |
203 | |
204 | mo = g_memory_output_stream_new_resizable (); |
205 | o = g_data_output_stream_new (base_stream: mo); |
206 | g_data_output_stream_put_byte (stream: o, data: 1, NULL, NULL); |
207 | pos = g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (mo)); |
208 | g_assert_cmpint (pos, ==, 1); |
209 | |
210 | g_seekable_seek (G_SEEKABLE (mo), offset: 0, type: G_SEEK_CUR, NULL, NULL); |
211 | pos = g_seekable_tell (G_SEEKABLE (mo)); |
212 | g_assert_cmpint (pos, ==, 1); |
213 | |
214 | g_test_bug (bug_uri_snippet: "540461" ); |
215 | |
216 | g_seekable_seek (G_SEEKABLE (mo), offset: 0, type: G_SEEK_SET, NULL, NULL); |
217 | pos = g_seekable_tell (G_SEEKABLE (mo)); |
218 | g_assert_cmpint (pos, ==, 0); |
219 | |
220 | pos = g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (mo)); |
221 | g_assert_cmpint (pos, ==, 1); |
222 | |
223 | g_assert_cmpint (g_memory_output_stream_get_size (G_MEMORY_OUTPUT_STREAM (mo)), ==, 16); |
224 | |
225 | g_object_unref (object: o); |
226 | g_object_unref (object: mo); |
227 | } |
228 | |
229 | static void |
230 | test_properties (void) |
231 | { |
232 | GOutputStream *mo; |
233 | GDataOutputStream *o; |
234 | int i; |
235 | GError *error = NULL; |
236 | gsize data_size_fun; |
237 | gsize data_size_prop = 0; |
238 | gpointer data_fun; |
239 | gpointer data_prop; |
240 | gpointer func; |
241 | |
242 | g_test_bug (bug_uri_snippet: "605733" ); |
243 | |
244 | mo = (GOutputStream*) g_object_new (G_TYPE_MEMORY_OUTPUT_STREAM, |
245 | first_property_name: "realloc-function" , g_realloc, |
246 | "destroy-function" , g_free, |
247 | NULL); |
248 | o = g_data_output_stream_new (base_stream: mo); |
249 | |
250 | for (i = 0; i < 1000; i++) |
251 | { |
252 | g_data_output_stream_put_byte (stream: o, data: 1, NULL, error: &error); |
253 | g_assert_no_error (error); |
254 | } |
255 | |
256 | data_size_fun = g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (mo)); |
257 | g_object_get (object: mo, first_property_name: "data-size" , &data_size_prop, NULL); |
258 | g_assert_cmpint (data_size_fun, ==, data_size_prop); |
259 | |
260 | data_fun = g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (mo)); |
261 | g_object_get (object: mo, first_property_name: "data" , &data_prop, NULL); |
262 | g_assert_cmphex (GPOINTER_TO_SIZE (data_fun), ==, GPOINTER_TO_SIZE (data_prop)); |
263 | |
264 | g_object_get (object: mo, first_property_name: "realloc-function" , &func, NULL); |
265 | g_assert (func == g_realloc); |
266 | g_object_get (object: mo, first_property_name: "destroy-function" , &func, NULL); |
267 | g_assert (func == g_free); |
268 | |
269 | data_size_fun = g_memory_output_stream_get_size (G_MEMORY_OUTPUT_STREAM (mo)); |
270 | g_object_get (object: mo, first_property_name: "size" , &data_size_prop, NULL); |
271 | g_assert_cmpint (data_size_fun, ==, data_size_prop); |
272 | |
273 | g_object_unref (object: o); |
274 | g_object_unref (object: mo); |
275 | } |
276 | |
277 | static void |
278 | test_write_bytes (void) |
279 | { |
280 | GOutputStream *mo; |
281 | GBytes *bytes, *bytes2; |
282 | GError *error = NULL; |
283 | |
284 | mo = (GOutputStream*) g_object_new (G_TYPE_MEMORY_OUTPUT_STREAM, |
285 | first_property_name: "realloc-function" , g_realloc, |
286 | "destroy-function" , g_free, |
287 | NULL); |
288 | bytes = g_bytes_new_static (data: "hello world!" , size: strlen (s: "hello world!" ) + 1); |
289 | g_output_stream_write_bytes (stream: mo, bytes, NULL, error: &error); |
290 | g_assert_no_error (error); |
291 | |
292 | g_output_stream_close (stream: mo, NULL, error: &error); |
293 | g_assert_no_error (error); |
294 | |
295 | bytes2 = g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (mo)); |
296 | g_object_unref (object: mo); |
297 | g_assert (g_bytes_equal (bytes, bytes2)); |
298 | |
299 | g_bytes_unref (bytes); |
300 | g_bytes_unref (bytes: bytes2); |
301 | } |
302 | |
303 | /* Test that writev() works on #GMemoryOutputStream with a non-empty set of vectors. This |
304 | * covers the default writev() implementation around write(). */ |
305 | static void |
306 | test_writev (void) |
307 | { |
308 | GOutputStream *mo; |
309 | GError *error = NULL; |
310 | gboolean res; |
311 | gsize bytes_written; |
312 | GOutputVector vectors[3]; |
313 | const guint8 buffer[] = {1, 2, 3, 4, 5, |
314 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, |
315 | 1, 2, 3}; |
316 | guint8 *output_buffer; |
317 | |
318 | vectors[0].buffer = buffer; |
319 | vectors[0].size = 5; |
320 | |
321 | vectors[1].buffer = buffer + vectors[0].size; |
322 | vectors[1].size = 12; |
323 | |
324 | vectors[2].buffer = buffer + vectors[0].size + vectors[1].size; |
325 | vectors[2].size = 3; |
326 | |
327 | mo = (GOutputStream*) g_object_new (G_TYPE_MEMORY_OUTPUT_STREAM, |
328 | first_property_name: "realloc-function" , g_realloc, |
329 | "destroy-function" , g_free, |
330 | NULL); |
331 | res = g_output_stream_writev_all (stream: mo, vectors, G_N_ELEMENTS (vectors), bytes_written: &bytes_written, NULL, error: &error); |
332 | g_assert_no_error (error); |
333 | g_assert_true (res); |
334 | g_assert_cmpuint (bytes_written, ==, sizeof buffer); |
335 | |
336 | g_output_stream_close (stream: mo, NULL, error: &error); |
337 | g_assert_no_error (error); |
338 | |
339 | g_assert_cmpuint (g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (mo)), ==, sizeof buffer); |
340 | output_buffer = g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (mo)); |
341 | g_assert_cmpmem (output_buffer, sizeof buffer, buffer, sizeof buffer); |
342 | |
343 | g_object_unref (object: mo); |
344 | } |
345 | |
346 | /* Test that writev_nonblocking() works on #GMemoryOutputStream with a non-empty set of vectors. This |
347 | * covers the default writev_nonblocking() implementation around write_nonblocking(). */ |
348 | static void |
349 | test_writev_nonblocking (void) |
350 | { |
351 | GOutputStream *mo; |
352 | GError *error = NULL; |
353 | gboolean res; |
354 | gsize bytes_written; |
355 | GOutputVector vectors[3]; |
356 | const guint8 buffer[] = {1, 2, 3, 4, 5, |
357 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, |
358 | 1, 2, 3}; |
359 | guint8 *output_buffer; |
360 | |
361 | vectors[0].buffer = buffer; |
362 | vectors[0].size = 5; |
363 | |
364 | vectors[1].buffer = buffer + vectors[0].size; |
365 | vectors[1].size = 12; |
366 | |
367 | vectors[2].buffer = buffer + vectors[0].size + vectors[1].size; |
368 | vectors[2].size = 3; |
369 | |
370 | mo = (GOutputStream*) g_object_new (G_TYPE_MEMORY_OUTPUT_STREAM, |
371 | first_property_name: "realloc-function" , g_realloc, |
372 | "destroy-function" , g_free, |
373 | NULL); |
374 | res = g_pollable_output_stream_writev_nonblocking (G_POLLABLE_OUTPUT_STREAM (mo), |
375 | vectors, G_N_ELEMENTS (vectors), |
376 | bytes_written: &bytes_written, NULL, error: &error); |
377 | g_assert_no_error (error); |
378 | g_assert_cmpint (res, ==, G_POLLABLE_RETURN_OK); |
379 | g_assert_cmpuint (bytes_written, ==, sizeof buffer); |
380 | |
381 | g_output_stream_close (stream: mo, NULL, error: &error); |
382 | g_assert_no_error (error); |
383 | |
384 | g_assert_cmpuint (g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (mo)), ==, sizeof buffer); |
385 | output_buffer = g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (mo)); |
386 | g_assert_cmpmem (output_buffer, sizeof buffer, buffer, sizeof buffer); |
387 | |
388 | g_object_unref (object: mo); |
389 | } |
390 | |
391 | static void |
392 | test_steal_as_bytes (void) |
393 | { |
394 | GOutputStream *mo; |
395 | GDataOutputStream *o; |
396 | GError *error = NULL; |
397 | GBytes *bytes; |
398 | gsize size; |
399 | |
400 | mo = (GOutputStream*) g_object_new (G_TYPE_MEMORY_OUTPUT_STREAM, |
401 | first_property_name: "realloc-function" , g_realloc, |
402 | "destroy-function" , g_free, |
403 | NULL); |
404 | o = g_data_output_stream_new (base_stream: mo); |
405 | |
406 | g_data_output_stream_put_string (stream: o, str: "hello " , NULL, error: &error); |
407 | g_assert_no_error (error); |
408 | |
409 | g_data_output_stream_put_string (stream: o, str: "world!" , NULL, error: &error); |
410 | g_assert_no_error (error); |
411 | |
412 | g_data_output_stream_put_byte (stream: o, data: '\0', NULL, error: &error); |
413 | g_assert_no_error (error); |
414 | |
415 | g_output_stream_close (stream: (GOutputStream*) o, NULL, error: &error); |
416 | g_assert_no_error (error); |
417 | |
418 | bytes = g_memory_output_stream_steal_as_bytes (ostream: (GMemoryOutputStream*)mo); |
419 | g_object_unref (object: mo); |
420 | |
421 | g_assert_cmpint (g_bytes_get_size (bytes), ==, strlen ("hello world!" ) + 1); |
422 | g_assert_cmpstr (g_bytes_get_data (bytes, &size), ==, "hello world!" ); |
423 | |
424 | g_bytes_unref (bytes); |
425 | g_object_unref (object: o); |
426 | } |
427 | |
428 | int |
429 | main (int argc, |
430 | char *argv[]) |
431 | { |
432 | g_test_init (argc: &argc, argv: &argv, NULL); |
433 | g_test_bug_base (uri_pattern: "http://bugzilla.gnome.org/" ); |
434 | |
435 | g_test_add_func (testpath: "/memory-output-stream/truncate" , test_func: test_truncate); |
436 | g_test_add_func (testpath: "/memory-output-stream/seek/fixed" , test_func: test_seek_fixed); |
437 | g_test_add_func (testpath: "/memory-output-stream/seek/resizable" , test_func: test_seek_resizable); |
438 | g_test_add_func (testpath: "/memory-output-stream/get-data-size" , test_func: test_data_size); |
439 | g_test_add_func (testpath: "/memory-output-stream/properties" , test_func: test_properties); |
440 | g_test_add_func (testpath: "/memory-output-stream/write-bytes" , test_func: test_write_bytes); |
441 | g_test_add_func (testpath: "/memory-output-stream/writev" , test_func: test_writev); |
442 | g_test_add_func (testpath: "/memory-output-stream/writev_nonblocking" , test_func: test_writev_nonblocking); |
443 | g_test_add_func (testpath: "/memory-output-stream/steal_as_bytes" , test_func: test_steal_as_bytes); |
444 | |
445 | return g_test_run(); |
446 | } |
447 | |