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 (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);
+}
+
#define DATA_LENGTH 1000000
+typedef struct {
+ const gchar *path;
+ GZlibCompressorFormat format;
+ gint level;
+} CompressorTest;
+
static void
-test_corruption (GZlibCompressorFormat format, gint level)
+test_roundtrip (gconstpointer data)
{
+ const CompressorTest *test = data;
GError *error = NULL;
guint32 *data0, *data1;
gsize data1_size;
GConverter *compressor, *decompressor;
GZlibCompressorFormat fmt;
gint lvl;
+ GFileInfo *info;
+ GFileInfo *info2;
+
+ g_test_bug ("619945");
data0 = g_malloc (DATA_LENGTH * sizeof (guint32));
for (i = 0; i < DATA_LENGTH; i++)
DATA_LENGTH * sizeof (guint32), NULL);
ostream1 = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
- compressor = G_CONVERTER (g_zlib_compressor_new (format, level));
+ 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 (info == info2);
+ g_object_unref (info);
costream1 = g_converter_output_stream_new (ostream1, compressor);
g_assert (g_converter_output_stream_get_converter (G_CONVERTER_OUTPUT_STREAM (costream1)) == compressor);
g_converter_reset (compressor);
g_object_get (compressor, "format", &fmt, "level", &lvl, NULL);
- g_assert_cmpint (fmt, ==, format);
- g_assert_cmpint (lvl, ==, level);
+ 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_object_unref (istream0);
istream1 = g_memory_input_stream_new_from_data (data1, data1_size, g_free);
- decompressor = G_CONVERTER (g_zlib_decompressor_new (format));
+ 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_object_unref (istream1);
g_converter_reset (decompressor);
g_object_get (decompressor, "format", &fmt, NULL);
- g_assert_cmpint (fmt, ==, format);
+ g_assert_cmpint (fmt, ==, test->format);
g_object_unref (decompressor);
g_object_unref (cistream1);
g_object_unref (ostream2);
typedef struct {
const gchar *path;
- GZlibCompressorFormat format;
- gint level;
-} CompressorTest;
-
-static void
-test_roundtrip (gconstpointer data)
-{
- const CompressorTest *test = data;
-
- g_test_bug ("162549");
-
- test_corruption (test->format, test->level);
-}
-
-typedef struct {
- const gchar *path;
const gchar *charset_in;
const gchar *text_in;
const gchar *charset_out;
if (outptr < expanded_end)
{
- res = g_output_stream_write (socket_out,
+ res = g_output_stream_write (socket_out,
outptr,
MIN (1000, (expanded_end - outptr)),
NULL, &error);
socket_out = NULL;
}
+ /* 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);
+
is_readable = g_pollable_input_stream_is_readable (pollable_in);
res = g_pollable_input_stream_read_nonblocking (pollable_in,
inptr, 1,
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 (g_pollable_output_stream_can_poll (pollable_out));
+ g_assert (g_pollable_output_stream_is_writable (pollable_out));
for (i = 0; i < expanded_size; i++)
{
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 (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/corruption/zlib-0", G_ZLIB_COMPRESSOR_FORMAT_ZLIB, 0 },
- { "/converter-output-stream/corruption/zlib-9", G_ZLIB_COMPRESSOR_FORMAT_ZLIB, 9 },
- { "/converter-output-stream/corruption/gzip-0", G_ZLIB_COMPRESSOR_FORMAT_GZIP, 0 },
- { "/converter-output-stream/corruption/gzip-9", G_ZLIB_COMPRESSOR_FORMAT_GZIP, 9 },
- { "/converter-output-stream/corruption/raw-0", G_ZLIB_COMPRESSOR_FORMAT_RAW, 0 },
- { "/converter-output-stream/corruption/raw-9", G_ZLIB_COMPRESSOR_FORMAT_RAW, 9 },
+ { "/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 },
-
};
gint i;
- g_type_init ();
g_test_init (&argc, &argv, NULL);
g_test_bug_base ("http://bugzilla.gnome.org/");
+ 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();
}