• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
G_DEFINE_TYPE_WITH_CODE(GExpanderConverter,g_expander_converter,G_TYPE_OBJECT,G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER,g_expander_converter_iface_init))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
g_expander_converter_init(GExpanderConverter * local)65 g_expander_converter_init (GExpanderConverter *local)
66 {
67 }
68 
69 GConverter *
g_expander_converter_new(void)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
g_expander_converter_reset(GConverter * converter)80 g_expander_converter_reset (GConverter *converter)
81 {
82 }
83 
84 static GConverterResult
g_expander_converter_convert(GConverter * converter,const void * inbuf,gsize inbuf_size,void * outbuf,gsize outbuf_size,GConverterFlags flags,gsize * bytes_read,gsize * bytes_written,GError ** error)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
g_expander_converter_iface_init(GConverterIface * iface)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 
G_DEFINE_TYPE_WITH_CODE(GCompressorConverter,g_compressor_converter,G_TYPE_OBJECT,G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER,g_compressor_converter_iface_init))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
g_compressor_converter_init(GCompressorConverter * local)181 g_compressor_converter_init (GCompressorConverter *local)
182 {
183 }
184 
185 GConverter *
g_compressor_converter_new(void)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
g_compressor_converter_reset(GConverter * converter)196 g_compressor_converter_reset (GConverter *converter)
197 {
198 }
199 
200 static GConverterResult
g_compressor_converter_convert(GConverter * converter,const void * inbuf,gsize inbuf_size,void * outbuf,gsize outbuf_size,GConverterFlags flags,gsize * bytes_read,gsize * bytes_written,GError ** error)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
g_compressor_converter_iface_init(GConverterIface * iface)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
test_expander(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_cmpmem (converted1, n_written, converted2, total_read);
345 
346   g_converter_reset (expander);
347 
348   mem_out = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
349   cstream_out = g_converter_output_stream_new (mem_out, expander);
350   g_assert (g_converter_output_stream_get_converter (G_CONVERTER_OUTPUT_STREAM (cstream_out)) == expander);
351   g_object_get (cstream_out, "converter", &converter, NULL);
352   g_assert (converter == expander);
353   g_object_unref (converter);
354   g_object_unref (mem_out);
355 
356   for (i = 0; i < sizeof(unexpanded_data); i++)
357     {
358       error = NULL;
359       res = g_output_stream_write (cstream_out,
360 				   unexpanded_data + i, 1,
361 				   NULL, &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 (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 (converted1);
378   g_free (converted2);
379   g_object_unref (cstream);
380   g_object_unref (cstream_out);
381   g_object_unref (expander);
382 }
383 
384 static void
test_compressor(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 (100*1000); /* Large enough */
400   cres = g_converter_convert (expander,
401 			      unexpanded_data, sizeof(unexpanded_data),
402 			      expanded, 100*1000,
403 			      G_CONVERTER_INPUT_AT_END,
404 			      &n_read, &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 (100*1000); /* Large enough */
412 
413   mem = g_memory_input_stream_new_from_data (expanded,
414 					     expanded_size,
415 					     NULL);
416   cstream = g_converter_input_stream_new (mem, compressor);
417   g_object_unref (mem);
418 
419   total_read = 0;
420   ptr = converted;
421   while (TRUE)
422     {
423       error = NULL;
424       res = g_input_stream_read (cstream,
425 				 ptr, 1,
426 				 NULL, &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 (cstream);
438 
439   g_converter_reset (compressor);
440 
441   mem_out = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
442   cstream_out = g_converter_output_stream_new (mem_out, compressor);
443   g_object_unref (mem_out);
444 
445   for (i = 0; i < expanded_size; i++)
446     {
447       error = NULL;
448       res = g_output_stream_write (cstream_out,
449 				   expanded + i, 1,
450 				   NULL, &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 (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 (cstream_out);
469 
470   g_converter_reset (compressor);
471 
472   memset (expanded, 5, 5*1000*2);
473 
474   mem = g_memory_input_stream_new_from_data (expanded,
475 					     5*1000,
476 					     NULL);
477   cstream = g_converter_input_stream_new (mem, compressor);
478   g_object_unref (mem);
479 
480   total_read = 0;
481   ptr = converted;
482   while (TRUE)
483     {
484       error = NULL;
485       res = g_input_stream_read (cstream,
486 				 ptr, 1,
487 				 NULL, &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 (cstream);
499 
500   mem = g_memory_input_stream_new_from_data (expanded,
501 					     5*1000 * 2,
502 					     NULL);
503   cstream = g_converter_input_stream_new (mem, compressor);
504   g_object_unref (mem);
505 
506   total_read = 0;
507   ptr = converted;
508   while (TRUE)
509     {
510       error = NULL;
511       res = g_input_stream_read (cstream,
512 				 ptr, 1,
513 				 NULL, &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 (cstream);
526 
527   g_converter_reset (compressor);
528 
529   mem = g_memory_input_stream_new_from_data (expanded,
530 					     5*1000 * 2 - 1,
531 					     NULL);
532   cstream = g_converter_input_stream_new (mem, compressor);
533   g_object_unref (mem);
534 
535   total_read = 0;
536   ptr = converted;
537   while (TRUE)
538     {
539       error = NULL;
540       res = g_input_stream_read (cstream,
541 				 ptr, 1,
542 				 NULL, &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 (cstream);
559 
560   g_free (expanded);
561   g_free (converted);
562   g_object_unref (expander);
563   g_object_unref (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 
G_DEFINE_TYPE_WITH_CODE(GLeftoverConverter,g_leftover_converter,G_TYPE_OBJECT,G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER,g_leftover_converter_iface_init))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
g_leftover_converter_init(GLeftoverConverter * local)605 g_leftover_converter_init (GLeftoverConverter *local)
606 {
607 }
608 
609 GConverter *
g_leftover_converter_new(void)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
g_leftover_converter_reset(GConverter * converter)620 g_leftover_converter_reset (GConverter *converter)
621 {
622 }
623 
624 static GConverterResult
g_leftover_converter_convert(GConverter * converter,const void * inbuf,gsize inbuf_size,void * outbuf,gsize outbuf_size,GConverterFlags flags,gsize * bytes_read,gsize * bytes_written,GError ** error)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 (error,
638 			   G_IO_ERROR,
639 			   G_IO_ERROR_PARTIAL_INPUT,
640 			   "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 (outbuf, inbuf, *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
g_leftover_converter_iface_init(GConverterIface * iface)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
test_converter_leftover(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 (orig, LEFTOVER_BUFSIZE, NULL);
685   cstream = g_converter_input_stream_new (mem, G_CONVERTER (converter));
686   g_object_unref (mem);
687 
688   total_read = 0;
689 
690   error = NULL;
691   res = g_input_stream_read (cstream,
692 			     converted, LEFTOVER_SHORT_READ_SIZE,
693 			     NULL, &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 (cstream,
710 				 converted + total_read,
711 				 LEFTOVER_BUFSIZE - total_read,
712 				 NULL, &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 (cstream);
722   g_free (orig);
723   g_free (converted);
724   g_object_unref (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
test_roundtrip(gconstpointer data)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 ("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   info = g_file_info_new ();
763   g_file_info_set_name (info, "foo");
764   g_object_set (compressor, "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 (info);
768   costream1 = g_converter_output_stream_new (ostream1, compressor);
769   g_assert (g_converter_output_stream_get_converter (G_CONVERTER_OUTPUT_STREAM (costream1)) == compressor);
770 
771   g_output_stream_splice (costream1, istream0, 0, NULL, &error);
772   g_assert_no_error (error);
773 
774   g_object_unref (costream1);
775 
776   g_converter_reset (compressor);
777   g_object_get (compressor, "format", &fmt, "level", &lvl, NULL);
778   g_assert_cmpint (fmt, ==, test->format);
779   g_assert_cmpint (lvl, ==, test->level);
780   g_object_unref (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 (ostream1);
785   g_object_unref (istream0);
786 
787   istream1 = g_memory_input_stream_new_from_data (data1, data1_size, g_free);
788   decompressor = G_CONVERTER (g_zlib_decompressor_new (test->format));
789   cistream1 = g_converter_input_stream_new (istream1, decompressor);
790 
791   ostream2 = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
792 
793   g_output_stream_splice (ostream2, cistream1, 0, NULL, &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 (istream1);
800   g_converter_reset (decompressor);
801   g_object_get (decompressor, "format", &fmt, NULL);
802   g_assert_cmpint (fmt, ==, test->format);
803   g_object_unref (decompressor);
804   g_object_unref (cistream1);
805   g_object_unref (ostream2);
806   g_free (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
test_charset(gconstpointer data)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 (test->charset_out, test->charset_in, NULL);
831   g_object_get (conv, "use-fallback", &fallback, NULL);
832   g_assert (!fallback);
833 
834   in = g_memory_input_stream_new_from_data (test->text_in, -1, NULL);
835   in2 = g_converter_input_stream_new (in, conv);
836 
837   count = 2 * strlen (test->text_out);
838   buffer = g_malloc0 (count);
839   error = NULL;
840   g_input_stream_read_all (in2, buffer, count, &bytes_read, NULL, &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 (buffer);
854   g_object_unref (in2);
855   g_object_unref (in);
856 
857   if (test->n_fallbacks == 0)
858     {
859        g_object_unref (conv);
860        return;
861     }
862 
863   g_converter_reset (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 (test->text_in, -1, NULL);
869   in2 = g_converter_input_stream_new (in, conv);
870 
871   count = 2 * strlen (test->text_out);
872   buffer = g_malloc0 (count);
873   error = NULL;
874   g_input_stream_read_all (in2, buffer, count, &bytes_read, NULL, &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 (buffer);
881   g_object_unref (in2);
882   g_object_unref (in);
883 
884   g_object_unref (conv);
885 }
886 
887 
888 static void
client_connected(GObject * source,GAsyncResult * result,gpointer user_data)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);
898   g_assert_no_error (error);
899 }
900 
901 static void
server_connected(GObject * source,GAsyncResult * result,gpointer user_data)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);
911   g_assert_no_error (error);
912 }
913 
914 static void
make_socketpair(GIOStream ** left,GIOStream ** right)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 (G_SOCKET_FAMILY_IPV4);
926   saddr = g_inet_socket_address_new (iaddr, 0);
927   g_object_unref (iaddr);
928 
929   listener = g_socket_listener_new ();
930   g_socket_listener_add_address (listener, saddr,
931 				 G_SOCKET_TYPE_STREAM,
932 				 G_SOCKET_PROTOCOL_TCP,
933 				 NULL,
934 				 &effective_address,
935 				 &error);
936   g_assert_no_error (error);
937   g_object_unref (saddr);
938 
939   client = g_socket_client_new ();
940 
941   g_socket_client_connect_async (client,
942 				 G_SOCKET_CONNECTABLE (effective_address),
943 				 NULL, client_connected, &client_conn);
944   g_socket_listener_accept_async (listener, NULL,
945 				  server_connected, &server_conn);
946 
947   while (!client_conn || !server_conn)
948     g_main_context_iteration (NULL, TRUE);
949 
950   g_object_unref (client);
951   g_object_unref (listener);
952   g_object_unref (effective_address);
953 
954   *left = G_IO_STREAM (client_conn);
955   *right = G_IO_STREAM (server_conn);
956 }
957 
958 static void
test_converter_pollable(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 (100*1000); /* Large enough */
979   cres = g_converter_convert (expander,
980 			      unexpanded_data, sizeof(unexpanded_data),
981 			      expanded, 100*1000,
982 			      G_CONVERTER_INPUT_AT_END,
983 			      &n_read, &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, &right);
990 
991   compressor = g_compressor_converter_new ();
992 
993   converted = g_malloc (100*1000); /* Large enough */
994 
995   cstream = g_converter_input_stream_new (g_io_stream_get_input_stream (left),
996 					  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 (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 (socket_out,
1012 				       outptr,
1013 				       MIN (1000, (expanded_end - outptr)),
1014 				       NULL, &error);
1015 	  g_assert_cmpint (res, >, 0);
1016 	  outptr += res;
1017 	}
1018       else if (socket_out)
1019 	{
1020 	  g_object_unref (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 (80L);
1029 
1030       is_readable = g_pollable_input_stream_is_readable (pollable_in);
1031       res = g_pollable_input_stream_read_nonblocking (pollable_in,
1032 						      inptr, 1,
1033 						      NULL, &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 (cstream);
1061   g_object_unref (left);
1062 
1063   g_converter_reset (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, 0, g_realloc, g_free);
1071   cstream_out = g_converter_output_stream_new (mem_out, compressor);
1072   g_object_unref (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 (pollable_out,
1081 							expanded + i, 1,
1082 							NULL, &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 (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 (cstream_out);
1101 
1102   g_free (expanded);
1103   g_free (converted);
1104   g_object_unref (expander);
1105   g_object_unref (compressor);
1106 }
1107 
1108 static void
test_truncation(gconstpointer data)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 (data0,
1125     DATA_LENGTH * sizeof (guint32), NULL);
1126 
1127   ostream1 = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
1128   compressor = G_CONVERTER (g_zlib_compressor_new (test->format, -1));
1129   costream1 = g_converter_output_stream_new (ostream1, compressor);
1130   g_assert (g_converter_output_stream_get_converter (G_CONVERTER_OUTPUT_STREAM (costream1)) == compressor);
1131 
1132   g_output_stream_splice (costream1, istream0, 0, NULL, &error);
1133   g_assert_no_error (error);
1134 
1135   g_object_unref (costream1);
1136   g_object_unref (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 (ostream1);
1142   g_object_unref (istream0);
1143 
1144   /* truncate */
1145   data1_size /= 2;
1146 
1147   istream1 = g_memory_input_stream_new_from_data (data1, data1_size, g_free);
1148   decompressor = G_CONVERTER (g_zlib_decompressor_new (test->format));
1149   cistream1 = g_converter_input_stream_new (istream1, decompressor);
1150 
1151   ostream2 = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
1152 
1153   g_output_stream_splice (ostream2, cistream1, 0, NULL, &error);
1154   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT);
1155   g_error_free (error);
1156 
1157   g_object_unref (istream1);
1158   g_object_unref (decompressor);
1159   g_object_unref (cistream1);
1160   g_object_unref (ostream2);
1161   g_free (data0);
1162 }
1163 
1164 static void
test_converter_basics(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 ("utf-8", "latin1", &error);
1173   g_assert_no_error (error);
1174   g_object_get (converter,
1175                 "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 (to);
1183   g_free (from);
1184   g_object_unref (converter);
1185 }
1186 
1187 int
main(int argc,char * argv[])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, &argv, NULL);
1213 
1214   g_test_bug_base ("http://bugzilla.gnome.org/");
1215 
1216   g_test_add_func ("/converter/basics", test_converter_basics);
1217   g_test_add_func ("/converter-input-stream/expander", test_expander);
1218   g_test_add_func ("/converter-input-stream/compressor", test_compressor);
1219 
1220   for (i = 0; i < G_N_ELEMENTS (compressor_tests); i++)
1221     g_test_add_data_func (compressor_tests[i].path, &compressor_tests[i], test_roundtrip);
1222 
1223   for (i = 0; i < G_N_ELEMENTS (truncation_tests); i++)
1224     g_test_add_data_func (truncation_tests[i].path, &truncation_tests[i], test_truncation);
1225 
1226   for (i = 0; i < G_N_ELEMENTS (charset_tests); i++)
1227     g_test_add_data_func (charset_tests[i].path, &charset_tests[i], test_charset);
1228 
1229   g_test_add_func ("/converter-stream/pollable", test_converter_pollable);
1230   g_test_add_func ("/converter-stream/leftover", test_converter_leftover);
1231 
1232   return g_test_run();
1233 }
1234