c3d210611d2f284f2ce6884d4bc9231fe975d700
[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   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 (error, G_IO_ERROR,
119                                G_IO_ERROR_NO_SPACE,
120                                "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 (error, G_IO_ERROR,
239                                G_IO_ERROR_PARTIAL_INPUT,
240                                "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 (error, G_IO_ERROR,
251                                    G_IO_ERROR_INVALID_DATA,
252                                    "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 (error, G_IO_ERROR,
262                                G_IO_ERROR_PARTIAL_INPUT,
263                                "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 (100*1000); /* Large enough */
305   converted2 = g_malloc (100*1000); /* Large enough */
306
307   cres = g_converter_convert (expander,
308                               unexpanded_data, sizeof(unexpanded_data),
309                               converted1, 100*1000,
310                               G_CONVERTER_INPUT_AT_END,
311                               &n_read, &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 (expander);
318
319   mem = g_memory_input_stream_new_from_data (unexpanded_data,
320                                              sizeof (unexpanded_data),
321                                              NULL);
322   cstream = g_converter_input_stream_new (mem, expander);
323   g_assert (g_converter_input_stream_get_converter (G_CONVERTER_INPUT_STREAM (cstream)) == expander);
324   g_object_get (cstream, "converter", &converter, NULL);
325   g_assert (converter == expander);
326   g_object_unref (converter);
327   g_object_unref (mem);
328
329   total_read = 0;
330   ptr = converted2;
331   while (TRUE)
332     {
333       error = NULL;
334       res = g_input_stream_read (cstream,
335                                  ptr, 1,
336                                  NULL, &error);
337       g_assert (res != -1);
338       if (res == 0)
339         break;
340       ptr += res;
341       total_read += res;
342     }
343
344   g_assert (total_read == n_written);
345   g_assert (memcmp (converted1, converted2, n_written)  == 0);
346
347   g_converter_reset (expander);
348
349   mem_out = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
350   cstream_out = g_converter_output_stream_new (mem_out, expander);
351   g_assert (g_converter_output_stream_get_converter (G_CONVERTER_OUTPUT_STREAM (cstream_out)) == expander);
352   g_object_get (cstream_out, "converter", &converter, NULL);
353   g_assert (converter == expander);
354   g_object_unref (converter);
355   g_object_unref (mem_out);
356
357   for (i = 0; i < sizeof(unexpanded_data); i++)
358     {
359       error = NULL;
360       res = g_output_stream_write (cstream_out,
361                                    unexpanded_data + i, 1,
362                                    NULL, &error);
363       g_assert (res != -1);
364       if (res == 0)
365         {
366           g_assert (i == sizeof(unexpanded_data) -1);
367           break;
368         }
369       g_assert (res == 1);
370     }
371
372   g_output_stream_close (cstream_out, NULL, NULL);
373
374   g_assert (g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (mem_out)) == n_written);
375   g_assert (memcmp (g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (mem_out)),
376                     converted1,
377                     n_written)  == 0);
378
379   g_free (converted1);
380   g_free (converted2);
381   g_object_unref (cstream);
382   g_object_unref (cstream_out);
383   g_object_unref (expander);
384 }
385
386 static void
387 test_compressor (void)
388 {
389   guint8 *converted, *expanded, *ptr;
390   gsize n_read, expanded_size;
391   gsize total_read;
392   gssize res;
393   GConverterResult cres;
394   GInputStream *mem, *cstream;
395   GOutputStream *mem_out, *cstream_out;
396   GConverter *expander, *compressor;
397   GError *error;
398   int i;
399
400   expander = g_expander_converter_new ();
401   expanded = g_malloc (100*1000); /* Large enough */
402   cres = g_converter_convert (expander,
403                               unexpanded_data, sizeof(unexpanded_data),
404                               expanded, 100*1000,
405                               G_CONVERTER_INPUT_AT_END,
406                               &n_read, &expanded_size, NULL);
407   g_assert (cres == G_CONVERTER_FINISHED);
408   g_assert (n_read == 11);
409   g_assert (expanded_size == 41030);
410
411   compressor = g_compressor_converter_new ();
412
413   converted = g_malloc (100*1000); /* Large enough */
414
415   mem = g_memory_input_stream_new_from_data (expanded,
416                                              expanded_size,
417                                              NULL);
418   cstream = g_converter_input_stream_new (mem, compressor);
419   g_object_unref (mem);
420
421   total_read = 0;
422   ptr = converted;
423   while (TRUE)
424     {
425       error = NULL;
426       res = g_input_stream_read (cstream,
427                                  ptr, 1,
428                                  NULL, &error);
429       g_assert (res != -1);
430       if (res == 0)
431         break;
432       ptr += res;
433       total_read += res;
434     }
435
436   g_assert (total_read == n_read - 1); /* Last 2 zeros are combined */
437   g_assert (memcmp (converted, unexpanded_data, total_read)  == 0);
438
439   g_object_unref (cstream);
440
441   g_converter_reset (compressor);
442
443   mem_out = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
444   cstream_out = g_converter_output_stream_new (mem_out, compressor);
445   g_object_unref (mem_out);
446
447   for (i = 0; i < expanded_size; i++)
448     {
449       error = NULL;
450       res = g_output_stream_write (cstream_out,
451                                    expanded + i, 1,
452                                    NULL, &error);
453       g_assert (res != -1);
454       if (res == 0)
455         {
456           g_assert (i == expanded_size -1);
457           break;
458         }
459       g_assert (res == 1);
460     }
461
462   g_output_stream_close (cstream_out, NULL, NULL);
463
464   g_assert (g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (mem_out)) == n_read - 1); /* Last 2 zeros are combined */
465   g_assert (memcmp (g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (mem_out)),
466                     unexpanded_data,
467                     g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (mem_out)))  == 0);
468
469   g_object_unref (cstream_out);
470
471   g_converter_reset (compressor);
472
473   memset (expanded, 5, 5*1000*2);
474
475   mem = g_memory_input_stream_new_from_data (expanded,
476                                              5*1000,
477                                              NULL);
478   cstream = g_converter_input_stream_new (mem, compressor);
479   g_object_unref (mem);
480
481   total_read = 0;
482   ptr = converted;
483   while (TRUE)
484     {
485       error = NULL;
486       res = g_input_stream_read (cstream,
487                                  ptr, 1,
488                                  NULL, &error);
489       g_assert (res != -1);
490       if (res == 0)
491         break;
492       ptr += res;
493       total_read += res;
494     }
495
496   g_assert (total_read == 1);
497   g_assert (*converted == 5);
498
499   g_object_unref (cstream);
500
501   mem = g_memory_input_stream_new_from_data (expanded,
502                                              5*1000 * 2,
503                                              NULL);
504   cstream = g_converter_input_stream_new (mem, compressor);
505   g_object_unref (mem);
506
507   total_read = 0;
508   ptr = converted;
509   while (TRUE)
510     {
511       error = NULL;
512       res = g_input_stream_read (cstream,
513                                  ptr, 1,
514                                  NULL, &error);
515       g_assert (res != -1);
516       if (res == 0)
517         break;
518       ptr += res;
519       total_read += res;
520     }
521
522   g_assert (total_read == 2);
523   g_assert (converted[0] == 5);
524   g_assert (converted[1] == 5);
525
526   g_object_unref (cstream);
527
528   g_converter_reset (compressor);
529
530   mem = g_memory_input_stream_new_from_data (expanded,
531                                              5*1000 * 2 - 1,
532                                              NULL);
533   cstream = g_converter_input_stream_new (mem, compressor);
534   g_object_unref (mem);
535
536   total_read = 0;
537   ptr = converted;
538   while (TRUE)
539     {
540       error = NULL;
541       res = g_input_stream_read (cstream,
542                                  ptr, 1,
543                                  NULL, &error);
544       if (res == -1)
545         {
546           g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT);
547           g_error_free (error);
548           break;
549         }
550
551       g_assert (res != 0);
552       ptr += res;
553       total_read += res;
554     }
555
556   g_assert (total_read == 1);
557   g_assert (converted[0] == 5);
558
559   g_object_unref (cstream);
560
561   g_free (expanded);
562   g_free (converted);
563   g_object_unref (expander);
564   g_object_unref (compressor);
565 }
566
567 #define LEFTOVER_SHORT_READ_SIZE 512
568
569 #define G_TYPE_LEFTOVER_CONVERTER         (g_leftover_converter_get_type ())
570 #define G_LEFTOVER_CONVERTER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_LEFTOVER_CONVERTER, GLeftoverConverter))
571 #define G_LEFTOVER_CONVERTER_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_LEFTOVER_CONVERTER, GLeftoverConverterClass))
572 #define G_IS_LEFTOVER_CONVERTER(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_LEFTOVER_CONVERTER))
573 #define G_IS_LEFTOVER_CONVERTER_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_LEFTOVER_CONVERTER))
574 #define G_LEFTOVER_CONVERTER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_LEFTOVER_CONVERTER, GLeftoverConverterClass))
575
576 typedef struct _GLeftoverConverter       GLeftoverConverter;
577 typedef struct _GLeftoverConverterClass  GLeftoverConverterClass;
578
579 struct _GLeftoverConverterClass
580 {
581   GObjectClass parent_class;
582 };
583
584 GType       g_leftover_converter_get_type (void) G_GNUC_CONST;
585 GConverter *g_leftover_converter_new      (void);
586
587
588
589 static void g_leftover_converter_iface_init          (GConverterIface *iface);
590
591 struct _GLeftoverConverter
592 {
593   GObject parent_instance;
594 };
595
596 G_DEFINE_TYPE_WITH_CODE (GLeftoverConverter, g_leftover_converter, G_TYPE_OBJECT,
597                          G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER,
598                                                 g_leftover_converter_iface_init))
599
600 static void
601 g_leftover_converter_class_init (GLeftoverConverterClass *klass)
602 {
603 }
604
605 static void
606 g_leftover_converter_init (GLeftoverConverter *local)
607 {
608 }
609
610 GConverter *
611 g_leftover_converter_new (void)
612 {
613   GConverter *conv;
614
615   conv = g_object_new (G_TYPE_LEFTOVER_CONVERTER, NULL);
616
617   return conv;
618 }
619
620 static void
621 g_leftover_converter_reset (GConverter *converter)
622 {
623 }
624
625 static GConverterResult
626 g_leftover_converter_convert (GConverter *converter,
627                               const void *inbuf,
628                               gsize       inbuf_size,
629                               void       *outbuf,
630                               gsize       outbuf_size,
631                               GConverterFlags flags,
632                               gsize      *bytes_read,
633                               gsize      *bytes_written,
634                               GError    **error)
635 {
636   if (outbuf_size == LEFTOVER_SHORT_READ_SIZE)
637     {
638       g_set_error_literal (error,
639                            G_IO_ERROR,
640                            G_IO_ERROR_PARTIAL_INPUT,
641                            "partial input");
642       return G_CONVERTER_ERROR;
643     }
644
645   if (inbuf_size < 100)
646     *bytes_read = *bytes_written = MIN (inbuf_size, outbuf_size);
647   else
648     *bytes_read = *bytes_written = MIN (inbuf_size - 10, outbuf_size);
649   memcpy (outbuf, inbuf, *bytes_written);
650
651   if (*bytes_read == inbuf_size && (flags & G_CONVERTER_INPUT_AT_END))
652     return G_CONVERTER_FINISHED;
653   return G_CONVERTER_CONVERTED;
654 }
655
656 static void
657 g_leftover_converter_iface_init (GConverterIface *iface)
658 {
659   iface->convert = g_leftover_converter_convert;
660   iface->reset = g_leftover_converter_reset;
661 }
662
663 #define LEFTOVER_BUFSIZE 8192
664 #define INTERNAL_BUFSIZE 4096
665
666 static void
667 test_converter_leftover (void)
668 {
669   gchar *orig, *converted;
670   gsize total_read;
671   gssize res;
672   goffset offset;
673   GInputStream *mem, *cstream;
674   GConverter *converter;
675   GError *error;
676   int i;
677
678   converter = g_leftover_converter_new ();
679
680   orig = g_malloc (LEFTOVER_BUFSIZE);
681   converted = g_malloc (LEFTOVER_BUFSIZE);
682   for (i = 0; i < LEFTOVER_BUFSIZE; i++)
683     orig[i] = i % 64 + 32;
684
685   mem = g_memory_input_stream_new_from_data (orig, LEFTOVER_BUFSIZE, NULL);
686   cstream = g_converter_input_stream_new (mem, G_CONVERTER (converter));
687   g_object_unref (mem);
688
689   total_read = 0;
690
691   error = NULL;
692   res = g_input_stream_read (cstream,
693                              converted, LEFTOVER_SHORT_READ_SIZE,
694                              NULL, &error);
695   g_assert_cmpint (res, ==, LEFTOVER_SHORT_READ_SIZE);
696   total_read += res;
697
698   offset = g_seekable_tell (G_SEEKABLE (mem));
699   g_assert_cmpint (offset, >, LEFTOVER_SHORT_READ_SIZE);
700   g_assert_cmpint (offset, <, LEFTOVER_BUFSIZE);
701
702   /* At this point, @cstream has both a non-empty input_buffer
703    * and a non-empty converted_buffer, which is the case
704    * we want to test.
705    */
706
707   while (TRUE)
708     {
709       error = NULL;
710       res = g_input_stream_read (cstream,
711                                  converted + total_read,
712                                  LEFTOVER_BUFSIZE - total_read,
713                                  NULL, &error);
714       g_assert (res >= 0);
715       if (res == 0)
716         break;
717       total_read += res;
718   }
719
720   g_assert_cmpint (total_read, ==, LEFTOVER_BUFSIZE);
721   g_assert (memcmp (converted, orig, LEFTOVER_BUFSIZE)  == 0);
722
723   g_object_unref (cstream);
724   g_free (orig);
725   g_free (converted);
726   g_object_unref (converter);
727 }
728
729 #define DATA_LENGTH 1000000
730
731 typedef struct {
732   const gchar *path;
733   GZlibCompressorFormat format;
734   gint level;
735 } CompressorTest;
736
737 static void
738 test_roundtrip (gconstpointer data)
739 {
740   const CompressorTest *test = data;
741   GError *error = NULL;
742   guint32 *data0, *data1;
743   gsize data1_size;
744   gint i;
745   GInputStream *istream0, *istream1, *cistream1;
746   GOutputStream *ostream1, *ostream2, *costream1;
747   GConverter *compressor, *decompressor;
748   GZlibCompressorFormat fmt;
749   gint lvl;
750
751   g_test_bug ("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 (data0,
758     DATA_LENGTH * sizeof (guint32), NULL);
759
760   ostream1 = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
761   compressor = G_CONVERTER (g_zlib_compressor_new (test->format, test->level));
762   costream1 = g_converter_output_stream_new (ostream1, compressor);
763   g_assert (g_converter_output_stream_get_converter (G_CONVERTER_OUTPUT_STREAM (costream1)) == compressor);
764
765   g_output_stream_splice (costream1, istream0, 0, NULL, &error);
766   g_assert_no_error (error);
767
768   g_object_unref (costream1);
769
770   g_converter_reset (compressor);
771   g_object_get (compressor, "format", &fmt, "level", &lvl, NULL);
772   g_assert_cmpint (fmt, ==, test->format);
773   g_assert_cmpint (lvl, ==, test->level);
774   g_object_unref (compressor);
775   data1 = g_memory_output_stream_steal_data (G_MEMORY_OUTPUT_STREAM (ostream1));
776   data1_size = g_memory_output_stream_get_data_size (
777     G_MEMORY_OUTPUT_STREAM (ostream1));
778   g_object_unref (ostream1);
779   g_object_unref (istream0);
780
781   istream1 = g_memory_input_stream_new_from_data (data1, data1_size, g_free);
782   decompressor = G_CONVERTER (g_zlib_decompressor_new (test->format));
783   cistream1 = g_converter_input_stream_new (istream1, decompressor);
784
785   ostream2 = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
786
787   g_output_stream_splice (ostream2, cistream1, 0, NULL, &error);
788   g_assert_no_error (error);
789
790   g_assert_cmpuint (DATA_LENGTH * sizeof (guint32), ==,
791     g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (ostream2)));
792   g_assert (memcmp (data0, g_memory_output_stream_get_data (
793     G_MEMORY_OUTPUT_STREAM (ostream2)), DATA_LENGTH * sizeof (guint32)) == 0);
794   g_object_unref (istream1);
795   g_converter_reset (decompressor);
796   g_object_get (decompressor, "format", &fmt, NULL);
797   g_assert_cmpint (fmt, ==, test->format);
798   g_object_unref (decompressor);
799   g_object_unref (cistream1);
800   g_object_unref (ostream2);
801   g_free (data0);
802 }
803
804 typedef struct {
805   const gchar *path;
806   const gchar *charset_in;
807   const gchar *text_in;
808   const gchar *charset_out;
809   const gchar *text_out;
810   gint n_fallbacks;
811 } CharsetTest;
812
813 static void
814 test_charset (gconstpointer data)
815 {
816   const CharsetTest *test = data;
817   GInputStream *in, *in2;
818   GConverter *conv;
819   gchar *buffer;
820   gsize count;
821   gsize bytes_read;
822   GError *error;
823   gboolean fallback;
824
825   conv = (GConverter *)g_charset_converter_new (test->charset_out, test->charset_in, NULL);
826   g_object_get (conv, "use-fallback", &fallback, NULL);
827   g_assert (!fallback);
828
829   in = g_memory_input_stream_new_from_data (test->text_in, -1, NULL);
830   in2 = g_converter_input_stream_new (in, conv);
831
832   count = 2 * strlen (test->text_out);
833   buffer = g_malloc0 (count);
834   error = NULL;
835   g_input_stream_read_all (in2, buffer, count, &bytes_read, NULL, &error);
836   if (test->n_fallbacks == 0)
837     {
838       g_assert_no_error (error);
839       g_assert_cmpint (bytes_read, ==, strlen (test->text_out));
840       g_assert_cmpstr (buffer, ==, test->text_out);
841     }
842   else
843     {
844       g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA);
845       g_error_free (error);
846     }
847
848   g_free (buffer);
849   g_object_unref (in2);
850   g_object_unref (in);
851
852   if (test->n_fallbacks == 0)
853     {
854        g_object_unref (conv);
855        return;
856     }
857
858   g_converter_reset (conv);
859
860   g_assert (!g_charset_converter_get_use_fallback (G_CHARSET_CONVERTER (conv)));
861   g_charset_converter_set_use_fallback (G_CHARSET_CONVERTER (conv), TRUE);
862
863   in = g_memory_input_stream_new_from_data (test->text_in, -1, NULL);
864   in2 = g_converter_input_stream_new (in, conv);
865
866   count = 2 * strlen (test->text_out);
867   buffer = g_malloc0 (count);
868   error = NULL;
869   g_input_stream_read_all (in2, buffer, count, &bytes_read, NULL, &error);
870   g_assert_no_error (error);
871   g_assert_cmpstr (buffer, ==, test->text_out);
872   g_assert_cmpint (bytes_read, ==, strlen (test->text_out));
873   g_assert_cmpint (test->n_fallbacks, ==, g_charset_converter_get_num_fallbacks (G_CHARSET_CONVERTER (conv)));
874
875   g_free (buffer);
876   g_object_unref (in2);
877   g_object_unref (in);
878
879   g_object_unref (conv);
880 }
881
882
883 static void
884 client_connected (GObject      *source,
885                   GAsyncResult *result,
886                   gpointer      user_data)
887 {
888   GSocketClient *client = G_SOCKET_CLIENT (source);
889   GSocketConnection **conn = user_data;
890   GError *error = NULL;
891
892   *conn = g_socket_client_connect_finish (client, result, &error);
893   g_assert_no_error (error);
894 }
895
896 static void
897 server_connected (GObject      *source,
898                   GAsyncResult *result,
899                   gpointer      user_data)
900 {
901   GSocketListener *listener = G_SOCKET_LISTENER (source);
902   GSocketConnection **conn = user_data;
903   GError *error = NULL;
904
905   *conn = g_socket_listener_accept_finish (listener, result, NULL, &error);
906   g_assert_no_error (error);
907 }
908
909 static void
910 make_socketpair (GIOStream **left,
911                  GIOStream **right)
912 {
913   GInetAddress *iaddr;
914   GSocketAddress *saddr, *effective_address;
915   GSocketListener *listener;
916   GSocketClient *client;
917   GError *error = NULL;
918   GSocketConnection *client_conn = NULL, *server_conn = NULL;
919
920   iaddr = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4);
921   saddr = g_inet_socket_address_new (iaddr, 0);
922   g_object_unref (iaddr);
923
924   listener = g_socket_listener_new ();
925   g_socket_listener_add_address (listener, saddr,
926                                  G_SOCKET_TYPE_STREAM,
927                                  G_SOCKET_PROTOCOL_TCP,
928                                  NULL,
929                                  &effective_address,
930                                  &error);
931   g_assert_no_error (error);
932   g_object_unref (saddr);
933
934   client = g_socket_client_new ();
935
936   g_socket_client_connect_async (client,
937                                  G_SOCKET_CONNECTABLE (effective_address),
938                                  NULL, client_connected, &client_conn);
939   g_socket_listener_accept_async (listener, NULL,
940                                   server_connected, &server_conn);
941
942   while (!client_conn || !server_conn)
943     g_main_context_iteration (NULL, TRUE);
944
945   g_object_unref (client);
946   g_object_unref (listener);
947   g_object_unref (effective_address);
948
949   *left = G_IO_STREAM (client_conn);
950   *right = G_IO_STREAM (server_conn);
951 }
952
953 static void
954 test_converter_pollable (void)
955 {
956   GIOStream *left, *right;
957   guint8 *converted, *inptr;
958   guint8 *expanded, *outptr, *expanded_end;
959   gsize n_read, expanded_size;
960   gsize total_read;
961   gssize res;
962   gboolean is_readable;
963   GConverterResult cres;
964   GInputStream *cstream;
965   GPollableInputStream *pollable_in;
966   GOutputStream *socket_out, *mem_out, *cstream_out;
967   GPollableOutputStream *pollable_out;
968   GConverter *expander, *compressor;
969   GError *error;
970   int i;
971
972   expander = g_expander_converter_new ();
973   expanded = g_malloc (100*1000); /* Large enough */
974   cres = g_converter_convert (expander,
975                               unexpanded_data, sizeof(unexpanded_data),
976                               expanded, 100*1000,
977                               G_CONVERTER_INPUT_AT_END,
978                               &n_read, &expanded_size, NULL);
979   g_assert (cres == G_CONVERTER_FINISHED);
980   g_assert (n_read == 11);
981   g_assert (expanded_size == 41030);
982   expanded_end = expanded + expanded_size;
983
984   make_socketpair (&left, &right);
985
986   compressor = g_compressor_converter_new ();
987
988   converted = g_malloc (100*1000); /* Large enough */
989
990   cstream = g_converter_input_stream_new (g_io_stream_get_input_stream (left),
991                                           compressor);
992   pollable_in = G_POLLABLE_INPUT_STREAM (cstream);
993   g_assert (g_pollable_input_stream_can_poll (pollable_in));
994
995   socket_out = g_io_stream_get_output_stream (right);
996
997   total_read = 0;
998   outptr = expanded;
999   inptr = converted;
1000   while (TRUE)
1001     {
1002       error = NULL;
1003
1004       if (outptr < expanded_end)
1005         {
1006           res = g_output_stream_write (socket_out,
1007                                        outptr,
1008                                        MIN (1000, (expanded_end - outptr)),
1009                                        NULL, &error);
1010           g_assert_cmpint (res, >, 0);
1011           outptr += res;
1012         }
1013       else if (socket_out)
1014         {
1015           g_object_unref (right);
1016           socket_out = NULL;
1017         }
1018
1019       is_readable = g_pollable_input_stream_is_readable (pollable_in);
1020       res = g_pollable_input_stream_read_nonblocking (pollable_in,
1021                                                       inptr, 1,
1022                                                       NULL, &error);
1023
1024       /* is_readable can be a false positive, but not a false negative */
1025       if (!is_readable)
1026         g_assert_cmpint (res, ==, -1);
1027
1028       /* After closing the write end, we can't get WOULD_BLOCK any more */
1029       if (!socket_out)
1030         g_assert_cmpint (res, !=, -1);
1031
1032       if (res == -1)
1033         {
1034           g_assert_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK);
1035           g_error_free (error);
1036
1037           continue;
1038         }
1039
1040       if (res == 0)
1041         break;
1042       inptr += res;
1043       total_read += res;
1044     }
1045
1046   g_assert (total_read == n_read - 1); /* Last 2 zeros are combined */
1047   g_assert (memcmp (converted, unexpanded_data, total_read)  == 0);
1048
1049   g_object_unref (cstream);
1050   g_object_unref (left);
1051
1052   g_converter_reset (compressor);
1053
1054   /* This doesn't actually test the behavior on
1055    * G_IO_ERROR_WOULD_BLOCK; to do that we'd need to implement a
1056    * custom GOutputStream that we could control blocking on.
1057    */
1058
1059   mem_out = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
1060   cstream_out = g_converter_output_stream_new (mem_out, compressor);
1061   g_object_unref (mem_out);
1062   pollable_out = G_POLLABLE_OUTPUT_STREAM (cstream_out);
1063
1064   for (i = 0; i < expanded_size; i++)
1065     {
1066       error = NULL;
1067       res = g_pollable_output_stream_write_nonblocking (pollable_out,
1068                                                         expanded + i, 1,
1069                                                         NULL, &error);
1070       g_assert (res != -1);
1071       if (res == 0)
1072         {
1073           g_assert (i == expanded_size -1);
1074           break;
1075         }
1076       g_assert (res == 1);
1077     }
1078
1079   g_output_stream_close (cstream_out, NULL, NULL);
1080
1081   g_assert (g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (mem_out)) == n_read - 1); /* Last 2 zeros are combined */
1082   g_assert (memcmp (g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (mem_out)),
1083                     unexpanded_data,
1084                     g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (mem_out)))  == 0);
1085
1086   g_object_unref (cstream_out);
1087
1088   g_free (expanded);
1089   g_free (converted);
1090   g_object_unref (expander);
1091   g_object_unref (compressor);
1092 }
1093
1094 static void
1095 test_truncation (gconstpointer data)
1096 {
1097   const CompressorTest *test = data;
1098   GError *error = NULL;
1099   guint32 *data0, *data1;
1100   gsize data1_size;
1101   gint i;
1102   GInputStream *istream0, *istream1, *cistream1;
1103   GOutputStream *ostream1, *ostream2, *costream1;
1104   GConverter *compressor, *decompressor;
1105
1106   data0 = g_malloc (DATA_LENGTH * sizeof (guint32));
1107   for (i = 0; i < DATA_LENGTH; i++)
1108     data0[i] = g_random_int ();
1109
1110   istream0 = g_memory_input_stream_new_from_data (data0,
1111     DATA_LENGTH * sizeof (guint32), NULL);
1112
1113   ostream1 = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
1114   compressor = G_CONVERTER (g_zlib_compressor_new (test->format, -1));
1115   costream1 = g_converter_output_stream_new (ostream1, compressor);
1116   g_assert (g_converter_output_stream_get_converter (G_CONVERTER_OUTPUT_STREAM (costream1)) == compressor);
1117
1118   g_output_stream_splice (costream1, istream0, 0, NULL, &error);
1119   g_assert_no_error (error);
1120
1121   g_object_unref (costream1);
1122   g_object_unref (compressor);
1123
1124   data1 = g_memory_output_stream_steal_data (G_MEMORY_OUTPUT_STREAM (ostream1));
1125   data1_size = g_memory_output_stream_get_data_size (
1126     G_MEMORY_OUTPUT_STREAM (ostream1));
1127   g_object_unref (ostream1);
1128   g_object_unref (istream0);
1129
1130   /* truncate */
1131   data1_size /= 2;
1132
1133   istream1 = g_memory_input_stream_new_from_data (data1, data1_size, g_free);
1134   decompressor = G_CONVERTER (g_zlib_decompressor_new (test->format));
1135   cistream1 = g_converter_input_stream_new (istream1, decompressor);
1136
1137   ostream2 = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
1138
1139   g_output_stream_splice (ostream2, cistream1, 0, NULL, &error);
1140   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT);
1141   g_error_free (error);
1142
1143   g_object_unref (istream1);
1144   g_object_unref (decompressor);
1145   g_object_unref (cistream1);
1146   g_object_unref (ostream2);
1147   g_free (data0);
1148 }
1149
1150 int
1151 main (int   argc,
1152       char *argv[])
1153 {
1154   CompressorTest compressor_tests[] = {
1155     { "/converter-output-stream/roundtrip/zlib-0", G_ZLIB_COMPRESSOR_FORMAT_ZLIB, 0 },
1156     { "/converter-output-stream/roundtrip/zlib-9", G_ZLIB_COMPRESSOR_FORMAT_ZLIB, 9 },
1157     { "/converter-output-stream/roundtrip/gzip-0", G_ZLIB_COMPRESSOR_FORMAT_GZIP, 0 },
1158     { "/converter-output-stream/roundtrip/gzip-9", G_ZLIB_COMPRESSOR_FORMAT_GZIP, 9 },
1159     { "/converter-output-stream/roundtrip/raw-0", G_ZLIB_COMPRESSOR_FORMAT_RAW, 0 },
1160     { "/converter-output-stream/roundtrip/raw-9", G_ZLIB_COMPRESSOR_FORMAT_RAW, 9 },
1161   };
1162   CompressorTest truncation_tests[] = {
1163     { "/converter-input-stream/truncation/zlib", G_ZLIB_COMPRESSOR_FORMAT_ZLIB, 0 },
1164     { "/converter-input-stream/truncation/gzip", G_ZLIB_COMPRESSOR_FORMAT_GZIP, 0 },
1165     { "/converter-input-stream/truncation/raw", G_ZLIB_COMPRESSOR_FORMAT_RAW, 0 },
1166   };
1167   CharsetTest charset_tests[] = {
1168     { "/converter-input-stream/charset/utf8->latin1", "UTF-8", "\303\205rr Sant\303\251", "ISO-8859-1", "\305rr Sant\351", 0 },
1169     { "/converter-input-stream/charset/latin1->utf8", "ISO-8859-1", "\305rr Sant\351", "UTF-8", "\303\205rr Sant\303\251", 0 },
1170     { "/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 },
1171   };
1172
1173   gint i;
1174
1175   g_test_init (&argc, &argv, NULL);
1176
1177   g_test_bug_base ("http://bugzilla.gnome.org/");
1178
1179   g_test_add_func ("/converter-input-stream/expander", test_expander);
1180   g_test_add_func ("/converter-input-stream/compressor", test_compressor);
1181
1182   for (i = 0; i < G_N_ELEMENTS (compressor_tests); i++)
1183     g_test_add_data_func (compressor_tests[i].path, &compressor_tests[i], test_roundtrip);
1184
1185   for (i = 0; i < G_N_ELEMENTS (truncation_tests); i++)
1186     g_test_add_data_func (truncation_tests[i].path, &truncation_tests[i], test_truncation);
1187
1188   for (i = 0; i < G_N_ELEMENTS (charset_tests); i++)
1189     g_test_add_data_func (charset_tests[i].path, &charset_tests[i], test_charset);
1190
1191   g_test_add_func ("/converter-stream/pollable", test_converter_pollable);
1192   g_test_add_func ("/converter-stream/leftover", test_converter_leftover);
1193
1194   return g_test_run();
1195 }