2009-10-23 19:59:03 +02:00
/* GLib testing framework examples and tests
* Copyright ( C ) 2009 Red Hat , Inc .
* Authors : Alexander Larsson < alexl @ redhat . com >
*
* This work is provided " as is " ; redistribution and modification
* in whole or in part , in any medium , physical or electronic is
* permitted without restriction .
*
* This work is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
*
* In no event shall the authors or contributors be liable for any
* direct , indirect , incidental , special , exemplary , or consequential
* damages ( including , but not limited to , procurement of substitute
* goods or services ; loss of use , data , or profits ; or business
* interruption ) however caused and on any theory of liability , whether
* in contract , strict liability , or tort ( including negligence or
* otherwise ) arising in any way out of the use of this software , even
* if advised of the possibility of such damage .
*/
# include <glib/glib.h>
# include <gio/gio.h>
# include <stdlib.h>
# include <string.h>
# define G_TYPE_EXPANDER_CONVERTER (g_expander_converter_get_type ())
# define G_EXPANDER_CONVERTER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_EXPANDER_CONVERTER, GExpanderConverter))
# define G_EXPANDER_CONVERTER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_EXPANDER_CONVERTER, GExpanderConverterClass))
# define G_IS_EXPANDER_CONVERTER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_EXPANDER_CONVERTER))
# define G_IS_EXPANDER_CONVERTER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_EXPANDER_CONVERTER))
# define G_EXPANDER_CONVERTER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_EXPANDER_CONVERTER, GExpanderConverterClass))
typedef struct _GExpanderConverter GExpanderConverter ;
typedef struct _GExpanderConverterClass GExpanderConverterClass ;
struct _GExpanderConverterClass
{
GObjectClass parent_class ;
} ;
GType g_expander_converter_get_type ( void ) G_GNUC_CONST ;
GConverter * g_expander_converter_new ( void ) ;
static void g_expander_converter_iface_init ( GConverterIface * iface ) ;
struct _GExpanderConverter
{
GObject parent_instance ;
} ;
G_DEFINE_TYPE_WITH_CODE ( GExpanderConverter , g_expander_converter , G_TYPE_OBJECT ,
G_IMPLEMENT_INTERFACE ( G_TYPE_CONVERTER ,
g_expander_converter_iface_init ) )
static void
g_expander_converter_class_init ( GExpanderConverterClass * klass )
{
}
static void
g_expander_converter_init ( GExpanderConverter * local )
{
}
GConverter *
g_expander_converter_new ( void )
{
GConverter * conv ;
conv = g_object_new ( G_TYPE_EXPANDER_CONVERTER , NULL ) ;
return conv ;
}
static void
g_expander_converter_reset ( GConverter * converter )
{
}
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 )
{
const guint8 * in , * in_end ;
guint8 v , * out ;
int i ;
gsize block_size ;
in = inbuf ;
out = outbuf ;
in_end = in + inbuf_size ;
while ( in < in_end )
{
v = * in ;
if ( v = = 0 )
block_size = 10 ;
else
block_size = v * 1000 ;
if ( outbuf_size < block_size )
{
if ( * bytes_read > 0 )
return G_CONVERTER_CONVERTED ;
g_set_error_literal ( error , G_IO_ERROR ,
G_IO_ERROR_NO_SPACE ,
" No space in dest " ) ;
return G_CONVERTER_ERROR ;
}
in + + ;
* bytes_read + = 1 ;
* bytes_written + = block_size ;
outbuf_size - = block_size ;
for ( i = 0 ; i < block_size ; i + + )
* out + + = v ;
}
if ( in = = in_end & & ( flags & G_CONVERTER_INPUT_AT_END ) )
return G_CONVERTER_FINISHED ;
return G_CONVERTER_CONVERTED ;
}
static void
g_expander_converter_iface_init ( GConverterIface * iface )
{
iface - > convert = g_expander_converter_convert ;
iface - > reset = g_expander_converter_reset ;
}
# define G_TYPE_COMPRESSOR_CONVERTER (g_compressor_converter_get_type ())
# define G_COMPRESSOR_CONVERTER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_COMPRESSOR_CONVERTER, GCompressorConverter))
# define G_COMPRESSOR_CONVERTER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_COMPRESSOR_CONVERTER, GCompressorConverterClass))
# define G_IS_COMPRESSOR_CONVERTER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_COMPRESSOR_CONVERTER))
# define G_IS_COMPRESSOR_CONVERTER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_COMPRESSOR_CONVERTER))
# define G_COMPRESSOR_CONVERTER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_COMPRESSOR_CONVERTER, GCompressorConverterClass))
typedef struct _GCompressorConverter GCompressorConverter ;
typedef struct _GCompressorConverterClass GCompressorConverterClass ;
struct _GCompressorConverterClass
{
GObjectClass parent_class ;
} ;
GType g_compressor_converter_get_type ( void ) G_GNUC_CONST ;
GConverter * g_compressor_converter_new ( void ) ;
static void g_compressor_converter_iface_init ( GConverterIface * iface ) ;
struct _GCompressorConverter
{
GObject parent_instance ;
} ;
G_DEFINE_TYPE_WITH_CODE ( GCompressorConverter , g_compressor_converter , G_TYPE_OBJECT ,
G_IMPLEMENT_INTERFACE ( G_TYPE_CONVERTER ,
g_compressor_converter_iface_init ) )
static void
g_compressor_converter_class_init ( GCompressorConverterClass * klass )
{
}
static void
g_compressor_converter_init ( GCompressorConverter * local )
{
}
GConverter *
g_compressor_converter_new ( void )
{
GConverter * conv ;
conv = g_object_new ( G_TYPE_COMPRESSOR_CONVERTER , NULL ) ;
return conv ;
}
static void
g_compressor_converter_reset ( GConverter * converter )
{
}
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 )
{
const guint8 * in , * in_end ;
guint8 v , * out ;
int i ;
gsize block_size ;
in = inbuf ;
out = outbuf ;
in_end = in + inbuf_size ;
while ( in < in_end )
{
v = * in ;
if ( v = = 0 )
{
block_size = 0 ;
while ( in + block_size < in_end & & * ( in + block_size ) = = 0 )
block_size + + ;
}
else
block_size = v * 1000 ;
/* Not enough data */
if ( in_end - in < block_size )
{
if ( * bytes_read > 0 )
break ;
g_set_error_literal ( error , G_IO_ERROR ,
G_IO_ERROR_PARTIAL_INPUT ,
" Need more data " ) ;
return G_CONVERTER_ERROR ;
}
for ( i = 0 ; i < block_size ; i + + )
{
if ( * ( in + i ) ! = v )
{
if ( * bytes_read > 0 )
break ;
g_set_error_literal ( error , G_IO_ERROR ,
G_IO_ERROR_INVALID_DATA ,
" invalid data " ) ;
return G_CONVERTER_ERROR ;
}
}
if ( v = = 0 & & in_end - in = = block_size & & ( flags & G_CONVERTER_INPUT_AT_END ) = = 0 )
{
if ( * bytes_read > 0 )
break ;
g_set_error_literal ( error , G_IO_ERROR ,
G_IO_ERROR_PARTIAL_INPUT ,
" Need more data " ) ;
return G_CONVERTER_ERROR ;
}
in + = block_size ;
* out + + = v ;
* bytes_read + = block_size ;
* bytes_written + = 1 ;
}
if ( in = = in_end & & ( flags & G_CONVERTER_INPUT_AT_END ) )
return G_CONVERTER_FINISHED ;
return G_CONVERTER_CONVERTED ;
}
static void
g_compressor_converter_iface_init ( GConverterIface * iface )
{
iface - > convert = g_compressor_converter_convert ;
iface - > reset = g_compressor_converter_reset ;
}
guint8 unexpanded_data [ ] = { 0 , 1 , 3 , 4 , 5 , 6 , 7 , 3 , 12 , 0 , 0 } ;
static void
test_expander ( void )
{
guint8 * converted1 , * converted2 , * ptr ;
gsize n_read , n_written ;
gsize total_read ;
gssize res ;
GConverterResult cres ;
2009-11-29 15:14:10 +01:00
GInputStream * mem , * cstream ;
GOutputStream * mem_out , * cstream_out ;
2009-10-23 19:59:03 +02:00
GConverter * expander ;
2010-07-29 06:54:23 +02:00
GConverter * converter ;
2009-10-23 19:59:03 +02:00
GError * error ;
int i ;
expander = g_expander_converter_new ( ) ;
converted1 = g_malloc ( 100 * 1000 ) ; /* Large enough */
converted2 = g_malloc ( 100 * 1000 ) ; /* Large enough */
cres = g_converter_convert ( expander ,
unexpanded_data , sizeof ( unexpanded_data ) ,
converted1 , 100 * 1000 ,
G_CONVERTER_INPUT_AT_END ,
& n_read , & n_written , NULL ) ;
g_assert ( cres = = G_CONVERTER_FINISHED ) ;
g_assert ( n_read = = 11 ) ;
g_assert ( n_written = = 41030 ) ;
g_converter_reset ( expander ) ;
mem = g_memory_input_stream_new_from_data ( unexpanded_data ,
sizeof ( unexpanded_data ) ,
NULL ) ;
cstream = g_converter_input_stream_new ( mem , expander ) ;
2010-07-06 01:33:05 +02:00
g_assert ( g_converter_input_stream_get_converter ( G_CONVERTER_INPUT_STREAM ( cstream ) ) = = expander ) ;
2010-07-29 06:54:23 +02:00
g_object_get ( cstream , " converter " , & converter , NULL ) ;
g_assert ( converter = = expander ) ;
g_object_unref ( converter ) ;
2009-10-23 19:59:03 +02:00
g_object_unref ( mem ) ;
total_read = 0 ;
ptr = converted2 ;
while ( TRUE )
{
error = NULL ;
2009-11-29 15:14:10 +01:00
res = g_input_stream_read ( cstream ,
2009-10-23 19:59:03 +02:00
ptr , 1 ,
NULL , & error ) ;
g_assert ( res ! = - 1 ) ;
if ( res = = 0 )
break ;
ptr + = res ;
total_read + = res ;
}
g_assert ( total_read = = n_written ) ;
g_assert ( memcmp ( converted1 , converted2 , n_written ) = = 0 ) ;
g_converter_reset ( expander ) ;
mem_out = g_memory_output_stream_new ( NULL , 0 , g_realloc , g_free ) ;
cstream_out = g_converter_output_stream_new ( mem_out , expander ) ;
2010-07-29 08:20:15 +02:00
g_assert ( g_converter_output_stream_get_converter ( G_CONVERTER_OUTPUT_STREAM ( cstream_out ) ) = = expander ) ;
g_object_get ( cstream_out , " converter " , & converter , NULL ) ;
g_assert ( converter = = expander ) ;
g_object_unref ( converter ) ;
2009-10-23 19:59:03 +02:00
g_object_unref ( mem_out ) ;
for ( i = 0 ; i < sizeof ( unexpanded_data ) ; i + + )
{
error = NULL ;
2009-11-29 15:14:10 +01:00
res = g_output_stream_write ( cstream_out ,
2009-10-23 19:59:03 +02:00
unexpanded_data + i , 1 ,
NULL , & error ) ;
g_assert ( res ! = - 1 ) ;
if ( res = = 0 )
{
g_assert ( i = = sizeof ( unexpanded_data ) - 1 ) ;
break ;
}
g_assert ( res = = 1 ) ;
}
2009-11-29 15:14:10 +01:00
g_output_stream_close ( cstream_out , NULL , NULL ) ;
2009-10-23 19:59:03 +02:00
g_assert ( g_memory_output_stream_get_data_size ( G_MEMORY_OUTPUT_STREAM ( mem_out ) ) = = n_written ) ;
g_assert ( memcmp ( g_memory_output_stream_get_data ( G_MEMORY_OUTPUT_STREAM ( mem_out ) ) ,
converted1 ,
n_written ) = = 0 ) ;
g_free ( converted1 ) ;
g_free ( converted2 ) ;
g_object_unref ( cstream ) ;
g_object_unref ( cstream_out ) ;
g_object_unref ( expander ) ;
}
static void
test_compressor ( void )
{
guint8 * converted , * expanded , * ptr ;
gsize n_read , expanded_size ;
gsize total_read ;
gssize res ;
GConverterResult cres ;
2009-11-29 15:14:10 +01:00
GInputStream * mem , * cstream ;
GOutputStream * mem_out , * cstream_out ;
2009-10-23 19:59:03 +02:00
GConverter * expander , * compressor ;
GError * error ;
int i ;
expander = g_expander_converter_new ( ) ;
expanded = g_malloc ( 100 * 1000 ) ; /* Large enough */
cres = g_converter_convert ( expander ,
unexpanded_data , sizeof ( unexpanded_data ) ,
expanded , 100 * 1000 ,
G_CONVERTER_INPUT_AT_END ,
& n_read , & expanded_size , NULL ) ;
g_assert ( cres = = G_CONVERTER_FINISHED ) ;
g_assert ( n_read = = 11 ) ;
g_assert ( expanded_size = = 41030 ) ;
compressor = g_compressor_converter_new ( ) ;
converted = g_malloc ( 100 * 1000 ) ; /* Large enough */
mem = g_memory_input_stream_new_from_data ( expanded ,
expanded_size ,
NULL ) ;
cstream = g_converter_input_stream_new ( mem , compressor ) ;
g_object_unref ( mem ) ;
total_read = 0 ;
ptr = converted ;
while ( TRUE )
{
error = NULL ;
2009-11-29 15:14:10 +01:00
res = g_input_stream_read ( cstream ,
2009-10-23 19:59:03 +02:00
ptr , 1 ,
NULL , & error ) ;
g_assert ( res ! = - 1 ) ;
if ( res = = 0 )
break ;
ptr + = res ;
total_read + = res ;
}
g_assert ( total_read = = n_read - 1 ) ; /* Last 2 zeros are combined */
g_assert ( memcmp ( converted , unexpanded_data , total_read ) = = 0 ) ;
g_object_unref ( cstream ) ;
g_converter_reset ( compressor ) ;
mem_out = g_memory_output_stream_new ( NULL , 0 , g_realloc , g_free ) ;
cstream_out = g_converter_output_stream_new ( mem_out , compressor ) ;
g_object_unref ( mem_out ) ;
for ( i = 0 ; i < expanded_size ; i + + )
{
error = NULL ;
2009-11-29 15:14:10 +01:00
res = g_output_stream_write ( cstream_out ,
2009-10-23 19:59:03 +02:00
expanded + i , 1 ,
NULL , & error ) ;
g_assert ( res ! = - 1 ) ;
if ( res = = 0 )
{
g_assert ( i = = expanded_size - 1 ) ;
break ;
}
g_assert ( res = = 1 ) ;
}
2009-11-29 15:14:10 +01:00
g_output_stream_close ( cstream_out , NULL , NULL ) ;
2009-10-23 19:59:03 +02:00
g_assert ( g_memory_output_stream_get_data_size ( G_MEMORY_OUTPUT_STREAM ( mem_out ) ) = = n_read - 1 ) ; /* Last 2 zeros are combined */
g_assert ( memcmp ( g_memory_output_stream_get_data ( G_MEMORY_OUTPUT_STREAM ( mem_out ) ) ,
unexpanded_data ,
g_memory_output_stream_get_data_size ( G_MEMORY_OUTPUT_STREAM ( mem_out ) ) ) = = 0 ) ;
g_object_unref ( cstream_out ) ;
g_converter_reset ( compressor ) ;
memset ( expanded , 5 , 5 * 1000 * 2 ) ;
mem = g_memory_input_stream_new_from_data ( expanded ,
5 * 1000 ,
NULL ) ;
cstream = g_converter_input_stream_new ( mem , compressor ) ;
g_object_unref ( mem ) ;
total_read = 0 ;
ptr = converted ;
while ( TRUE )
{
error = NULL ;
2009-11-29 15:14:10 +01:00
res = g_input_stream_read ( cstream ,
2009-10-23 19:59:03 +02:00
ptr , 1 ,
NULL , & error ) ;
g_assert ( res ! = - 1 ) ;
if ( res = = 0 )
break ;
ptr + = res ;
total_read + = res ;
}
g_assert ( total_read = = 1 ) ;
g_assert ( * converted = = 5 ) ;
2010-09-03 21:39:58 +02:00
g_object_unref ( cstream ) ;
2009-10-23 19:59:03 +02:00
mem = g_memory_input_stream_new_from_data ( expanded ,
5 * 1000 * 2 ,
NULL ) ;
cstream = g_converter_input_stream_new ( mem , compressor ) ;
g_object_unref ( mem ) ;
total_read = 0 ;
ptr = converted ;
while ( TRUE )
{
error = NULL ;
2009-11-29 15:14:10 +01:00
res = g_input_stream_read ( cstream ,
2009-10-23 19:59:03 +02:00
ptr , 1 ,
NULL , & error ) ;
g_assert ( res ! = - 1 ) ;
if ( res = = 0 )
break ;
ptr + = res ;
total_read + = res ;
}
g_assert ( total_read = = 2 ) ;
g_assert ( converted [ 0 ] = = 5 ) ;
g_assert ( converted [ 1 ] = = 5 ) ;
g_object_unref ( cstream ) ;
g_converter_reset ( compressor ) ;
mem = g_memory_input_stream_new_from_data ( expanded ,
5 * 1000 * 2 - 1 ,
NULL ) ;
cstream = g_converter_input_stream_new ( mem , compressor ) ;
g_object_unref ( mem ) ;
total_read = 0 ;
ptr = converted ;
while ( TRUE )
{
error = NULL ;
2009-11-29 15:14:10 +01:00
res = g_input_stream_read ( cstream ,
2009-10-23 19:59:03 +02:00
ptr , 1 ,
NULL , & error ) ;
if ( res = = - 1 )
{
g_assert_error ( error , G_IO_ERROR , G_IO_ERROR_PARTIAL_INPUT ) ;
2010-09-03 21:37:56 +02:00
g_error_free ( error ) ;
2009-10-23 19:59:03 +02:00
break ;
}
g_assert ( res ! = 0 ) ;
ptr + = res ;
total_read + = res ;
}
g_assert ( total_read = = 1 ) ;
g_assert ( converted [ 0 ] = = 5 ) ;
g_object_unref ( cstream ) ;
g_free ( expanded ) ;
g_free ( converted ) ;
g_object_unref ( expander ) ;
g_object_unref ( compressor ) ;
}
2012-05-30 14:30:27 +02:00
# define LEFTOVER_SHORT_READ_SIZE 512
# define G_TYPE_LEFTOVER_CONVERTER (g_leftover_converter_get_type ())
# define G_LEFTOVER_CONVERTER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_LEFTOVER_CONVERTER, GLeftoverConverter))
# define G_LEFTOVER_CONVERTER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_LEFTOVER_CONVERTER, GLeftoverConverterClass))
# define G_IS_LEFTOVER_CONVERTER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_LEFTOVER_CONVERTER))
# define G_IS_LEFTOVER_CONVERTER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_LEFTOVER_CONVERTER))
# define G_LEFTOVER_CONVERTER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_LEFTOVER_CONVERTER, GLeftoverConverterClass))
typedef struct _GLeftoverConverter GLeftoverConverter ;
typedef struct _GLeftoverConverterClass GLeftoverConverterClass ;
struct _GLeftoverConverterClass
{
GObjectClass parent_class ;
} ;
GType g_leftover_converter_get_type ( void ) G_GNUC_CONST ;
GConverter * g_leftover_converter_new ( void ) ;
static void g_leftover_converter_iface_init ( GConverterIface * iface ) ;
struct _GLeftoverConverter
{
GObject parent_instance ;
} ;
G_DEFINE_TYPE_WITH_CODE ( GLeftoverConverter , g_leftover_converter , G_TYPE_OBJECT ,
G_IMPLEMENT_INTERFACE ( G_TYPE_CONVERTER ,
g_leftover_converter_iface_init ) )
static void
g_leftover_converter_class_init ( GLeftoverConverterClass * klass )
{
}
static void
g_leftover_converter_init ( GLeftoverConverter * local )
{
}
GConverter *
g_leftover_converter_new ( void )
{
GConverter * conv ;
conv = g_object_new ( G_TYPE_LEFTOVER_CONVERTER , NULL ) ;
return conv ;
}
static void
g_leftover_converter_reset ( GConverter * converter )
{
}
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 )
{
if ( outbuf_size = = LEFTOVER_SHORT_READ_SIZE )
{
g_set_error_literal ( error ,
G_IO_ERROR ,
G_IO_ERROR_PARTIAL_INPUT ,
" partial input " ) ;
return G_CONVERTER_ERROR ;
}
if ( inbuf_size < 100 )
* bytes_read = * bytes_written = MIN ( inbuf_size , outbuf_size ) ;
else
* bytes_read = * bytes_written = MIN ( inbuf_size - 10 , outbuf_size ) ;
memcpy ( outbuf , inbuf , * bytes_written ) ;
if ( * bytes_read = = inbuf_size & & ( flags & G_CONVERTER_INPUT_AT_END ) )
return G_CONVERTER_FINISHED ;
return G_CONVERTER_CONVERTED ;
}
static void
g_leftover_converter_iface_init ( GConverterIface * iface )
{
iface - > convert = g_leftover_converter_convert ;
iface - > reset = g_leftover_converter_reset ;
}
# define LEFTOVER_BUFSIZE 8192
# define INTERNAL_BUFSIZE 4096
static void
test_converter_leftover ( void )
{
gchar * orig , * converted ;
gsize total_read ;
gssize res ;
goffset offset ;
GInputStream * mem , * cstream ;
GConverter * converter ;
GError * error ;
int i ;
converter = g_leftover_converter_new ( ) ;
orig = g_malloc ( LEFTOVER_BUFSIZE ) ;
converted = g_malloc ( LEFTOVER_BUFSIZE ) ;
for ( i = 0 ; i < LEFTOVER_BUFSIZE ; i + + )
orig [ i ] = i % 64 + 32 ;
mem = g_memory_input_stream_new_from_data ( orig , LEFTOVER_BUFSIZE , NULL ) ;
cstream = g_converter_input_stream_new ( mem , G_CONVERTER ( converter ) ) ;
g_object_unref ( mem ) ;
total_read = 0 ;
error = NULL ;
res = g_input_stream_read ( cstream ,
converted , LEFTOVER_SHORT_READ_SIZE ,
NULL , & error ) ;
g_assert_cmpint ( res , = = , LEFTOVER_SHORT_READ_SIZE ) ;
total_read + = res ;
offset = g_seekable_tell ( G_SEEKABLE ( mem ) ) ;
g_assert_cmpint ( offset , > , LEFTOVER_SHORT_READ_SIZE ) ;
g_assert_cmpint ( offset , < , LEFTOVER_BUFSIZE ) ;
/* At this point, @cstream has both a non-empty input_buffer
* and a non - empty converted_buffer , which is the case
* we want to test .
*/
while ( TRUE )
{
error = NULL ;
res = g_input_stream_read ( cstream ,
converted + total_read ,
LEFTOVER_BUFSIZE - total_read ,
NULL , & error ) ;
g_assert ( res > = 0 ) ;
if ( res = = 0 )
break ;
total_read + = res ;
}
g_assert_cmpint ( total_read , = = , LEFTOVER_BUFSIZE ) ;
g_assert ( memcmp ( converted , orig , LEFTOVER_BUFSIZE ) = = 0 ) ;
g_object_unref ( cstream ) ;
g_free ( orig ) ;
g_free ( converted ) ;
g_object_unref ( converter ) ;
}
2010-06-11 09:46:47 +02:00
# define DATA_LENGTH 1000000
2012-07-17 22:21:03 +02:00
typedef struct {
const gchar * path ;
GZlibCompressorFormat format ;
gint level ;
} CompressorTest ;
2010-06-11 09:46:47 +02:00
static void
2012-07-17 22:21:03 +02:00
test_roundtrip ( gconstpointer data )
2010-06-11 09:46:47 +02:00
{
2012-07-17 22:21:03 +02:00
const CompressorTest * test = data ;
2010-06-11 09:46:47 +02:00
GError * error = NULL ;
guint32 * data0 , * data1 ;
gsize data1_size ;
gint i ;
GInputStream * istream0 , * istream1 , * cistream1 ;
GOutputStream * ostream1 , * ostream2 , * costream1 ;
GConverter * compressor , * decompressor ;
2010-07-27 20:01:48 +02:00
GZlibCompressorFormat fmt ;
gint lvl ;
2010-06-11 09:46:47 +02:00
2012-07-17 22:21:03 +02:00
g_test_bug ( " 619945 " ) ;
2010-06-11 09:46:47 +02:00
data0 = g_malloc ( DATA_LENGTH * sizeof ( guint32 ) ) ;
for ( i = 0 ; i < DATA_LENGTH ; i + + )
data0 [ i ] = g_random_int ( ) ;
istream0 = g_memory_input_stream_new_from_data ( data0 ,
DATA_LENGTH * sizeof ( guint32 ) , NULL ) ;
2010-09-03 21:43:03 +02:00
ostream1 = g_memory_output_stream_new ( NULL , 0 , g_realloc , g_free ) ;
2012-07-17 22:21:03 +02:00
compressor = G_CONVERTER ( g_zlib_compressor_new ( test - > format , test - > level ) ) ;
2010-06-11 09:46:47 +02:00
costream1 = g_converter_output_stream_new ( ostream1 , compressor ) ;
2010-07-06 01:33:05 +02:00
g_assert ( g_converter_output_stream_get_converter ( G_CONVERTER_OUTPUT_STREAM ( costream1 ) ) = = compressor ) ;
2010-06-11 09:46:47 +02:00
g_output_stream_splice ( costream1 , istream0 , 0 , NULL , & error ) ;
g_assert_no_error ( error ) ;
g_object_unref ( costream1 ) ;
2010-07-27 20:01:48 +02:00
g_converter_reset ( compressor ) ;
g_object_get ( compressor , " format " , & fmt , " level " , & lvl , NULL ) ;
2012-07-17 22:21:03 +02:00
g_assert_cmpint ( fmt , = = , test - > format ) ;
g_assert_cmpint ( lvl , = = , test - > level ) ;
2010-06-11 09:46:47 +02:00
g_object_unref ( compressor ) ;
2010-09-03 21:43:03 +02:00
data1 = g_memory_output_stream_steal_data ( G_MEMORY_OUTPUT_STREAM ( ostream1 ) ) ;
2010-06-11 09:46:47 +02:00
data1_size = g_memory_output_stream_get_data_size (
G_MEMORY_OUTPUT_STREAM ( ostream1 ) ) ;
g_object_unref ( ostream1 ) ;
g_object_unref ( istream0 ) ;
2010-09-03 21:43:03 +02:00
istream1 = g_memory_input_stream_new_from_data ( data1 , data1_size , g_free ) ;
2012-07-17 22:21:03 +02:00
decompressor = G_CONVERTER ( g_zlib_decompressor_new ( test - > format ) ) ;
2010-06-11 09:46:47 +02:00
cistream1 = g_converter_input_stream_new ( istream1 , decompressor ) ;
2010-09-03 21:43:03 +02:00
ostream2 = g_memory_output_stream_new ( NULL , 0 , g_realloc , g_free ) ;
2010-06-11 09:46:47 +02:00
g_output_stream_splice ( ostream2 , cistream1 , 0 , NULL , & error ) ;
g_assert_no_error ( error ) ;
g_assert_cmpuint ( DATA_LENGTH * sizeof ( guint32 ) , = = ,
g_memory_output_stream_get_data_size ( G_MEMORY_OUTPUT_STREAM ( ostream2 ) ) ) ;
g_assert ( memcmp ( data0 , g_memory_output_stream_get_data (
G_MEMORY_OUTPUT_STREAM ( ostream2 ) ) , DATA_LENGTH * sizeof ( guint32 ) ) = = 0 ) ;
2010-07-27 03:16:03 +02:00
g_object_unref ( istream1 ) ;
2010-07-27 20:01:48 +02:00
g_converter_reset ( decompressor ) ;
g_object_get ( decompressor , " format " , & fmt , NULL ) ;
2012-07-17 22:21:03 +02:00
g_assert_cmpint ( fmt , = = , test - > format ) ;
2010-07-27 03:16:03 +02:00
g_object_unref ( decompressor ) ;
g_object_unref ( cistream1 ) ;
g_object_unref ( ostream2 ) ;
2010-09-03 21:43:03 +02:00
g_free ( data0 ) ;
2010-06-11 09:46:47 +02:00
}
2010-07-05 02:49:29 +02:00
typedef struct {
const gchar * path ;
const gchar * charset_in ;
const gchar * text_in ;
const gchar * charset_out ;
const gchar * text_out ;
2010-07-06 01:33:05 +02:00
gint n_fallbacks ;
2010-07-05 02:49:29 +02:00
} CharsetTest ;
static void
test_charset ( gconstpointer data )
{
const CharsetTest * test = data ;
GInputStream * in , * in2 ;
GConverter * conv ;
gchar * buffer ;
gsize count ;
gsize bytes_read ;
GError * error ;
2010-07-06 01:33:05 +02:00
gboolean fallback ;
2010-07-05 02:49:29 +02:00
conv = ( GConverter * ) g_charset_converter_new ( test - > charset_out , test - > charset_in , NULL ) ;
2010-07-06 01:33:05 +02:00
g_object_get ( conv , " use-fallback " , & fallback , NULL ) ;
g_assert ( ! fallback ) ;
in = g_memory_input_stream_new_from_data ( test - > text_in , - 1 , NULL ) ;
2010-07-05 02:49:29 +02:00
in2 = g_converter_input_stream_new ( in , conv ) ;
2010-07-06 01:33:05 +02:00
count = 2 * strlen ( test - > text_out ) ;
2010-07-07 07:00:58 +02:00
buffer = g_malloc0 ( count ) ;
2010-07-06 01:33:05 +02:00
error = NULL ;
g_input_stream_read_all ( in2 , buffer , count , & bytes_read , NULL , & error ) ;
if ( test - > n_fallbacks = = 0 )
{
g_assert_no_error ( error ) ;
g_assert_cmpint ( bytes_read , = = , strlen ( test - > text_out ) ) ;
g_assert_cmpstr ( buffer , = = , test - > text_out ) ;
}
else
2010-09-03 21:39:07 +02:00
{
g_assert_error ( error , G_IO_ERROR , G_IO_ERROR_INVALID_DATA ) ;
g_error_free ( error ) ;
}
2010-07-06 01:33:05 +02:00
g_free ( buffer ) ;
g_object_unref ( in2 ) ;
2010-07-05 02:49:29 +02:00
g_object_unref ( in ) ;
2010-07-06 01:33:05 +02:00
if ( test - > n_fallbacks = = 0 )
2010-09-03 21:40:55 +02:00
{
g_object_unref ( conv ) ;
return ;
}
2010-07-06 01:33:05 +02:00
g_converter_reset ( conv ) ;
g_assert ( ! g_charset_converter_get_use_fallback ( G_CHARSET_CONVERTER ( conv ) ) ) ;
g_charset_converter_set_use_fallback ( G_CHARSET_CONVERTER ( conv ) , TRUE ) ;
in = g_memory_input_stream_new_from_data ( test - > text_in , - 1 , NULL ) ;
in2 = g_converter_input_stream_new ( in , conv ) ;
2010-07-05 02:49:29 +02:00
count = 2 * strlen ( test - > text_out ) ;
2010-07-07 07:00:58 +02:00
buffer = g_malloc0 ( count ) ;
2010-07-05 02:49:29 +02:00
error = NULL ;
g_input_stream_read_all ( in2 , buffer , count , & bytes_read , NULL , & error ) ;
g_assert_no_error ( error ) ;
g_assert_cmpstr ( buffer , = = , test - > text_out ) ;
2010-07-06 01:33:05 +02:00
g_assert_cmpint ( bytes_read , = = , strlen ( test - > text_out ) ) ;
g_assert_cmpint ( test - > n_fallbacks , = = , g_charset_converter_get_num_fallbacks ( G_CHARSET_CONVERTER ( conv ) ) ) ;
2010-07-05 02:49:29 +02:00
g_free ( buffer ) ;
g_object_unref ( in2 ) ;
2010-07-06 01:33:05 +02:00
g_object_unref ( in ) ;
g_object_unref ( conv ) ;
2010-07-05 02:49:29 +02:00
}
2012-02-06 21:08:08 +01:00
static void
client_connected ( GObject * source ,
GAsyncResult * result ,
gpointer user_data )
{
GSocketClient * client = G_SOCKET_CLIENT ( source ) ;
GSocketConnection * * conn = user_data ;
GError * error = NULL ;
* conn = g_socket_client_connect_finish ( client , result , & error ) ;
g_assert_no_error ( error ) ;
}
static void
server_connected ( GObject * source ,
GAsyncResult * result ,
gpointer user_data )
{
GSocketListener * listener = G_SOCKET_LISTENER ( source ) ;
GSocketConnection * * conn = user_data ;
GError * error = NULL ;
* conn = g_socket_listener_accept_finish ( listener , result , NULL , & error ) ;
g_assert_no_error ( error ) ;
}
static void
make_socketpair ( GIOStream * * left ,
GIOStream * * right )
{
GInetAddress * iaddr ;
GSocketAddress * saddr , * effective_address ;
GSocketListener * listener ;
GSocketClient * client ;
GError * error = NULL ;
GSocketConnection * client_conn = NULL , * server_conn = NULL ;
iaddr = g_inet_address_new_loopback ( G_SOCKET_FAMILY_IPV4 ) ;
saddr = g_inet_socket_address_new ( iaddr , 0 ) ;
g_object_unref ( iaddr ) ;
listener = g_socket_listener_new ( ) ;
g_socket_listener_add_address ( listener , saddr ,
G_SOCKET_TYPE_STREAM ,
G_SOCKET_PROTOCOL_TCP ,
NULL ,
& effective_address ,
& error ) ;
g_assert_no_error ( error ) ;
g_object_unref ( saddr ) ;
client = g_socket_client_new ( ) ;
g_socket_client_connect_async ( client ,
G_SOCKET_CONNECTABLE ( effective_address ) ,
NULL , client_connected , & client_conn ) ;
g_socket_listener_accept_async ( listener , NULL ,
server_connected , & server_conn ) ;
while ( ! client_conn | | ! server_conn )
g_main_context_iteration ( NULL , TRUE ) ;
g_object_unref ( client ) ;
g_object_unref ( listener ) ;
g_object_unref ( effective_address ) ;
* left = G_IO_STREAM ( client_conn ) ;
* right = G_IO_STREAM ( server_conn ) ;
}
static void
test_converter_pollable ( void )
{
GIOStream * left , * right ;
guint8 * converted , * inptr ;
guint8 * expanded , * outptr , * expanded_end ;
gsize n_read , expanded_size ;
gsize total_read ;
gssize res ;
gboolean is_readable ;
GConverterResult cres ;
GInputStream * cstream ;
GPollableInputStream * pollable_in ;
GOutputStream * socket_out , * mem_out , * cstream_out ;
GPollableOutputStream * pollable_out ;
GConverter * expander , * compressor ;
GError * error ;
int i ;
expander = g_expander_converter_new ( ) ;
expanded = g_malloc ( 100 * 1000 ) ; /* Large enough */
cres = g_converter_convert ( expander ,
unexpanded_data , sizeof ( unexpanded_data ) ,
expanded , 100 * 1000 ,
G_CONVERTER_INPUT_AT_END ,
& n_read , & expanded_size , NULL ) ;
g_assert ( cres = = G_CONVERTER_FINISHED ) ;
g_assert ( n_read = = 11 ) ;
g_assert ( expanded_size = = 41030 ) ;
expanded_end = expanded + expanded_size ;
make_socketpair ( & left , & right ) ;
compressor = g_compressor_converter_new ( ) ;
converted = g_malloc ( 100 * 1000 ) ; /* Large enough */
cstream = g_converter_input_stream_new ( g_io_stream_get_input_stream ( left ) ,
compressor ) ;
pollable_in = G_POLLABLE_INPUT_STREAM ( cstream ) ;
g_assert ( g_pollable_input_stream_can_poll ( pollable_in ) ) ;
socket_out = g_io_stream_get_output_stream ( right ) ;
total_read = 0 ;
outptr = expanded ;
inptr = converted ;
while ( TRUE )
{
error = NULL ;
if ( outptr < expanded_end )
{
res = g_output_stream_write ( socket_out ,
outptr ,
MIN ( 1000 , ( expanded_end - outptr ) ) ,
NULL , & error ) ;
g_assert_cmpint ( res , > , 0 ) ;
outptr + = res ;
}
else if ( socket_out )
{
g_object_unref ( right ) ;
socket_out = NULL ;
}
2012-11-09 18:22:19 +01:00
/* Wait a few ticks to check for the pipe to propagate the
* write . Finesses the race condition in the following test ,
* where is_readable fails because the write hasn ' t propagated ,
* but the read then succeeds because it has . */
g_usleep ( 80L ) ;
2012-02-06 21:08:08 +01:00
is_readable = g_pollable_input_stream_is_readable ( pollable_in ) ;
res = g_pollable_input_stream_read_nonblocking ( pollable_in ,
inptr , 1 ,
NULL , & error ) ;
/* is_readable can be a false positive, but not a false negative */
if ( ! is_readable )
g_assert_cmpint ( res , = = , - 1 ) ;
/* After closing the write end, we can't get WOULD_BLOCK any more */
if ( ! socket_out )
g_assert_cmpint ( res , ! = , - 1 ) ;
if ( res = = - 1 )
{
g_assert_error ( error , G_IO_ERROR , G_IO_ERROR_WOULD_BLOCK ) ;
g_error_free ( error ) ;
continue ;
}
if ( res = = 0 )
break ;
inptr + = res ;
total_read + = res ;
}
g_assert ( total_read = = n_read - 1 ) ; /* Last 2 zeros are combined */
g_assert ( memcmp ( converted , unexpanded_data , total_read ) = = 0 ) ;
g_object_unref ( cstream ) ;
g_object_unref ( left ) ;
g_converter_reset ( compressor ) ;
/* This doesn't actually test the behavior on
* G_IO_ERROR_WOULD_BLOCK ; to do that we ' d need to implement a
* custom GOutputStream that we could control blocking on .
*/
mem_out = g_memory_output_stream_new ( NULL , 0 , g_realloc , g_free ) ;
cstream_out = g_converter_output_stream_new ( mem_out , compressor ) ;
g_object_unref ( mem_out ) ;
pollable_out = G_POLLABLE_OUTPUT_STREAM ( cstream_out ) ;
for ( i = 0 ; i < expanded_size ; i + + )
{
error = NULL ;
res = g_pollable_output_stream_write_nonblocking ( pollable_out ,
expanded + i , 1 ,
NULL , & error ) ;
g_assert ( res ! = - 1 ) ;
if ( res = = 0 )
{
g_assert ( i = = expanded_size - 1 ) ;
break ;
}
g_assert ( res = = 1 ) ;
}
g_output_stream_close ( cstream_out , NULL , NULL ) ;
g_assert ( g_memory_output_stream_get_data_size ( G_MEMORY_OUTPUT_STREAM ( mem_out ) ) = = n_read - 1 ) ; /* Last 2 zeros are combined */
g_assert ( memcmp ( g_memory_output_stream_get_data ( G_MEMORY_OUTPUT_STREAM ( mem_out ) ) ,
unexpanded_data ,
g_memory_output_stream_get_data_size ( G_MEMORY_OUTPUT_STREAM ( mem_out ) ) ) = = 0 ) ;
g_object_unref ( cstream_out ) ;
g_free ( expanded ) ;
g_free ( converted ) ;
g_object_unref ( expander ) ;
g_object_unref ( compressor ) ;
}
2012-07-17 22:21:03 +02:00
static void
test_truncation ( gconstpointer data )
{
const CompressorTest * test = data ;
GError * error = NULL ;
guint32 * data0 , * data1 ;
gsize data1_size ;
gint i ;
GInputStream * istream0 , * istream1 , * cistream1 ;
GOutputStream * ostream1 , * ostream2 , * costream1 ;
GConverter * compressor , * decompressor ;
data0 = g_malloc ( DATA_LENGTH * sizeof ( guint32 ) ) ;
for ( i = 0 ; i < DATA_LENGTH ; i + + )
data0 [ i ] = g_random_int ( ) ;
istream0 = g_memory_input_stream_new_from_data ( data0 ,
DATA_LENGTH * sizeof ( guint32 ) , NULL ) ;
ostream1 = g_memory_output_stream_new ( NULL , 0 , g_realloc , g_free ) ;
compressor = G_CONVERTER ( g_zlib_compressor_new ( test - > format , - 1 ) ) ;
costream1 = g_converter_output_stream_new ( ostream1 , compressor ) ;
g_assert ( g_converter_output_stream_get_converter ( G_CONVERTER_OUTPUT_STREAM ( costream1 ) ) = = compressor ) ;
g_output_stream_splice ( costream1 , istream0 , 0 , NULL , & error ) ;
g_assert_no_error ( error ) ;
g_object_unref ( costream1 ) ;
g_object_unref ( compressor ) ;
data1 = g_memory_output_stream_steal_data ( G_MEMORY_OUTPUT_STREAM ( ostream1 ) ) ;
data1_size = g_memory_output_stream_get_data_size (
G_MEMORY_OUTPUT_STREAM ( ostream1 ) ) ;
g_object_unref ( ostream1 ) ;
g_object_unref ( istream0 ) ;
/* truncate */
data1_size / = 2 ;
istream1 = g_memory_input_stream_new_from_data ( data1 , data1_size , g_free ) ;
decompressor = G_CONVERTER ( g_zlib_decompressor_new ( test - > format ) ) ;
cistream1 = g_converter_input_stream_new ( istream1 , decompressor ) ;
ostream2 = g_memory_output_stream_new ( NULL , 0 , g_realloc , g_free ) ;
g_output_stream_splice ( ostream2 , cistream1 , 0 , NULL , & error ) ;
g_assert_error ( error , G_IO_ERROR , G_IO_ERROR_PARTIAL_INPUT ) ;
2012-08-25 02:43:54 +02:00
g_error_free ( error ) ;
2012-07-17 22:21:03 +02:00
g_object_unref ( istream1 ) ;
g_object_unref ( decompressor ) ;
g_object_unref ( cistream1 ) ;
g_object_unref ( ostream2 ) ;
g_free ( data0 ) ;
}
2012-02-06 21:08:08 +01:00
2009-10-23 19:59:03 +02:00
int
main ( int argc ,
char * argv [ ] )
{
2010-07-05 02:49:29 +02:00
CompressorTest compressor_tests [ ] = {
2012-07-17 22:21:03 +02:00
{ " /converter-output-stream/roundtrip/zlib-0 " , G_ZLIB_COMPRESSOR_FORMAT_ZLIB , 0 } ,
{ " /converter-output-stream/roundtrip/zlib-9 " , G_ZLIB_COMPRESSOR_FORMAT_ZLIB , 9 } ,
{ " /converter-output-stream/roundtrip/gzip-0 " , G_ZLIB_COMPRESSOR_FORMAT_GZIP , 0 } ,
{ " /converter-output-stream/roundtrip/gzip-9 " , G_ZLIB_COMPRESSOR_FORMAT_GZIP , 9 } ,
{ " /converter-output-stream/roundtrip/raw-0 " , G_ZLIB_COMPRESSOR_FORMAT_RAW , 0 } ,
{ " /converter-output-stream/roundtrip/raw-9 " , G_ZLIB_COMPRESSOR_FORMAT_RAW , 9 } ,
} ;
CompressorTest truncation_tests [ ] = {
{ " /converter-input-stream/truncation/zlib " , G_ZLIB_COMPRESSOR_FORMAT_ZLIB , 0 } ,
{ " /converter-input-stream/truncation/gzip " , G_ZLIB_COMPRESSOR_FORMAT_GZIP , 0 } ,
{ " /converter-input-stream/truncation/raw " , G_ZLIB_COMPRESSOR_FORMAT_RAW , 0 } ,
2010-07-03 09:31:24 +02:00
} ;
2010-07-05 02:49:29 +02:00
CharsetTest charset_tests [ ] = {
2010-07-06 01:33:05 +02:00
{ " /converter-input-stream/charset/utf8->latin1 " , " UTF-8 " , " \303 \205 rr Sant \303 \251 " , " ISO-8859-1 " , " \305 rr Sant \351 " , 0 } ,
{ " /converter-input-stream/charset/latin1->utf8 " , " ISO-8859-1 " , " \305 rr Sant \351 " , " UTF-8 " , " \303 \205 rr Sant \303 \251 " , 0 } ,
{ " /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 } ,
2010-07-05 02:49:29 +02:00
} ;
2010-07-03 09:31:24 +02:00
gint i ;
2009-10-23 19:59:03 +02:00
g_test_init ( & argc , & argv , NULL ) ;
2010-08-14 03:22:45 +02:00
g_test_bug_base ( " http://bugzilla.gnome.org/ " ) ;
2009-10-23 19:59:03 +02:00
g_test_add_func ( " /converter-input-stream/expander " , test_expander ) ;
g_test_add_func ( " /converter-input-stream/compressor " , test_compressor ) ;
2010-07-03 09:31:24 +02:00
2010-07-05 02:49:29 +02:00
for ( i = 0 ; i < G_N_ELEMENTS ( compressor_tests ) ; i + + )
g_test_add_data_func ( compressor_tests [ i ] . path , & compressor_tests [ i ] , test_roundtrip ) ;
2012-07-17 22:21:03 +02:00
for ( i = 0 ; i < G_N_ELEMENTS ( truncation_tests ) ; i + + )
g_test_add_data_func ( truncation_tests [ i ] . path , & truncation_tests [ i ] , test_truncation ) ;
2010-07-05 02:49:29 +02:00
for ( i = 0 ; i < G_N_ELEMENTS ( charset_tests ) ; i + + )
g_test_add_data_func ( charset_tests [ i ] . path , & charset_tests [ i ] , test_charset ) ;
2012-02-06 21:08:08 +01:00
g_test_add_func ( " /converter-stream/pollable " , test_converter_pollable ) ;
2012-05-30 14:30:27 +02:00
g_test_add_func ( " /converter-stream/leftover " , test_converter_leftover ) ;
2009-10-23 19:59:03 +02:00
return g_test_run ( ) ;
}