1 | /* GLib testing framework examples and tests |
2 | * Copyright (C) 2009 Red Hat, Inc. |
3 | * Authors: Alexander Larsson <alexl@redhat.com> |
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 | |
23 | #include <glib/glib.h> |
24 | #include <gio/gio.h> |
25 | #include <stdlib.h> |
26 | #include <string.h> |
27 | |
28 | #define G_TYPE_EXPANDER_CONVERTER (g_expander_converter_get_type ()) |
29 | #define G_EXPANDER_CONVERTER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_EXPANDER_CONVERTER, GExpanderConverter)) |
30 | #define G_EXPANDER_CONVERTER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_EXPANDER_CONVERTER, GExpanderConverterClass)) |
31 | #define G_IS_EXPANDER_CONVERTER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_EXPANDER_CONVERTER)) |
32 | #define G_IS_EXPANDER_CONVERTER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_EXPANDER_CONVERTER)) |
33 | #define G_EXPANDER_CONVERTER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_EXPANDER_CONVERTER, GExpanderConverterClass)) |
34 | |
35 | typedef struct _GExpanderConverter GExpanderConverter; |
36 | typedef struct _GExpanderConverterClass GExpanderConverterClass; |
37 | |
38 | struct _GExpanderConverterClass |
39 | { |
40 | GObjectClass parent_class; |
41 | }; |
42 | |
43 | GType g_expander_converter_get_type (void) G_GNUC_CONST; |
44 | GConverter *g_expander_converter_new (void); |
45 | |
46 | |
47 | |
48 | static void g_expander_converter_iface_init (GConverterIface *iface); |
49 | |
50 | struct _GExpanderConverter |
51 | { |
52 | GObject parent_instance; |
53 | }; |
54 | |
55 | G_DEFINE_TYPE_WITH_CODE (GExpanderConverter, g_expander_converter, G_TYPE_OBJECT, |
56 | G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER, |
57 | g_expander_converter_iface_init)) |
58 | |
59 | static void |
60 | g_expander_converter_class_init (GExpanderConverterClass *klass) |
61 | { |
62 | } |
63 | |
64 | static void |
65 | g_expander_converter_init (GExpanderConverter *local) |
66 | { |
67 | } |
68 | |
69 | GConverter * |
70 | g_expander_converter_new (void) |
71 | { |
72 | GConverter *conv; |
73 | |
74 | conv = g_object_new (G_TYPE_EXPANDER_CONVERTER, NULL); |
75 | |
76 | return conv; |
77 | } |
78 | |
79 | static void |
80 | g_expander_converter_reset (GConverter *converter) |
81 | { |
82 | } |
83 | |
84 | static GConverterResult |
85 | g_expander_converter_convert (GConverter *converter, |
86 | const void *inbuf, |
87 | gsize inbuf_size, |
88 | void *outbuf, |
89 | gsize outbuf_size, |
90 | GConverterFlags flags, |
91 | gsize *bytes_read, |
92 | gsize *bytes_written, |
93 | GError **error) |
94 | { |
95 | const guint8 *in, *in_end; |
96 | guint8 v, *out; |
97 | int i; |
98 | gsize block_size; |
99 | |
100 | in = inbuf; |
101 | out = outbuf; |
102 | in_end = in + inbuf_size; |
103 | |
104 | while (in < in_end) |
105 | { |
106 | v = *in; |
107 | |
108 | if (v == 0) |
109 | block_size = 10; |
110 | else |
111 | block_size = v * 1000; |
112 | |
113 | if (outbuf_size < block_size) |
114 | { |
115 | if (*bytes_read > 0) |
116 | return G_CONVERTER_CONVERTED; |
117 | |
118 | g_set_error_literal (err: error, G_IO_ERROR, |
119 | code: G_IO_ERROR_NO_SPACE, |
120 | message: "No space in dest" ); |
121 | return G_CONVERTER_ERROR; |
122 | } |
123 | |
124 | in++; |
125 | *bytes_read += 1; |
126 | *bytes_written += block_size; |
127 | outbuf_size -= block_size; |
128 | for (i = 0; i < block_size; i++) |
129 | *out++ = v; |
130 | } |
131 | |
132 | if (in == in_end && (flags & G_CONVERTER_INPUT_AT_END)) |
133 | return G_CONVERTER_FINISHED; |
134 | return G_CONVERTER_CONVERTED; |
135 | } |
136 | |
137 | static void |
138 | g_expander_converter_iface_init (GConverterIface *iface) |
139 | { |
140 | iface->convert = g_expander_converter_convert; |
141 | iface->reset = g_expander_converter_reset; |
142 | } |
143 | |
144 | #define G_TYPE_COMPRESSOR_CONVERTER (g_compressor_converter_get_type ()) |
145 | #define G_COMPRESSOR_CONVERTER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_COMPRESSOR_CONVERTER, GCompressorConverter)) |
146 | #define G_COMPRESSOR_CONVERTER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_COMPRESSOR_CONVERTER, GCompressorConverterClass)) |
147 | #define G_IS_COMPRESSOR_CONVERTER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_COMPRESSOR_CONVERTER)) |
148 | #define G_IS_COMPRESSOR_CONVERTER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_COMPRESSOR_CONVERTER)) |
149 | #define G_COMPRESSOR_CONVERTER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_COMPRESSOR_CONVERTER, GCompressorConverterClass)) |
150 | |
151 | typedef struct _GCompressorConverter GCompressorConverter; |
152 | typedef struct _GCompressorConverterClass GCompressorConverterClass; |
153 | |
154 | struct _GCompressorConverterClass |
155 | { |
156 | GObjectClass parent_class; |
157 | }; |
158 | |
159 | GType g_compressor_converter_get_type (void) G_GNUC_CONST; |
160 | GConverter *g_compressor_converter_new (void); |
161 | |
162 | |
163 | |
164 | static void g_compressor_converter_iface_init (GConverterIface *iface); |
165 | |
166 | struct _GCompressorConverter |
167 | { |
168 | GObject parent_instance; |
169 | }; |
170 | |
171 | G_DEFINE_TYPE_WITH_CODE (GCompressorConverter, g_compressor_converter, G_TYPE_OBJECT, |
172 | G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER, |
173 | g_compressor_converter_iface_init)) |
174 | |
175 | static void |
176 | g_compressor_converter_class_init (GCompressorConverterClass *klass) |
177 | { |
178 | } |
179 | |
180 | static void |
181 | g_compressor_converter_init (GCompressorConverter *local) |
182 | { |
183 | } |
184 | |
185 | GConverter * |
186 | g_compressor_converter_new (void) |
187 | { |
188 | GConverter *conv; |
189 | |
190 | conv = g_object_new (G_TYPE_COMPRESSOR_CONVERTER, NULL); |
191 | |
192 | return conv; |
193 | } |
194 | |
195 | static void |
196 | g_compressor_converter_reset (GConverter *converter) |
197 | { |
198 | } |
199 | |
200 | static GConverterResult |
201 | g_compressor_converter_convert (GConverter *converter, |
202 | const void *inbuf, |
203 | gsize inbuf_size, |
204 | void *outbuf, |
205 | gsize outbuf_size, |
206 | GConverterFlags flags, |
207 | gsize *bytes_read, |
208 | gsize *bytes_written, |
209 | GError **error) |
210 | { |
211 | const guint8 *in, *in_end; |
212 | guint8 v, *out; |
213 | int i; |
214 | gsize block_size; |
215 | |
216 | in = inbuf; |
217 | out = outbuf; |
218 | in_end = in + inbuf_size; |
219 | |
220 | while (in < in_end) |
221 | { |
222 | v = *in; |
223 | |
224 | if (v == 0) |
225 | { |
226 | block_size = 0; |
227 | while (in+block_size < in_end && *(in+block_size) == 0) |
228 | block_size ++; |
229 | } |
230 | else |
231 | block_size = v * 1000; |
232 | |
233 | /* Not enough data */ |
234 | if (in_end - in < block_size) |
235 | { |
236 | if (*bytes_read > 0) |
237 | break; |
238 | g_set_error_literal (err: error, G_IO_ERROR, |
239 | code: G_IO_ERROR_PARTIAL_INPUT, |
240 | message: "Need more data" ); |
241 | return G_CONVERTER_ERROR; |
242 | } |
243 | |
244 | for (i = 0; i < block_size; i++) |
245 | { |
246 | if (*(in + i) != v) |
247 | { |
248 | if (*bytes_read > 0) |
249 | break; |
250 | g_set_error_literal (err: error, G_IO_ERROR, |
251 | code: G_IO_ERROR_INVALID_DATA, |
252 | message: "invalid data" ); |
253 | return G_CONVERTER_ERROR; |
254 | } |
255 | } |
256 | |
257 | if (v == 0 && in_end - in == block_size && (flags & G_CONVERTER_INPUT_AT_END) == 0) |
258 | { |
259 | if (*bytes_read > 0) |
260 | break; |
261 | g_set_error_literal (err: error, G_IO_ERROR, |
262 | code: G_IO_ERROR_PARTIAL_INPUT, |
263 | message: "Need more data" ); |
264 | return G_CONVERTER_ERROR; |
265 | } |
266 | |
267 | in += block_size; |
268 | *out++ = v; |
269 | *bytes_read += block_size; |
270 | *bytes_written += 1; |
271 | } |
272 | |
273 | if (in == in_end && (flags & G_CONVERTER_INPUT_AT_END)) |
274 | return G_CONVERTER_FINISHED; |
275 | return G_CONVERTER_CONVERTED; |
276 | } |
277 | |
278 | static void |
279 | g_compressor_converter_iface_init (GConverterIface *iface) |
280 | { |
281 | iface->convert = g_compressor_converter_convert; |
282 | iface->reset = g_compressor_converter_reset; |
283 | } |
284 | |
285 | guint8 unexpanded_data[] = { 0,1,3,4,5,6,7,3,12,0,0}; |
286 | |
287 | static void |
288 | test_expander (void) |
289 | { |
290 | guint8 *converted1, *converted2, *ptr; |
291 | gsize n_read, n_written; |
292 | gsize total_read; |
293 | gssize res; |
294 | GConverterResult cres; |
295 | GInputStream *mem, *cstream; |
296 | GOutputStream *mem_out, *cstream_out; |
297 | GConverter *expander; |
298 | GConverter *converter; |
299 | GError *error; |
300 | int i; |
301 | |
302 | expander = g_expander_converter_new (); |
303 | |
304 | converted1 = g_malloc (n_bytes: 100*1000); /* Large enough */ |
305 | converted2 = g_malloc (n_bytes: 100*1000); /* Large enough */ |
306 | |
307 | cres = g_converter_convert (converter: expander, |
308 | inbuf: unexpanded_data, inbuf_size: sizeof(unexpanded_data), |
309 | outbuf: converted1, outbuf_size: 100*1000, |
310 | flags: G_CONVERTER_INPUT_AT_END, |
311 | bytes_read: &n_read, bytes_written: &n_written, NULL); |
312 | |
313 | g_assert (cres == G_CONVERTER_FINISHED); |
314 | g_assert (n_read == 11); |
315 | g_assert (n_written == 41030); |
316 | |
317 | g_converter_reset (converter: expander); |
318 | |
319 | mem = g_memory_input_stream_new_from_data (data: unexpanded_data, |
320 | len: sizeof (unexpanded_data), |
321 | NULL); |
322 | cstream = g_converter_input_stream_new (base_stream: mem, converter: expander); |
323 | g_assert (g_converter_input_stream_get_converter (G_CONVERTER_INPUT_STREAM (cstream)) == expander); |
324 | g_object_get (object: cstream, first_property_name: "converter" , &converter, NULL); |
325 | g_assert (converter == expander); |
326 | g_object_unref (object: converter); |
327 | g_object_unref (object: mem); |
328 | |
329 | total_read = 0; |
330 | ptr = converted2; |
331 | while (TRUE) |
332 | { |
333 | error = NULL; |
334 | res = g_input_stream_read (stream: cstream, |
335 | buffer: ptr, count: 1, |
336 | NULL, error: &error); |
337 | g_assert (res != -1); |
338 | if (res == 0) |
339 | break; |
340 | ptr += res; |
341 | total_read += res; |
342 | } |
343 | |
344 | g_assert_cmpmem (converted1, n_written, converted2, total_read); |
345 | |
346 | g_converter_reset (converter: expander); |
347 | |
348 | mem_out = g_memory_output_stream_new (NULL, size: 0, realloc_function: g_realloc, destroy_function: g_free); |
349 | cstream_out = g_converter_output_stream_new (base_stream: mem_out, converter: expander); |
350 | g_assert (g_converter_output_stream_get_converter (G_CONVERTER_OUTPUT_STREAM (cstream_out)) == expander); |
351 | g_object_get (object: cstream_out, first_property_name: "converter" , &converter, NULL); |
352 | g_assert (converter == expander); |
353 | g_object_unref (object: converter); |
354 | g_object_unref (object: mem_out); |
355 | |
356 | for (i = 0; i < sizeof(unexpanded_data); i++) |
357 | { |
358 | error = NULL; |
359 | res = g_output_stream_write (stream: cstream_out, |
360 | buffer: unexpanded_data + i, count: 1, |
361 | NULL, error: &error); |
362 | g_assert (res != -1); |
363 | if (res == 0) |
364 | { |
365 | g_assert (i == sizeof(unexpanded_data) -1); |
366 | break; |
367 | } |
368 | g_assert (res == 1); |
369 | } |
370 | |
371 | g_output_stream_close (stream: cstream_out, NULL, NULL); |
372 | |
373 | g_assert_cmpmem (g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (mem_out)), |
374 | g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (mem_out)), |
375 | converted1, n_written); |
376 | |
377 | g_free (mem: converted1); |
378 | g_free (mem: converted2); |
379 | g_object_unref (object: cstream); |
380 | g_object_unref (object: cstream_out); |
381 | g_object_unref (object: expander); |
382 | } |
383 | |
384 | static void |
385 | test_compressor (void) |
386 | { |
387 | guint8 *converted, *expanded, *ptr; |
388 | gsize n_read, expanded_size; |
389 | gsize total_read; |
390 | gssize res; |
391 | GConverterResult cres; |
392 | GInputStream *mem, *cstream; |
393 | GOutputStream *mem_out, *cstream_out; |
394 | GConverter *expander, *compressor; |
395 | GError *error; |
396 | int i; |
397 | |
398 | expander = g_expander_converter_new (); |
399 | expanded = g_malloc (n_bytes: 100*1000); /* Large enough */ |
400 | cres = g_converter_convert (converter: expander, |
401 | inbuf: unexpanded_data, inbuf_size: sizeof(unexpanded_data), |
402 | outbuf: expanded, outbuf_size: 100*1000, |
403 | flags: G_CONVERTER_INPUT_AT_END, |
404 | bytes_read: &n_read, bytes_written: &expanded_size, NULL); |
405 | g_assert (cres == G_CONVERTER_FINISHED); |
406 | g_assert (n_read == 11); |
407 | g_assert (expanded_size == 41030); |
408 | |
409 | compressor = g_compressor_converter_new (); |
410 | |
411 | converted = g_malloc (n_bytes: 100*1000); /* Large enough */ |
412 | |
413 | mem = g_memory_input_stream_new_from_data (data: expanded, |
414 | len: expanded_size, |
415 | NULL); |
416 | cstream = g_converter_input_stream_new (base_stream: mem, converter: compressor); |
417 | g_object_unref (object: mem); |
418 | |
419 | total_read = 0; |
420 | ptr = converted; |
421 | while (TRUE) |
422 | { |
423 | error = NULL; |
424 | res = g_input_stream_read (stream: cstream, |
425 | buffer: ptr, count: 1, |
426 | NULL, error: &error); |
427 | g_assert (res != -1); |
428 | if (res == 0) |
429 | break; |
430 | ptr += res; |
431 | total_read += res; |
432 | } |
433 | |
434 | /* "n_read - 1" because last 2 zeros are combined */ |
435 | g_assert_cmpmem (unexpanded_data, n_read - 1, converted, total_read); |
436 | |
437 | g_object_unref (object: cstream); |
438 | |
439 | g_converter_reset (converter: compressor); |
440 | |
441 | mem_out = g_memory_output_stream_new (NULL, size: 0, realloc_function: g_realloc, destroy_function: g_free); |
442 | cstream_out = g_converter_output_stream_new (base_stream: mem_out, converter: compressor); |
443 | g_object_unref (object: mem_out); |
444 | |
445 | for (i = 0; i < expanded_size; i++) |
446 | { |
447 | error = NULL; |
448 | res = g_output_stream_write (stream: cstream_out, |
449 | buffer: expanded + i, count: 1, |
450 | NULL, error: &error); |
451 | g_assert (res != -1); |
452 | if (res == 0) |
453 | { |
454 | g_assert (i == expanded_size -1); |
455 | break; |
456 | } |
457 | g_assert (res == 1); |
458 | } |
459 | |
460 | g_output_stream_close (stream: cstream_out, NULL, NULL); |
461 | |
462 | /* "n_read - 1" because last 2 zeros are combined */ |
463 | g_assert_cmpmem (g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (mem_out)), |
464 | g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (mem_out)), |
465 | unexpanded_data, |
466 | n_read - 1); |
467 | |
468 | g_object_unref (object: cstream_out); |
469 | |
470 | g_converter_reset (converter: compressor); |
471 | |
472 | memset (s: expanded, c: 5, n: 5*1000*2); |
473 | |
474 | mem = g_memory_input_stream_new_from_data (data: expanded, |
475 | len: 5*1000, |
476 | NULL); |
477 | cstream = g_converter_input_stream_new (base_stream: mem, converter: compressor); |
478 | g_object_unref (object: mem); |
479 | |
480 | total_read = 0; |
481 | ptr = converted; |
482 | while (TRUE) |
483 | { |
484 | error = NULL; |
485 | res = g_input_stream_read (stream: cstream, |
486 | buffer: ptr, count: 1, |
487 | NULL, error: &error); |
488 | g_assert (res != -1); |
489 | if (res == 0) |
490 | break; |
491 | ptr += res; |
492 | total_read += res; |
493 | } |
494 | |
495 | g_assert (total_read == 1); |
496 | g_assert (*converted == 5); |
497 | |
498 | g_object_unref (object: cstream); |
499 | |
500 | mem = g_memory_input_stream_new_from_data (data: expanded, |
501 | len: 5*1000 * 2, |
502 | NULL); |
503 | cstream = g_converter_input_stream_new (base_stream: mem, converter: compressor); |
504 | g_object_unref (object: mem); |
505 | |
506 | total_read = 0; |
507 | ptr = converted; |
508 | while (TRUE) |
509 | { |
510 | error = NULL; |
511 | res = g_input_stream_read (stream: cstream, |
512 | buffer: ptr, count: 1, |
513 | NULL, error: &error); |
514 | g_assert (res != -1); |
515 | if (res == 0) |
516 | break; |
517 | ptr += res; |
518 | total_read += res; |
519 | } |
520 | |
521 | g_assert (total_read == 2); |
522 | g_assert (converted[0] == 5); |
523 | g_assert (converted[1] == 5); |
524 | |
525 | g_object_unref (object: cstream); |
526 | |
527 | g_converter_reset (converter: compressor); |
528 | |
529 | mem = g_memory_input_stream_new_from_data (data: expanded, |
530 | len: 5*1000 * 2 - 1, |
531 | NULL); |
532 | cstream = g_converter_input_stream_new (base_stream: mem, converter: compressor); |
533 | g_object_unref (object: mem); |
534 | |
535 | total_read = 0; |
536 | ptr = converted; |
537 | while (TRUE) |
538 | { |
539 | error = NULL; |
540 | res = g_input_stream_read (stream: cstream, |
541 | buffer: ptr, count: 1, |
542 | NULL, error: &error); |
543 | if (res == -1) |
544 | { |
545 | g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT); |
546 | g_error_free (error); |
547 | break; |
548 | } |
549 | |
550 | g_assert (res != 0); |
551 | ptr += res; |
552 | total_read += res; |
553 | } |
554 | |
555 | g_assert (total_read == 1); |
556 | g_assert (converted[0] == 5); |
557 | |
558 | g_object_unref (object: cstream); |
559 | |
560 | g_free (mem: expanded); |
561 | g_free (mem: converted); |
562 | g_object_unref (object: expander); |
563 | g_object_unref (object: compressor); |
564 | } |
565 | |
566 | #define LEFTOVER_SHORT_READ_SIZE 512 |
567 | |
568 | #define G_TYPE_LEFTOVER_CONVERTER (g_leftover_converter_get_type ()) |
569 | #define G_LEFTOVER_CONVERTER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_LEFTOVER_CONVERTER, GLeftoverConverter)) |
570 | #define G_LEFTOVER_CONVERTER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_LEFTOVER_CONVERTER, GLeftoverConverterClass)) |
571 | #define G_IS_LEFTOVER_CONVERTER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_LEFTOVER_CONVERTER)) |
572 | #define G_IS_LEFTOVER_CONVERTER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_LEFTOVER_CONVERTER)) |
573 | #define G_LEFTOVER_CONVERTER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_LEFTOVER_CONVERTER, GLeftoverConverterClass)) |
574 | |
575 | typedef struct _GLeftoverConverter GLeftoverConverter; |
576 | typedef struct _GLeftoverConverterClass GLeftoverConverterClass; |
577 | |
578 | struct _GLeftoverConverterClass |
579 | { |
580 | GObjectClass parent_class; |
581 | }; |
582 | |
583 | GType g_leftover_converter_get_type (void) G_GNUC_CONST; |
584 | GConverter *g_leftover_converter_new (void); |
585 | |
586 | |
587 | |
588 | static void g_leftover_converter_iface_init (GConverterIface *iface); |
589 | |
590 | struct _GLeftoverConverter |
591 | { |
592 | GObject parent_instance; |
593 | }; |
594 | |
595 | G_DEFINE_TYPE_WITH_CODE (GLeftoverConverter, g_leftover_converter, G_TYPE_OBJECT, |
596 | G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER, |
597 | g_leftover_converter_iface_init)) |
598 | |
599 | static void |
600 | g_leftover_converter_class_init (GLeftoverConverterClass *klass) |
601 | { |
602 | } |
603 | |
604 | static void |
605 | g_leftover_converter_init (GLeftoverConverter *local) |
606 | { |
607 | } |
608 | |
609 | GConverter * |
610 | g_leftover_converter_new (void) |
611 | { |
612 | GConverter *conv; |
613 | |
614 | conv = g_object_new (G_TYPE_LEFTOVER_CONVERTER, NULL); |
615 | |
616 | return conv; |
617 | } |
618 | |
619 | static void |
620 | g_leftover_converter_reset (GConverter *converter) |
621 | { |
622 | } |
623 | |
624 | static GConverterResult |
625 | g_leftover_converter_convert (GConverter *converter, |
626 | const void *inbuf, |
627 | gsize inbuf_size, |
628 | void *outbuf, |
629 | gsize outbuf_size, |
630 | GConverterFlags flags, |
631 | gsize *bytes_read, |
632 | gsize *bytes_written, |
633 | GError **error) |
634 | { |
635 | if (outbuf_size == LEFTOVER_SHORT_READ_SIZE) |
636 | { |
637 | g_set_error_literal (err: error, |
638 | G_IO_ERROR, |
639 | code: G_IO_ERROR_PARTIAL_INPUT, |
640 | message: "partial input" ); |
641 | return G_CONVERTER_ERROR; |
642 | } |
643 | |
644 | if (inbuf_size < 100) |
645 | *bytes_read = *bytes_written = MIN (inbuf_size, outbuf_size); |
646 | else |
647 | *bytes_read = *bytes_written = MIN (inbuf_size - 10, outbuf_size); |
648 | memcpy (dest: outbuf, src: inbuf, n: *bytes_written); |
649 | |
650 | if (*bytes_read == inbuf_size && (flags & G_CONVERTER_INPUT_AT_END)) |
651 | return G_CONVERTER_FINISHED; |
652 | return G_CONVERTER_CONVERTED; |
653 | } |
654 | |
655 | static void |
656 | g_leftover_converter_iface_init (GConverterIface *iface) |
657 | { |
658 | iface->convert = g_leftover_converter_convert; |
659 | iface->reset = g_leftover_converter_reset; |
660 | } |
661 | |
662 | #define LEFTOVER_BUFSIZE 8192 |
663 | #define INTERNAL_BUFSIZE 4096 |
664 | |
665 | static void |
666 | test_converter_leftover (void) |
667 | { |
668 | gchar *orig, *converted; |
669 | gsize total_read; |
670 | gssize res; |
671 | goffset offset; |
672 | GInputStream *mem, *cstream; |
673 | GConverter *converter; |
674 | GError *error; |
675 | int i; |
676 | |
677 | converter = g_leftover_converter_new (); |
678 | |
679 | orig = g_malloc (LEFTOVER_BUFSIZE); |
680 | converted = g_malloc (LEFTOVER_BUFSIZE); |
681 | for (i = 0; i < LEFTOVER_BUFSIZE; i++) |
682 | orig[i] = i % 64 + 32; |
683 | |
684 | mem = g_memory_input_stream_new_from_data (data: orig, LEFTOVER_BUFSIZE, NULL); |
685 | cstream = g_converter_input_stream_new (base_stream: mem, G_CONVERTER (converter)); |
686 | g_object_unref (object: mem); |
687 | |
688 | total_read = 0; |
689 | |
690 | error = NULL; |
691 | res = g_input_stream_read (stream: cstream, |
692 | buffer: converted, LEFTOVER_SHORT_READ_SIZE, |
693 | NULL, error: &error); |
694 | g_assert_cmpint (res, ==, LEFTOVER_SHORT_READ_SIZE); |
695 | total_read += res; |
696 | |
697 | offset = g_seekable_tell (G_SEEKABLE (mem)); |
698 | g_assert_cmpint (offset, >, LEFTOVER_SHORT_READ_SIZE); |
699 | g_assert_cmpint (offset, <, LEFTOVER_BUFSIZE); |
700 | |
701 | /* At this point, @cstream has both a non-empty input_buffer |
702 | * and a non-empty converted_buffer, which is the case |
703 | * we want to test. |
704 | */ |
705 | |
706 | while (TRUE) |
707 | { |
708 | error = NULL; |
709 | res = g_input_stream_read (stream: cstream, |
710 | buffer: converted + total_read, |
711 | LEFTOVER_BUFSIZE - total_read, |
712 | NULL, error: &error); |
713 | g_assert (res >= 0); |
714 | if (res == 0) |
715 | break; |
716 | total_read += res; |
717 | } |
718 | |
719 | g_assert_cmpmem (orig, LEFTOVER_BUFSIZE, converted, total_read); |
720 | |
721 | g_object_unref (object: cstream); |
722 | g_free (mem: orig); |
723 | g_free (mem: converted); |
724 | g_object_unref (object: converter); |
725 | } |
726 | |
727 | #define DATA_LENGTH 1000000 |
728 | |
729 | typedef struct { |
730 | const gchar *path; |
731 | GZlibCompressorFormat format; |
732 | gint level; |
733 | } CompressorTest; |
734 | |
735 | static void |
736 | test_roundtrip (gconstpointer data) |
737 | { |
738 | const CompressorTest *test = data; |
739 | GError *error = NULL; |
740 | guint32 *data0, *data1; |
741 | gsize data1_size; |
742 | gint i; |
743 | GInputStream *istream0, *istream1, *cistream1; |
744 | GOutputStream *ostream1, *ostream2, *costream1; |
745 | GConverter *compressor, *decompressor; |
746 | GZlibCompressorFormat fmt; |
747 | gint lvl; |
748 | GFileInfo *info; |
749 | GFileInfo *info2; |
750 | |
751 | g_test_bug (bug_uri_snippet: "619945" ); |
752 | |
753 | data0 = g_malloc (DATA_LENGTH * sizeof (guint32)); |
754 | for (i = 0; i < DATA_LENGTH; i++) |
755 | data0[i] = g_random_int (); |
756 | |
757 | istream0 = g_memory_input_stream_new_from_data (data: data0, |
758 | DATA_LENGTH * sizeof (guint32), NULL); |
759 | |
760 | ostream1 = g_memory_output_stream_new (NULL, size: 0, realloc_function: g_realloc, destroy_function: g_free); |
761 | compressor = G_CONVERTER (g_zlib_compressor_new (test->format, test->level)); |
762 | info = g_file_info_new (); |
763 | g_file_info_set_name (info, name: "foo" ); |
764 | g_object_set (object: compressor, first_property_name: "file-info" , info, NULL); |
765 | info2 = g_zlib_compressor_get_file_info (G_ZLIB_COMPRESSOR (compressor)); |
766 | g_assert (info == info2); |
767 | g_object_unref (object: info); |
768 | costream1 = g_converter_output_stream_new (base_stream: ostream1, converter: compressor); |
769 | g_assert (g_converter_output_stream_get_converter (G_CONVERTER_OUTPUT_STREAM (costream1)) == compressor); |
770 | |
771 | g_output_stream_splice (stream: costream1, source: istream0, flags: 0, NULL, error: &error); |
772 | g_assert_no_error (error); |
773 | |
774 | g_object_unref (object: costream1); |
775 | |
776 | g_converter_reset (converter: compressor); |
777 | g_object_get (object: compressor, first_property_name: "format" , &fmt, "level" , &lvl, NULL); |
778 | g_assert_cmpint (fmt, ==, test->format); |
779 | g_assert_cmpint (lvl, ==, test->level); |
780 | g_object_unref (object: compressor); |
781 | data1 = g_memory_output_stream_steal_data (G_MEMORY_OUTPUT_STREAM (ostream1)); |
782 | data1_size = g_memory_output_stream_get_data_size ( |
783 | G_MEMORY_OUTPUT_STREAM (ostream1)); |
784 | g_object_unref (object: ostream1); |
785 | g_object_unref (object: istream0); |
786 | |
787 | istream1 = g_memory_input_stream_new_from_data (data: data1, len: data1_size, destroy: g_free); |
788 | decompressor = G_CONVERTER (g_zlib_decompressor_new (test->format)); |
789 | cistream1 = g_converter_input_stream_new (base_stream: istream1, converter: decompressor); |
790 | |
791 | ostream2 = g_memory_output_stream_new (NULL, size: 0, realloc_function: g_realloc, destroy_function: g_free); |
792 | |
793 | g_output_stream_splice (stream: ostream2, source: cistream1, flags: 0, NULL, error: &error); |
794 | g_assert_no_error (error); |
795 | |
796 | g_assert_cmpmem (data0, DATA_LENGTH * sizeof (guint32), |
797 | g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (ostream2)), |
798 | g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (ostream2))); |
799 | g_object_unref (object: istream1); |
800 | g_converter_reset (converter: decompressor); |
801 | g_object_get (object: decompressor, first_property_name: "format" , &fmt, NULL); |
802 | g_assert_cmpint (fmt, ==, test->format); |
803 | g_object_unref (object: decompressor); |
804 | g_object_unref (object: cistream1); |
805 | g_object_unref (object: ostream2); |
806 | g_free (mem: data0); |
807 | } |
808 | |
809 | typedef struct { |
810 | const gchar *path; |
811 | const gchar *charset_in; |
812 | const gchar *text_in; |
813 | const gchar *charset_out; |
814 | const gchar *text_out; |
815 | gint n_fallbacks; |
816 | } CharsetTest; |
817 | |
818 | static void |
819 | test_charset (gconstpointer data) |
820 | { |
821 | const CharsetTest *test = data; |
822 | GInputStream *in, *in2; |
823 | GConverter *conv; |
824 | gchar *buffer; |
825 | gsize count; |
826 | gsize bytes_read; |
827 | GError *error; |
828 | gboolean fallback; |
829 | |
830 | conv = (GConverter *)g_charset_converter_new (to_charset: test->charset_out, from_charset: test->charset_in, NULL); |
831 | g_object_get (object: conv, first_property_name: "use-fallback" , &fallback, NULL); |
832 | g_assert (!fallback); |
833 | |
834 | in = g_memory_input_stream_new_from_data (data: test->text_in, len: -1, NULL); |
835 | in2 = g_converter_input_stream_new (base_stream: in, converter: conv); |
836 | |
837 | count = 2 * strlen (s: test->text_out); |
838 | buffer = g_malloc0 (n_bytes: count); |
839 | error = NULL; |
840 | g_input_stream_read_all (stream: in2, buffer, count, bytes_read: &bytes_read, NULL, error: &error); |
841 | if (test->n_fallbacks == 0) |
842 | { |
843 | g_assert_no_error (error); |
844 | g_assert_cmpint (bytes_read, ==, strlen (test->text_out)); |
845 | g_assert_cmpstr (buffer, ==, test->text_out); |
846 | } |
847 | else |
848 | { |
849 | g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA); |
850 | g_error_free (error); |
851 | } |
852 | |
853 | g_free (mem: buffer); |
854 | g_object_unref (object: in2); |
855 | g_object_unref (object: in); |
856 | |
857 | if (test->n_fallbacks == 0) |
858 | { |
859 | g_object_unref (object: conv); |
860 | return; |
861 | } |
862 | |
863 | g_converter_reset (converter: conv); |
864 | |
865 | g_assert (!g_charset_converter_get_use_fallback (G_CHARSET_CONVERTER (conv))); |
866 | g_charset_converter_set_use_fallback (G_CHARSET_CONVERTER (conv), TRUE); |
867 | |
868 | in = g_memory_input_stream_new_from_data (data: test->text_in, len: -1, NULL); |
869 | in2 = g_converter_input_stream_new (base_stream: in, converter: conv); |
870 | |
871 | count = 2 * strlen (s: test->text_out); |
872 | buffer = g_malloc0 (n_bytes: count); |
873 | error = NULL; |
874 | g_input_stream_read_all (stream: in2, buffer, count, bytes_read: &bytes_read, NULL, error: &error); |
875 | g_assert_no_error (error); |
876 | g_assert_cmpstr (buffer, ==, test->text_out); |
877 | g_assert_cmpint (bytes_read, ==, strlen (test->text_out)); |
878 | g_assert_cmpint (test->n_fallbacks, ==, g_charset_converter_get_num_fallbacks (G_CHARSET_CONVERTER (conv))); |
879 | |
880 | g_free (mem: buffer); |
881 | g_object_unref (object: in2); |
882 | g_object_unref (object: in); |
883 | |
884 | g_object_unref (object: conv); |
885 | } |
886 | |
887 | |
888 | static void |
889 | client_connected (GObject *source, |
890 | GAsyncResult *result, |
891 | gpointer user_data) |
892 | { |
893 | GSocketClient *client = G_SOCKET_CLIENT (source); |
894 | GSocketConnection **conn = user_data; |
895 | GError *error = NULL; |
896 | |
897 | *conn = g_socket_client_connect_finish (client, result, error: &error); |
898 | g_assert_no_error (error); |
899 | } |
900 | |
901 | static void |
902 | server_connected (GObject *source, |
903 | GAsyncResult *result, |
904 | gpointer user_data) |
905 | { |
906 | GSocketListener *listener = G_SOCKET_LISTENER (source); |
907 | GSocketConnection **conn = user_data; |
908 | GError *error = NULL; |
909 | |
910 | *conn = g_socket_listener_accept_finish (listener, result, NULL, error: &error); |
911 | g_assert_no_error (error); |
912 | } |
913 | |
914 | static void |
915 | make_socketpair (GIOStream **left, |
916 | GIOStream **right) |
917 | { |
918 | GInetAddress *iaddr; |
919 | GSocketAddress *saddr, *effective_address; |
920 | GSocketListener *listener; |
921 | GSocketClient *client; |
922 | GError *error = NULL; |
923 | GSocketConnection *client_conn = NULL, *server_conn = NULL; |
924 | |
925 | iaddr = g_inet_address_new_loopback (family: G_SOCKET_FAMILY_IPV4); |
926 | saddr = g_inet_socket_address_new (address: iaddr, port: 0); |
927 | g_object_unref (object: iaddr); |
928 | |
929 | listener = g_socket_listener_new (); |
930 | g_socket_listener_add_address (listener, address: saddr, |
931 | type: G_SOCKET_TYPE_STREAM, |
932 | protocol: G_SOCKET_PROTOCOL_TCP, |
933 | NULL, |
934 | effective_address: &effective_address, |
935 | error: &error); |
936 | g_assert_no_error (error); |
937 | g_object_unref (object: saddr); |
938 | |
939 | client = g_socket_client_new (); |
940 | |
941 | g_socket_client_connect_async (client, |
942 | G_SOCKET_CONNECTABLE (effective_address), |
943 | NULL, callback: client_connected, user_data: &client_conn); |
944 | g_socket_listener_accept_async (listener, NULL, |
945 | callback: server_connected, user_data: &server_conn); |
946 | |
947 | while (!client_conn || !server_conn) |
948 | g_main_context_iteration (NULL, TRUE); |
949 | |
950 | g_object_unref (object: client); |
951 | g_object_unref (object: listener); |
952 | g_object_unref (object: effective_address); |
953 | |
954 | *left = G_IO_STREAM (client_conn); |
955 | *right = G_IO_STREAM (server_conn); |
956 | } |
957 | |
958 | static void |
959 | test_converter_pollable (void) |
960 | { |
961 | GIOStream *left, *right; |
962 | guint8 *converted, *inptr; |
963 | guint8 *expanded, *outptr, *expanded_end; |
964 | gsize n_read, expanded_size; |
965 | gsize total_read; |
966 | gssize res; |
967 | gboolean is_readable; |
968 | GConverterResult cres; |
969 | GInputStream *cstream; |
970 | GPollableInputStream *pollable_in; |
971 | GOutputStream *socket_out, *mem_out, *cstream_out; |
972 | GPollableOutputStream *pollable_out; |
973 | GConverter *expander, *compressor; |
974 | GError *error; |
975 | int i; |
976 | |
977 | expander = g_expander_converter_new (); |
978 | expanded = g_malloc (n_bytes: 100*1000); /* Large enough */ |
979 | cres = g_converter_convert (converter: expander, |
980 | inbuf: unexpanded_data, inbuf_size: sizeof(unexpanded_data), |
981 | outbuf: expanded, outbuf_size: 100*1000, |
982 | flags: G_CONVERTER_INPUT_AT_END, |
983 | bytes_read: &n_read, bytes_written: &expanded_size, NULL); |
984 | g_assert (cres == G_CONVERTER_FINISHED); |
985 | g_assert (n_read == 11); |
986 | g_assert (expanded_size == 41030); |
987 | expanded_end = expanded + expanded_size; |
988 | |
989 | make_socketpair (left: &left, right: &right); |
990 | |
991 | compressor = g_compressor_converter_new (); |
992 | |
993 | converted = g_malloc (n_bytes: 100*1000); /* Large enough */ |
994 | |
995 | cstream = g_converter_input_stream_new (base_stream: g_io_stream_get_input_stream (stream: left), |
996 | converter: compressor); |
997 | pollable_in = G_POLLABLE_INPUT_STREAM (cstream); |
998 | g_assert (g_pollable_input_stream_can_poll (pollable_in)); |
999 | |
1000 | socket_out = g_io_stream_get_output_stream (stream: right); |
1001 | |
1002 | total_read = 0; |
1003 | outptr = expanded; |
1004 | inptr = converted; |
1005 | while (TRUE) |
1006 | { |
1007 | error = NULL; |
1008 | |
1009 | if (outptr < expanded_end) |
1010 | { |
1011 | res = g_output_stream_write (stream: socket_out, |
1012 | buffer: outptr, |
1013 | MIN (1000, (expanded_end - outptr)), |
1014 | NULL, error: &error); |
1015 | g_assert_cmpint (res, >, 0); |
1016 | outptr += res; |
1017 | } |
1018 | else if (socket_out) |
1019 | { |
1020 | g_object_unref (object: right); |
1021 | socket_out = NULL; |
1022 | } |
1023 | |
1024 | /* Wait a few ticks to check for the pipe to propagate the |
1025 | * write. Finesses the race condition in the following test, |
1026 | * where is_readable fails because the write hasn't propagated, |
1027 | * but the read then succeeds because it has. */ |
1028 | g_usleep (microseconds: 80L); |
1029 | |
1030 | is_readable = g_pollable_input_stream_is_readable (stream: pollable_in); |
1031 | res = g_pollable_input_stream_read_nonblocking (stream: pollable_in, |
1032 | buffer: inptr, count: 1, |
1033 | NULL, error: &error); |
1034 | |
1035 | /* is_readable can be a false positive, but not a false negative */ |
1036 | if (!is_readable) |
1037 | g_assert_cmpint (res, ==, -1); |
1038 | |
1039 | /* After closing the write end, we can't get WOULD_BLOCK any more */ |
1040 | if (!socket_out) |
1041 | g_assert_cmpint (res, !=, -1); |
1042 | |
1043 | if (res == -1) |
1044 | { |
1045 | g_assert_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK); |
1046 | g_error_free (error); |
1047 | |
1048 | continue; |
1049 | } |
1050 | |
1051 | if (res == 0) |
1052 | break; |
1053 | inptr += res; |
1054 | total_read += res; |
1055 | } |
1056 | |
1057 | /* "n_read - 1" because last 2 zeros are combined */ |
1058 | g_assert_cmpmem (unexpanded_data, n_read - 1, converted, total_read); |
1059 | |
1060 | g_object_unref (object: cstream); |
1061 | g_object_unref (object: left); |
1062 | |
1063 | g_converter_reset (converter: compressor); |
1064 | |
1065 | /* This doesn't actually test the behavior on |
1066 | * G_IO_ERROR_WOULD_BLOCK; to do that we'd need to implement a |
1067 | * custom GOutputStream that we could control blocking on. |
1068 | */ |
1069 | |
1070 | mem_out = g_memory_output_stream_new (NULL, size: 0, realloc_function: g_realloc, destroy_function: g_free); |
1071 | cstream_out = g_converter_output_stream_new (base_stream: mem_out, converter: compressor); |
1072 | g_object_unref (object: mem_out); |
1073 | pollable_out = G_POLLABLE_OUTPUT_STREAM (cstream_out); |
1074 | g_assert (g_pollable_output_stream_can_poll (pollable_out)); |
1075 | g_assert (g_pollable_output_stream_is_writable (pollable_out)); |
1076 | |
1077 | for (i = 0; i < expanded_size; i++) |
1078 | { |
1079 | error = NULL; |
1080 | res = g_pollable_output_stream_write_nonblocking (stream: pollable_out, |
1081 | buffer: expanded + i, count: 1, |
1082 | NULL, error: &error); |
1083 | g_assert (res != -1); |
1084 | if (res == 0) |
1085 | { |
1086 | g_assert (i == expanded_size -1); |
1087 | break; |
1088 | } |
1089 | g_assert (res == 1); |
1090 | } |
1091 | |
1092 | g_output_stream_close (stream: cstream_out, NULL, NULL); |
1093 | |
1094 | /* "n_read - 1" because last 2 zeros are combined */ |
1095 | g_assert_cmpmem (g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (mem_out)), |
1096 | g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (mem_out)), |
1097 | unexpanded_data, |
1098 | n_read - 1); |
1099 | |
1100 | g_object_unref (object: cstream_out); |
1101 | |
1102 | g_free (mem: expanded); |
1103 | g_free (mem: converted); |
1104 | g_object_unref (object: expander); |
1105 | g_object_unref (object: compressor); |
1106 | } |
1107 | |
1108 | static void |
1109 | test_truncation (gconstpointer data) |
1110 | { |
1111 | const CompressorTest *test = data; |
1112 | GError *error = NULL; |
1113 | guint32 *data0, *data1; |
1114 | gsize data1_size; |
1115 | gint i; |
1116 | GInputStream *istream0, *istream1, *cistream1; |
1117 | GOutputStream *ostream1, *ostream2, *costream1; |
1118 | GConverter *compressor, *decompressor; |
1119 | |
1120 | data0 = g_malloc (DATA_LENGTH * sizeof (guint32)); |
1121 | for (i = 0; i < DATA_LENGTH; i++) |
1122 | data0[i] = g_random_int (); |
1123 | |
1124 | istream0 = g_memory_input_stream_new_from_data (data: data0, |
1125 | DATA_LENGTH * sizeof (guint32), NULL); |
1126 | |
1127 | ostream1 = g_memory_output_stream_new (NULL, size: 0, realloc_function: g_realloc, destroy_function: g_free); |
1128 | compressor = G_CONVERTER (g_zlib_compressor_new (test->format, -1)); |
1129 | costream1 = g_converter_output_stream_new (base_stream: ostream1, converter: compressor); |
1130 | g_assert (g_converter_output_stream_get_converter (G_CONVERTER_OUTPUT_STREAM (costream1)) == compressor); |
1131 | |
1132 | g_output_stream_splice (stream: costream1, source: istream0, flags: 0, NULL, error: &error); |
1133 | g_assert_no_error (error); |
1134 | |
1135 | g_object_unref (object: costream1); |
1136 | g_object_unref (object: compressor); |
1137 | |
1138 | data1 = g_memory_output_stream_steal_data (G_MEMORY_OUTPUT_STREAM (ostream1)); |
1139 | data1_size = g_memory_output_stream_get_data_size ( |
1140 | G_MEMORY_OUTPUT_STREAM (ostream1)); |
1141 | g_object_unref (object: ostream1); |
1142 | g_object_unref (object: istream0); |
1143 | |
1144 | /* truncate */ |
1145 | data1_size /= 2; |
1146 | |
1147 | istream1 = g_memory_input_stream_new_from_data (data: data1, len: data1_size, destroy: g_free); |
1148 | decompressor = G_CONVERTER (g_zlib_decompressor_new (test->format)); |
1149 | cistream1 = g_converter_input_stream_new (base_stream: istream1, converter: decompressor); |
1150 | |
1151 | ostream2 = g_memory_output_stream_new (NULL, size: 0, realloc_function: g_realloc, destroy_function: g_free); |
1152 | |
1153 | g_output_stream_splice (stream: ostream2, source: cistream1, flags: 0, NULL, error: &error); |
1154 | g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT); |
1155 | g_error_free (error); |
1156 | |
1157 | g_object_unref (object: istream1); |
1158 | g_object_unref (object: decompressor); |
1159 | g_object_unref (object: cistream1); |
1160 | g_object_unref (object: ostream2); |
1161 | g_free (mem: data0); |
1162 | } |
1163 | |
1164 | static void |
1165 | test_converter_basics (void) |
1166 | { |
1167 | GConverter *converter; |
1168 | GError *error = NULL; |
1169 | gchar *to; |
1170 | gchar *from; |
1171 | |
1172 | converter = (GConverter *)g_charset_converter_new (to_charset: "utf-8" , from_charset: "latin1" , error: &error); |
1173 | g_assert_no_error (error); |
1174 | g_object_get (object: converter, |
1175 | first_property_name: "to-charset" , &to, |
1176 | "from-charset" , &from, |
1177 | NULL); |
1178 | |
1179 | g_assert_cmpstr (to, ==, "utf-8" ); |
1180 | g_assert_cmpstr (from, ==, "latin1" ); |
1181 | |
1182 | g_free (mem: to); |
1183 | g_free (mem: from); |
1184 | g_object_unref (object: converter); |
1185 | } |
1186 | |
1187 | int |
1188 | main (int argc, |
1189 | char *argv[]) |
1190 | { |
1191 | CompressorTest compressor_tests[] = { |
1192 | { "/converter-output-stream/roundtrip/zlib-0" , G_ZLIB_COMPRESSOR_FORMAT_ZLIB, 0 }, |
1193 | { "/converter-output-stream/roundtrip/zlib-9" , G_ZLIB_COMPRESSOR_FORMAT_ZLIB, 9 }, |
1194 | { "/converter-output-stream/roundtrip/gzip-0" , G_ZLIB_COMPRESSOR_FORMAT_GZIP, 0 }, |
1195 | { "/converter-output-stream/roundtrip/gzip-9" , G_ZLIB_COMPRESSOR_FORMAT_GZIP, 9 }, |
1196 | { "/converter-output-stream/roundtrip/raw-0" , G_ZLIB_COMPRESSOR_FORMAT_RAW, 0 }, |
1197 | { "/converter-output-stream/roundtrip/raw-9" , G_ZLIB_COMPRESSOR_FORMAT_RAW, 9 }, |
1198 | }; |
1199 | CompressorTest truncation_tests[] = { |
1200 | { "/converter-input-stream/truncation/zlib" , G_ZLIB_COMPRESSOR_FORMAT_ZLIB, 0 }, |
1201 | { "/converter-input-stream/truncation/gzip" , G_ZLIB_COMPRESSOR_FORMAT_GZIP, 0 }, |
1202 | { "/converter-input-stream/truncation/raw" , G_ZLIB_COMPRESSOR_FORMAT_RAW, 0 }, |
1203 | }; |
1204 | CharsetTest charset_tests[] = { |
1205 | { "/converter-input-stream/charset/utf8->latin1" , "UTF-8" , "\303\205rr Sant\303\251" , "ISO-8859-1" , "\305rr Sant\351" , 0 }, |
1206 | { "/converter-input-stream/charset/latin1->utf8" , "ISO-8859-1" , "\305rr Sant\351" , "UTF-8" , "\303\205rr Sant\303\251" , 0 }, |
1207 | { "/converter-input-stream/charset/fallbacks" , "UTF-8" , "Some characters just don't fit into latin1: πא" , "ISO-8859-1" , "Some characters just don't fit into latin1: \\CF\\80\\D7\\90" , 4 }, |
1208 | }; |
1209 | |
1210 | gint i; |
1211 | |
1212 | g_test_init (argc: &argc, argv: &argv, NULL); |
1213 | |
1214 | g_test_bug_base (uri_pattern: "http://bugzilla.gnome.org/" ); |
1215 | |
1216 | g_test_add_func (testpath: "/converter/basics" , test_func: test_converter_basics); |
1217 | g_test_add_func (testpath: "/converter-input-stream/expander" , test_func: test_expander); |
1218 | g_test_add_func (testpath: "/converter-input-stream/compressor" , test_func: test_compressor); |
1219 | |
1220 | for (i = 0; i < G_N_ELEMENTS (compressor_tests); i++) |
1221 | g_test_add_data_func (testpath: compressor_tests[i].path, test_data: &compressor_tests[i], test_func: test_roundtrip); |
1222 | |
1223 | for (i = 0; i < G_N_ELEMENTS (truncation_tests); i++) |
1224 | g_test_add_data_func (testpath: truncation_tests[i].path, test_data: &truncation_tests[i], test_func: test_truncation); |
1225 | |
1226 | for (i = 0; i < G_N_ELEMENTS (charset_tests); i++) |
1227 | g_test_add_data_func (testpath: charset_tests[i].path, test_data: &charset_tests[i], test_func: test_charset); |
1228 | |
1229 | g_test_add_func (testpath: "/converter-stream/pollable" , test_func: test_converter_pollable); |
1230 | g_test_add_func (testpath: "/converter-stream/leftover" , test_func: test_converter_leftover); |
1231 | |
1232 | return g_test_run(); |
1233 | } |
1234 | |