Merge remote branch 'gvdb/master'
[platform/upstream/glib.git] / gio / tests / converter-stream.c
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   GExpanderConverter  *conv;
96   const guint8 *in, *in_end;
97   guint8 v, *out;
98   int i;
99   gsize block_size;
100
101   conv = G_EXPANDER_CONVERTER (converter);
102
103   in = inbuf;
104   out = outbuf;
105   in_end = in + inbuf_size;
106
107   while (in < in_end)
108     {
109       v = *in;
110
111       if (v == 0)
112         block_size = 10;
113       else
114         block_size = v * 1000;
115
116       if (outbuf_size < block_size)
117         {
118           if (*bytes_read > 0)
119             return G_CONVERTER_CONVERTED;
120
121           g_set_error_literal (error, G_IO_ERROR,
122                                G_IO_ERROR_NO_SPACE,
123                                "No space in dest");
124           return G_CONVERTER_ERROR;
125         }
126
127       in++;
128       *bytes_read += 1;
129       *bytes_written += block_size;
130       outbuf_size -= block_size;
131       for (i = 0; i < block_size; i++)
132         *out++ = v;
133     }
134
135   if (in == in_end && (flags & G_CONVERTER_INPUT_AT_END))
136     return G_CONVERTER_FINISHED;
137   return G_CONVERTER_CONVERTED;
138 }
139
140 static void
141 g_expander_converter_iface_init (GConverterIface *iface)
142 {
143   iface->convert = g_expander_converter_convert;
144   iface->reset = g_expander_converter_reset;
145 }
146
147 #define G_TYPE_COMPRESSOR_CONVERTER         (g_compressor_converter_get_type ())
148 #define G_COMPRESSOR_CONVERTER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_COMPRESSOR_CONVERTER, GCompressorConverter))
149 #define G_COMPRESSOR_CONVERTER_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_COMPRESSOR_CONVERTER, GCompressorConverterClass))
150 #define G_IS_COMPRESSOR_CONVERTER(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_COMPRESSOR_CONVERTER))
151 #define G_IS_COMPRESSOR_CONVERTER_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_COMPRESSOR_CONVERTER))
152 #define G_COMPRESSOR_CONVERTER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_COMPRESSOR_CONVERTER, GCompressorConverterClass))
153
154 typedef struct _GCompressorConverter       GCompressorConverter;
155 typedef struct _GCompressorConverterClass  GCompressorConverterClass;
156
157 struct _GCompressorConverterClass
158 {
159   GObjectClass parent_class;
160 };
161
162 GType       g_compressor_converter_get_type (void) G_GNUC_CONST;
163 GConverter *g_compressor_converter_new      (void);
164
165
166
167 static void g_compressor_converter_iface_init          (GConverterIface *iface);
168
169 struct _GCompressorConverter
170 {
171   GObject parent_instance;
172 };
173
174 G_DEFINE_TYPE_WITH_CODE (GCompressorConverter, g_compressor_converter, G_TYPE_OBJECT,
175                          G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER,
176                                                 g_compressor_converter_iface_init))
177
178 static void
179 g_compressor_converter_class_init (GCompressorConverterClass *klass)
180 {
181 }
182
183 static void
184 g_compressor_converter_init (GCompressorConverter *local)
185 {
186 }
187
188 GConverter *
189 g_compressor_converter_new (void)
190 {
191   GConverter *conv;
192
193   conv = g_object_new (G_TYPE_COMPRESSOR_CONVERTER, NULL);
194
195   return conv;
196 }
197
198 static void
199 g_compressor_converter_reset (GConverter *converter)
200 {
201 }
202
203 static GConverterResult
204 g_compressor_converter_convert (GConverter *converter,
205                                 const void *inbuf,
206                                 gsize       inbuf_size,
207                                 void       *outbuf,
208                                 gsize       outbuf_size,
209                                 GConverterFlags flags,
210                                 gsize      *bytes_read,
211                                 gsize      *bytes_written,
212                                 GError    **error)
213 {
214   GCompressorConverter  *conv;
215   const guint8 *in, *in_end;
216   guint8 v, *out;
217   int i;
218   gsize block_size;
219
220   conv = G_COMPRESSOR_CONVERTER (converter);
221
222   in = inbuf;
223   out = outbuf;
224   in_end = in + inbuf_size;
225
226   while (in < in_end)
227     {
228       v = *in;
229
230       if (v == 0)
231         {
232           block_size = 0;
233           while (in+block_size < in_end && *(in+block_size) == 0)
234             block_size ++;
235         }
236       else
237         block_size = v * 1000;
238
239       /* Not enough data */
240       if (in_end - in < block_size)
241         {
242           if (*bytes_read > 0)
243             break;
244           g_set_error_literal (error, G_IO_ERROR,
245                                G_IO_ERROR_PARTIAL_INPUT,
246                                "Need more data");
247           return G_CONVERTER_ERROR;
248         }
249
250       for (i = 0; i < block_size; i++)
251         {
252           if (*(in + i) != v)
253             {
254               if (*bytes_read > 0)
255                 break;
256               g_set_error_literal (error, G_IO_ERROR,
257                                    G_IO_ERROR_INVALID_DATA,
258                                    "invalid data");
259               return G_CONVERTER_ERROR;
260             }
261         }
262
263       if (v == 0 && in_end - in == block_size && (flags & G_CONVERTER_INPUT_AT_END) == 0)
264         {
265           if (*bytes_read > 0)
266             break;
267           g_set_error_literal (error, G_IO_ERROR,
268                                G_IO_ERROR_PARTIAL_INPUT,
269                                "Need more data");
270           return G_CONVERTER_ERROR;
271         }
272
273       in += block_size;
274       *out++ = v;
275       *bytes_read += block_size;
276       *bytes_written += 1;
277     }
278
279   if (in == in_end && (flags & G_CONVERTER_INPUT_AT_END))
280     return G_CONVERTER_FINISHED;
281   return G_CONVERTER_CONVERTED;
282 }
283
284 static void
285 g_compressor_converter_iface_init (GConverterIface *iface)
286 {
287   iface->convert = g_compressor_converter_convert;
288   iface->reset = g_compressor_converter_reset;
289 }
290
291 guint8 unexpanded_data[] = { 0,1,3,4,5,6,7,3,12,0,0};
292
293 static void
294 test_expander (void)
295 {
296   guint8 *converted1, *converted2, *ptr;
297   gsize n_read, n_written;
298   gsize total_read;
299   gssize res;
300   GConverterResult cres;
301   GInputStream *mem, *cstream;
302   GOutputStream *mem_out, *cstream_out;
303   GConverter *expander;
304   GConverter *converter;
305   GError *error;
306   int i;
307
308   expander = g_expander_converter_new ();
309
310   converted1 = g_malloc (100*1000); /* Large enough */
311   converted2 = g_malloc (100*1000); /* Large enough */
312
313   cres = g_converter_convert (expander,
314                               unexpanded_data, sizeof(unexpanded_data),
315                               converted1, 100*1000,
316                               G_CONVERTER_INPUT_AT_END,
317                               &n_read, &n_written, NULL);
318
319   g_assert (cres == G_CONVERTER_FINISHED);
320   g_assert (n_read == 11);
321   g_assert (n_written == 41030);
322
323   g_converter_reset (expander);
324
325   mem = g_memory_input_stream_new_from_data (unexpanded_data,
326                                              sizeof (unexpanded_data),
327                                              NULL);
328   cstream = g_converter_input_stream_new (mem, expander);
329   g_assert (g_converter_input_stream_get_converter (G_CONVERTER_INPUT_STREAM (cstream)) == expander);
330   g_object_get (cstream, "converter", &converter, NULL);
331   g_assert (converter == expander);
332   g_object_unref (converter);
333   g_object_unref (mem);
334
335   total_read = 0;
336   ptr = converted2;
337   while (TRUE)
338     {
339       error = NULL;
340       res = g_input_stream_read (cstream,
341                                  ptr, 1,
342                                  NULL, &error);
343       g_assert (res != -1);
344       if (res == 0)
345         break;
346       ptr += res;
347       total_read += res;
348     }
349
350   g_assert (total_read == n_written);
351   g_assert (memcmp (converted1, converted2, n_written)  == 0);
352
353   g_converter_reset (expander);
354
355   mem_out = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
356   cstream_out = g_converter_output_stream_new (mem_out, expander);
357   g_assert (g_converter_output_stream_get_converter (G_CONVERTER_OUTPUT_STREAM (cstream_out)) == expander);
358   g_object_get (cstream_out, "converter", &converter, NULL);
359   g_assert (converter == expander);
360   g_object_unref (converter);
361   g_object_unref (mem_out);
362
363   for (i = 0; i < sizeof(unexpanded_data); i++)
364     {
365       error = NULL;
366       res = g_output_stream_write (cstream_out,
367                                    unexpanded_data + i, 1,
368                                    NULL, &error);
369       g_assert (res != -1);
370       if (res == 0)
371         {
372           g_assert (i == sizeof(unexpanded_data) -1);
373           break;
374         }
375       g_assert (res == 1);
376     }
377
378   g_output_stream_close (cstream_out, NULL, NULL);
379
380   g_assert (g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (mem_out)) == n_written);
381   g_assert (memcmp (g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (mem_out)),
382                     converted1,
383                     n_written)  == 0);
384
385   g_free (converted1);
386   g_free (converted2);
387   g_object_unref (cstream);
388   g_object_unref (cstream_out);
389   g_object_unref (expander);
390 }
391
392 static void
393 test_compressor (void)
394 {
395   guint8 *converted, *expanded, *ptr;
396   gsize n_read, expanded_size;
397   gsize total_read;
398   gssize res;
399   GConverterResult cres;
400   GInputStream *mem, *cstream;
401   GOutputStream *mem_out, *cstream_out;
402   GConverter *expander, *compressor;
403   GError *error;
404   int i;
405
406   expander = g_expander_converter_new ();
407   expanded = g_malloc (100*1000); /* Large enough */
408   cres = g_converter_convert (expander,
409                               unexpanded_data, sizeof(unexpanded_data),
410                               expanded, 100*1000,
411                               G_CONVERTER_INPUT_AT_END,
412                               &n_read, &expanded_size, NULL);
413   g_assert (cres == G_CONVERTER_FINISHED);
414   g_assert (n_read == 11);
415   g_assert (expanded_size == 41030);
416
417   compressor = g_compressor_converter_new ();
418
419   converted = g_malloc (100*1000); /* Large enough */
420
421   mem = g_memory_input_stream_new_from_data (expanded,
422                                              expanded_size,
423                                              NULL);
424   cstream = g_converter_input_stream_new (mem, compressor);
425   g_object_unref (mem);
426
427   total_read = 0;
428   ptr = converted;
429   while (TRUE)
430     {
431       error = NULL;
432       res = g_input_stream_read (cstream,
433                                  ptr, 1,
434                                  NULL, &error);
435       g_assert (res != -1);
436       if (res == 0)
437         break;
438       ptr += res;
439       total_read += res;
440     }
441
442   g_assert (total_read == n_read - 1); /* Last 2 zeros are combined */
443   g_assert (memcmp (converted, unexpanded_data, total_read)  == 0);
444
445   g_object_unref (cstream);
446
447   g_converter_reset (compressor);
448
449   mem_out = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
450   cstream_out = g_converter_output_stream_new (mem_out, compressor);
451   g_object_unref (mem_out);
452
453   for (i = 0; i < expanded_size; i++)
454     {
455       error = NULL;
456       res = g_output_stream_write (cstream_out,
457                                    expanded + i, 1,
458                                    NULL, &error);
459       g_assert (res != -1);
460       if (res == 0)
461         {
462           g_assert (i == expanded_size -1);
463           break;
464         }
465       g_assert (res == 1);
466     }
467
468   g_output_stream_close (cstream_out, NULL, NULL);
469
470   g_assert (g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (mem_out)) == n_read - 1); /* Last 2 zeros are combined */
471   g_assert (memcmp (g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (mem_out)),
472                     unexpanded_data,
473                     g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (mem_out)))  == 0);
474
475   g_object_unref (cstream_out);
476
477   g_converter_reset (compressor);
478
479   memset (expanded, 5, 5*1000*2);
480
481   mem = g_memory_input_stream_new_from_data (expanded,
482                                              5*1000,
483                                              NULL);
484   cstream = g_converter_input_stream_new (mem, compressor);
485   g_object_unref (mem);
486
487   total_read = 0;
488   ptr = converted;
489   while (TRUE)
490     {
491       error = NULL;
492       res = g_input_stream_read (cstream,
493                                  ptr, 1,
494                                  NULL, &error);
495       g_assert (res != -1);
496       if (res == 0)
497         break;
498       ptr += res;
499       total_read += res;
500     }
501
502   g_assert (total_read == 1);
503   g_assert (*converted == 5);
504
505   g_object_unref (cstream);
506
507   mem = g_memory_input_stream_new_from_data (expanded,
508                                              5*1000 * 2,
509                                              NULL);
510   cstream = g_converter_input_stream_new (mem, compressor);
511   g_object_unref (mem);
512
513   total_read = 0;
514   ptr = converted;
515   while (TRUE)
516     {
517       error = NULL;
518       res = g_input_stream_read (cstream,
519                                  ptr, 1,
520                                  NULL, &error);
521       g_assert (res != -1);
522       if (res == 0)
523         break;
524       ptr += res;
525       total_read += res;
526     }
527
528   g_assert (total_read == 2);
529   g_assert (converted[0] == 5);
530   g_assert (converted[1] == 5);
531
532   g_object_unref (cstream);
533
534   g_converter_reset (compressor);
535
536   mem = g_memory_input_stream_new_from_data (expanded,
537                                              5*1000 * 2 - 1,
538                                              NULL);
539   cstream = g_converter_input_stream_new (mem, compressor);
540   g_object_unref (mem);
541
542   total_read = 0;
543   ptr = converted;
544   while (TRUE)
545     {
546       error = NULL;
547       res = g_input_stream_read (cstream,
548                                  ptr, 1,
549                                  NULL, &error);
550       if (res == -1)
551         {
552           g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT);
553           g_error_free (error);
554           break;
555         }
556
557       g_assert (res != 0);
558       ptr += res;
559       total_read += res;
560     }
561
562   g_assert (total_read == 1);
563   g_assert (converted[0] == 5);
564
565   g_object_unref (cstream);
566
567   g_free (expanded);
568   g_free (converted);
569   g_object_unref (expander);
570   g_object_unref (compressor);
571 }
572
573 #define DATA_LENGTH 1000000
574
575 static void
576 test_corruption (GZlibCompressorFormat format, gint level)
577 {
578   GError *error = NULL;
579   guint32 *data0, *data1;
580   gsize data1_size;
581   gint i;
582   GInputStream *istream0, *istream1, *cistream1;
583   GOutputStream *ostream1, *ostream2, *costream1;
584   GConverter *compressor, *decompressor;
585   GZlibCompressorFormat fmt;
586   gint lvl;
587
588   data0 = g_malloc (DATA_LENGTH * sizeof (guint32));
589   for (i = 0; i < DATA_LENGTH; i++)
590     data0[i] = g_random_int ();
591
592   istream0 = g_memory_input_stream_new_from_data (data0,
593     DATA_LENGTH * sizeof (guint32), NULL);
594
595   ostream1 = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
596   compressor = G_CONVERTER (g_zlib_compressor_new (format, level));
597   costream1 = g_converter_output_stream_new (ostream1, compressor);
598   g_assert (g_converter_output_stream_get_converter (G_CONVERTER_OUTPUT_STREAM (costream1)) == compressor);
599
600   g_output_stream_splice (costream1, istream0, 0, NULL, &error);
601   g_assert_no_error (error);
602
603   g_object_unref (costream1);
604
605   g_converter_reset (compressor);
606   g_object_get (compressor, "format", &fmt, "level", &lvl, NULL);
607   g_assert_cmpint (fmt, ==, format);
608   g_assert_cmpint (lvl, ==, level);
609   g_object_unref (compressor);
610   data1 = g_memory_output_stream_steal_data (G_MEMORY_OUTPUT_STREAM (ostream1));
611   data1_size = g_memory_output_stream_get_data_size (
612     G_MEMORY_OUTPUT_STREAM (ostream1));
613   g_object_unref (ostream1);
614   g_object_unref (istream0);
615
616   istream1 = g_memory_input_stream_new_from_data (data1, data1_size, g_free);
617   decompressor = G_CONVERTER (g_zlib_decompressor_new (format));
618   cistream1 = g_converter_input_stream_new (istream1, decompressor);
619
620   ostream2 = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
621
622   g_output_stream_splice (ostream2, cistream1, 0, NULL, &error);
623   g_assert_no_error (error);
624
625   g_assert_cmpuint (DATA_LENGTH * sizeof (guint32), ==,
626     g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (ostream2)));
627   g_assert (memcmp (data0, g_memory_output_stream_get_data (
628     G_MEMORY_OUTPUT_STREAM (ostream2)), DATA_LENGTH * sizeof (guint32)) == 0);
629   g_object_unref (istream1);
630   g_converter_reset (decompressor);
631   g_object_get (decompressor, "format", &fmt, NULL);
632   g_assert_cmpint (fmt, ==, format);
633   g_object_unref (decompressor);
634   g_object_unref (cistream1);
635   g_object_unref (ostream2);
636   g_free (data0);
637 }
638
639 typedef struct {
640   const gchar *path;
641   GZlibCompressorFormat format;
642   gint level;
643 } CompressorTest;
644
645 static void
646 test_roundtrip (gconstpointer data)
647 {
648   const CompressorTest *test = data;
649
650   g_test_bug ("162549");
651
652   test_corruption (test->format, test->level);
653 }
654
655 typedef struct {
656   const gchar *path;
657   const gchar *charset_in;
658   const gchar *text_in;
659   const gchar *charset_out;
660   const gchar *text_out;
661   gint n_fallbacks;
662 } CharsetTest;
663
664 static void
665 test_charset (gconstpointer data)
666 {
667   const CharsetTest *test = data;
668   GInputStream *in, *in2;
669   GConverter *conv;
670   gchar *buffer;
671   gsize count;
672   gsize bytes_read;
673   GError *error;
674   gboolean fallback;
675
676   conv = (GConverter *)g_charset_converter_new (test->charset_out, test->charset_in, NULL);
677   g_object_get (conv, "use-fallback", &fallback, NULL);
678   g_assert (!fallback);
679
680   in = g_memory_input_stream_new_from_data (test->text_in, -1, NULL);
681   in2 = g_converter_input_stream_new (in, conv);
682
683   count = 2 * strlen (test->text_out);
684   buffer = g_malloc0 (count);
685   error = NULL;
686   g_input_stream_read_all (in2, buffer, count, &bytes_read, NULL, &error);
687   if (test->n_fallbacks == 0)
688     {
689       g_assert_no_error (error);
690       g_assert_cmpint (bytes_read, ==, strlen (test->text_out));
691       g_assert_cmpstr (buffer, ==, test->text_out);
692     }
693   else
694     {
695       g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA);
696       g_error_free (error);
697     }
698
699   g_free (buffer);
700   g_object_unref (in2);
701   g_object_unref (in);
702
703   if (test->n_fallbacks == 0)
704     {
705        g_object_unref (conv);
706        return;
707     }
708
709   g_converter_reset (conv);
710
711   g_assert (!g_charset_converter_get_use_fallback (G_CHARSET_CONVERTER (conv)));
712   g_charset_converter_set_use_fallback (G_CHARSET_CONVERTER (conv), TRUE);
713
714   in = g_memory_input_stream_new_from_data (test->text_in, -1, NULL);
715   in2 = g_converter_input_stream_new (in, conv);
716
717   count = 2 * strlen (test->text_out);
718   buffer = g_malloc0 (count);
719   error = NULL;
720   g_input_stream_read_all (in2, buffer, count, &bytes_read, NULL, &error);
721   g_assert_no_error (error);
722   g_assert_cmpstr (buffer, ==, test->text_out);
723   g_assert_cmpint (bytes_read, ==, strlen (test->text_out));
724   g_assert_cmpint (test->n_fallbacks, ==, g_charset_converter_get_num_fallbacks (G_CHARSET_CONVERTER (conv)));
725
726   g_free (buffer);
727   g_object_unref (in2);
728   g_object_unref (in);
729
730   g_object_unref (conv);
731 }
732
733 int
734 main (int   argc,
735       char *argv[])
736 {
737   CompressorTest compressor_tests[] = {
738     { "/converter-output-stream/corruption/zlib-0", G_ZLIB_COMPRESSOR_FORMAT_ZLIB, 0 },
739     { "/converter-output-stream/corruption/zlib-9", G_ZLIB_COMPRESSOR_FORMAT_ZLIB, 9 },
740     { "/converter-output-stream/corruption/gzip-0", G_ZLIB_COMPRESSOR_FORMAT_GZIP, 0 },
741     { "/converter-output-stream/corruption/gzip-9", G_ZLIB_COMPRESSOR_FORMAT_GZIP, 9 },
742     { "/converter-output-stream/corruption/raw-0", G_ZLIB_COMPRESSOR_FORMAT_RAW, 0 },
743     { "/converter-output-stream/corruption/raw-9", G_ZLIB_COMPRESSOR_FORMAT_RAW, 9 },
744   };
745   CharsetTest charset_tests[] = {
746     { "/converter-input-stream/charset/utf8->latin1", "UTF-8", "\303\205rr Sant\303\251", "ISO-8859-1", "\305rr Sant\351", 0 },
747     { "/converter-input-stream/charset/latin1->utf8", "ISO-8859-1", "\305rr Sant\351", "UTF-8", "\303\205rr Sant\303\251", 0 },
748     { "/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 },
749
750   };
751
752   gint i;
753
754   g_type_init ();
755   g_test_init (&argc, &argv, NULL);
756
757   g_test_bug_base ("http://bugzilla.gnome.org/");
758
759   g_test_add_func ("/converter-input-stream/expander", test_expander);
760   g_test_add_func ("/converter-input-stream/compressor", test_compressor);
761
762   for (i = 0; i < G_N_ELEMENTS (compressor_tests); i++)
763     g_test_add_data_func (compressor_tests[i].path, &compressor_tests[i], test_roundtrip);
764
765   for (i = 0; i < G_N_ELEMENTS (charset_tests); i++)
766     g_test_add_data_func (charset_tests[i].path, &charset_tests[i], test_charset);
767
768
769   return g_test_run();
770 }