mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-27 07:56:14 +01:00
aec5d17d77
While the assertion always turned out to be true on Linux, it frequently caused spurious test failures on FreeBSD. After some remote debugging, I *think* the cause is as written up in the comment in the code in this commit. However, I cannot be certain, as the more debugging messages I added, the harder the failure was to reproduce; and I don’t have access to a FreeBSD machine. This fixes failures like: ``` Bail out! GLib-GIO:ERROR:../gio/tests/converter-stream.c:1043:test_converter_pollable: assertion failed (error == NULL): Resource temporarily unavailable (g-io-error-quark, 27) ``` It’s succeeded 1000 times in a row on the FreeBSD CI now; previously it was failing one time in three: https://gitlab.gnome.org/GNOME/glib/-/jobs/1936395. Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
1235 lines
34 KiB
C
1235 lines
34 KiB
C
/* 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;
|
||
gsize 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;
|
||
gsize 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 ((gsize) (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 && (gsize) (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;
|
||
GInputStream *mem, *cstream;
|
||
GOutputStream *mem_out, *cstream_out;
|
||
GConverter *expander;
|
||
GConverter *converter;
|
||
GError *error;
|
||
gsize 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_cmpint (cres, ==, G_CONVERTER_FINISHED);
|
||
g_assert_cmpuint (n_read, ==, 11);
|
||
g_assert_cmpuint (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);
|
||
g_assert_true (g_converter_input_stream_get_converter (G_CONVERTER_INPUT_STREAM (cstream)) == expander);
|
||
g_object_get (cstream, "converter", &converter, NULL);
|
||
g_assert_true (converter == expander);
|
||
g_object_unref (converter);
|
||
g_object_unref (mem);
|
||
|
||
total_read = 0;
|
||
ptr = converted2;
|
||
while (TRUE)
|
||
{
|
||
error = NULL;
|
||
res = g_input_stream_read (cstream,
|
||
ptr, 1,
|
||
NULL, &error);
|
||
g_assert_cmpint (res, !=, -1);
|
||
if (res == 0)
|
||
break;
|
||
ptr += res;
|
||
total_read += res;
|
||
}
|
||
|
||
g_assert_cmpmem (converted1, n_written, converted2, total_read);
|
||
|
||
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);
|
||
g_assert_true (g_converter_output_stream_get_converter (G_CONVERTER_OUTPUT_STREAM (cstream_out)) == expander);
|
||
g_object_get (cstream_out, "converter", &converter, NULL);
|
||
g_assert_true (converter == expander);
|
||
g_object_unref (converter);
|
||
g_object_unref (mem_out);
|
||
|
||
for (i = 0; i < sizeof(unexpanded_data); i++)
|
||
{
|
||
error = NULL;
|
||
res = g_output_stream_write (cstream_out,
|
||
unexpanded_data + i, 1,
|
||
NULL, &error);
|
||
g_assert_cmpint (res, !=, -1);
|
||
if (res == 0)
|
||
{
|
||
g_assert_cmpuint (i, ==, sizeof(unexpanded_data) -1);
|
||
break;
|
||
}
|
||
g_assert_cmpint (res, ==, 1);
|
||
}
|
||
|
||
g_output_stream_close (cstream_out, NULL, NULL);
|
||
|
||
g_assert_cmpmem (g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (mem_out)),
|
||
g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (mem_out)),
|
||
converted1, n_written);
|
||
|
||
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;
|
||
GInputStream *mem, *cstream;
|
||
GOutputStream *mem_out, *cstream_out;
|
||
GConverter *expander, *compressor;
|
||
GError *error;
|
||
gsize 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_cmpint (cres, ==, G_CONVERTER_FINISHED);
|
||
g_assert_cmpuint (n_read, ==, 11);
|
||
g_assert_cmpuint (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;
|
||
res = g_input_stream_read (cstream,
|
||
ptr, 1,
|
||
NULL, &error);
|
||
g_assert_cmpint (res, !=, -1);
|
||
if (res == 0)
|
||
break;
|
||
ptr += res;
|
||
total_read += res;
|
||
}
|
||
|
||
/* "n_read - 1" because last 2 zeros are combined */
|
||
g_assert_cmpmem (unexpanded_data, n_read - 1, converted, total_read);
|
||
|
||
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;
|
||
res = g_output_stream_write (cstream_out,
|
||
expanded + i, 1,
|
||
NULL, &error);
|
||
g_assert_cmpint (res, !=, -1);
|
||
if (res == 0)
|
||
{
|
||
g_assert_cmpuint (i, ==, expanded_size -1);
|
||
break;
|
||
}
|
||
g_assert_cmpint (res, ==, 1);
|
||
}
|
||
|
||
g_output_stream_close (cstream_out, NULL, NULL);
|
||
|
||
/* "n_read - 1" because last 2 zeros are combined */
|
||
g_assert_cmpmem (g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (mem_out)),
|
||
g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (mem_out)),
|
||
unexpanded_data,
|
||
n_read - 1);
|
||
|
||
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;
|
||
res = g_input_stream_read (cstream,
|
||
ptr, 1,
|
||
NULL, &error);
|
||
g_assert_cmpint (res, !=, -1);
|
||
if (res == 0)
|
||
break;
|
||
ptr += res;
|
||
total_read += res;
|
||
}
|
||
|
||
g_assert_cmpuint (total_read, ==, 1);
|
||
g_assert_cmpuint (*converted, ==, 5);
|
||
|
||
g_object_unref (cstream);
|
||
|
||
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;
|
||
res = g_input_stream_read (cstream,
|
||
ptr, 1,
|
||
NULL, &error);
|
||
g_assert_cmpint (res, !=, -1);
|
||
if (res == 0)
|
||
break;
|
||
ptr += res;
|
||
total_read += res;
|
||
}
|
||
|
||
g_assert_cmpuint (total_read, ==, 2);
|
||
g_assert_cmpuint (converted[0], ==, 5);
|
||
g_assert_cmpuint (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;
|
||
res = g_input_stream_read (cstream,
|
||
ptr, 1,
|
||
NULL, &error);
|
||
if (res == -1)
|
||
{
|
||
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT);
|
||
g_error_free (error);
|
||
break;
|
||
}
|
||
|
||
g_assert_cmpint (res, !=, 0);
|
||
ptr += res;
|
||
total_read += res;
|
||
}
|
||
|
||
g_assert_cmpuint (total_read, ==, 1);
|
||
g_assert_cmpuint (converted[0], ==, 5);
|
||
|
||
g_object_unref (cstream);
|
||
|
||
g_free (expanded);
|
||
g_free (converted);
|
||
g_object_unref (expander);
|
||
g_object_unref (compressor);
|
||
}
|
||
|
||
#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_cmpint (res, >=, 0);
|
||
if (res == 0)
|
||
break;
|
||
total_read += res;
|
||
}
|
||
|
||
g_assert_cmpmem (orig, LEFTOVER_BUFSIZE, converted, total_read);
|
||
|
||
g_object_unref (cstream);
|
||
g_free (orig);
|
||
g_free (converted);
|
||
g_object_unref (converter);
|
||
}
|
||
|
||
#define DATA_LENGTH 1000000
|
||
|
||
typedef struct {
|
||
const gchar *path;
|
||
GZlibCompressorFormat format;
|
||
gint level;
|
||
} CompressorTest;
|
||
|
||
static void
|
||
test_roundtrip (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;
|
||
GZlibCompressorFormat fmt;
|
||
gint lvl;
|
||
GFileInfo *info;
|
||
GFileInfo *info2;
|
||
|
||
g_test_bug ("https://bugzilla.gnome.org/show_bug.cgi?id=619945");
|
||
|
||
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, test->level));
|
||
info = g_file_info_new ();
|
||
g_file_info_set_name (info, "foo");
|
||
g_object_set (compressor, "file-info", info, NULL);
|
||
info2 = g_zlib_compressor_get_file_info (G_ZLIB_COMPRESSOR (compressor));
|
||
g_assert_true (info == info2);
|
||
g_object_unref (info);
|
||
costream1 = g_converter_output_stream_new (ostream1, compressor);
|
||
g_assert_true (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_converter_reset (compressor);
|
||
g_object_get (compressor, "format", &fmt, "level", &lvl, NULL);
|
||
g_assert_cmpint (fmt, ==, test->format);
|
||
g_assert_cmpint (lvl, ==, test->level);
|
||
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);
|
||
|
||
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_no_error (error);
|
||
|
||
g_assert_cmpmem (data0, DATA_LENGTH * sizeof (guint32),
|
||
g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (ostream2)),
|
||
g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (ostream2)));
|
||
g_object_unref (istream1);
|
||
g_converter_reset (decompressor);
|
||
g_object_get (decompressor, "format", &fmt, NULL);
|
||
g_assert_cmpint (fmt, ==, test->format);
|
||
g_object_unref (decompressor);
|
||
g_object_unref (cistream1);
|
||
g_object_unref (ostream2);
|
||
g_free (data0);
|
||
}
|
||
|
||
typedef struct {
|
||
const gchar *path;
|
||
const gchar *charset_in;
|
||
const gchar *text_in;
|
||
const gchar *charset_out;
|
||
const gchar *text_out;
|
||
gint n_fallbacks;
|
||
} 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;
|
||
gboolean fallback;
|
||
|
||
conv = (GConverter *)g_charset_converter_new (test->charset_out, test->charset_in, NULL);
|
||
g_object_get (conv, "use-fallback", &fallback, NULL);
|
||
g_assert_false (fallback);
|
||
|
||
in = g_memory_input_stream_new_from_data (test->text_in, -1, NULL);
|
||
in2 = g_converter_input_stream_new (in, conv);
|
||
|
||
count = 2 * strlen (test->text_out);
|
||
buffer = g_malloc0 (count);
|
||
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
|
||
{
|
||
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA);
|
||
g_error_free (error);
|
||
}
|
||
|
||
g_free (buffer);
|
||
g_object_unref (in2);
|
||
g_object_unref (in);
|
||
|
||
if (test->n_fallbacks == 0)
|
||
{
|
||
g_object_unref (conv);
|
||
return;
|
||
}
|
||
|
||
g_converter_reset (conv);
|
||
|
||
g_assert_false (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);
|
||
|
||
count = 2 * strlen (test->text_out);
|
||
buffer = g_malloc0 (count);
|
||
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);
|
||
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)));
|
||
|
||
g_free (buffer);
|
||
g_object_unref (in2);
|
||
g_object_unref (in);
|
||
|
||
g_object_unref (conv);
|
||
}
|
||
|
||
|
||
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;
|
||
gsize 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_cmpint (cres, ==, G_CONVERTER_FINISHED);
|
||
g_assert_cmpuint (n_read, ==, 11);
|
||
g_assert_cmpuint (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_true (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_output_stream_close (socket_out, NULL, NULL);
|
||
g_object_unref (right);
|
||
socket_out = NULL;
|
||
}
|
||
|
||
/* Wait a few ticks to check for the pipe to propagate the
|
||
* write. We can’t wait on a GSource as that might affect the stream under
|
||
* test, so just poll. */
|
||
while (!g_pollable_input_stream_is_readable (pollable_in))
|
||
g_usleep (80L);
|
||
|
||
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);
|
||
|
||
/* Even after closing the write end, we can get WOULD_BLOCK (particularly
|
||
* on FreeBSD), so we can’t make any assertions based on `!socket_out`.
|
||
* This is because the FIN packets may still be in the out buffer of one
|
||
* half of the socket pair, while the in buffer of the other half has some
|
||
* data, but not enough for a full block for the converter to consume. */
|
||
|
||
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;
|
||
}
|
||
|
||
/* "n_read - 1" because last 2 zeros are combined */
|
||
g_assert_cmpmem (unexpanded_data, n_read - 1, converted, total_read);
|
||
|
||
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);
|
||
g_assert_true (g_pollable_output_stream_can_poll (pollable_out));
|
||
g_assert_true (g_pollable_output_stream_is_writable (pollable_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_cmpint (res, !=, -1);
|
||
if (res == 0)
|
||
{
|
||
g_assert_cmpuint (i, ==, expanded_size -1);
|
||
break;
|
||
}
|
||
g_assert_cmpint (res, ==, 1);
|
||
}
|
||
|
||
g_output_stream_close (cstream_out, NULL, NULL);
|
||
|
||
/* "n_read - 1" because last 2 zeros are combined */
|
||
g_assert_cmpmem (g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (mem_out)),
|
||
g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (mem_out)),
|
||
unexpanded_data,
|
||
n_read - 1);
|
||
|
||
g_object_unref (cstream_out);
|
||
|
||
g_free (expanded);
|
||
g_free (converted);
|
||
g_object_unref (expander);
|
||
g_object_unref (compressor);
|
||
}
|
||
|
||
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_true (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);
|
||
g_error_free (error);
|
||
|
||
g_object_unref (istream1);
|
||
g_object_unref (decompressor);
|
||
g_object_unref (cistream1);
|
||
g_object_unref (ostream2);
|
||
g_free (data0);
|
||
}
|
||
|
||
static void
|
||
test_converter_basics (void)
|
||
{
|
||
GConverter *converter;
|
||
GError *error = NULL;
|
||
gchar *to;
|
||
gchar *from;
|
||
|
||
converter = (GConverter *)g_charset_converter_new ("utf-8", "latin1", &error);
|
||
g_assert_no_error (error);
|
||
g_object_get (converter,
|
||
"to-charset", &to,
|
||
"from-charset", &from,
|
||
NULL);
|
||
|
||
g_assert_cmpstr (to, ==, "utf-8");
|
||
g_assert_cmpstr (from, ==, "latin1");
|
||
|
||
g_free (to);
|
||
g_free (from);
|
||
g_object_unref (converter);
|
||
}
|
||
|
||
int
|
||
main (int argc,
|
||
char *argv[])
|
||
{
|
||
CompressorTest compressor_tests[] = {
|
||
{ "/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 },
|
||
};
|
||
CharsetTest charset_tests[] = {
|
||
{ "/converter-input-stream/charset/utf8->latin1", "UTF-8", "\303\205rr Sant\303\251", "ISO-8859-1", "\305rr Sant\351", 0 },
|
||
{ "/converter-input-stream/charset/latin1->utf8", "ISO-8859-1", "\305rr Sant\351", "UTF-8", "\303\205rr 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 },
|
||
};
|
||
|
||
gsize i;
|
||
|
||
g_test_init (&argc, &argv, NULL);
|
||
|
||
g_test_add_func ("/converter/basics", test_converter_basics);
|
||
g_test_add_func ("/converter-input-stream/expander", test_expander);
|
||
g_test_add_func ("/converter-input-stream/compressor", test_compressor);
|
||
|
||
for (i = 0; i < G_N_ELEMENTS (compressor_tests); i++)
|
||
g_test_add_data_func (compressor_tests[i].path, &compressor_tests[i], test_roundtrip);
|
||
|
||
for (i = 0; i < G_N_ELEMENTS (truncation_tests); i++)
|
||
g_test_add_data_func (truncation_tests[i].path, &truncation_tests[i], test_truncation);
|
||
|
||
for (i = 0; i < G_N_ELEMENTS (charset_tests); i++)
|
||
g_test_add_data_func (charset_tests[i].path, &charset_tests[i], test_charset);
|
||
|
||
g_test_add_func ("/converter-stream/pollable", test_converter_pollable);
|
||
g_test_add_func ("/converter-stream/leftover", test_converter_leftover);
|
||
|
||
return g_test_run();
|
||
}
|