[gtk/wip/otte/newline-converter] gdk: Add GNewLineConverter
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/otte/newline-converter] gdk: Add GNewLineConverter
- Date: Mon, 16 Aug 2021 05:26:10 +0000 (UTC)
commit b24a3736dc234099714501db5a27cf0551f214b6
Author: Benjamin Otte <otte redhat com>
Date: Mon Aug 16 07:24:42 2021 +0200
gdk: Add GNewLineConverter
A converter that converts between different line endings - \r, \n and
\r\n.
This should probably live in glib, but for now it lives here.
gdk/gnewlineconverter.c | 345 +++++++++++++++++++++++++++++++++++++++
gdk/gnewlineconverter.h | 60 +++++++
gdk/meson.build | 2 +
testsuite/gtk/meson.build | 5 +-
testsuite/gtk/newlineconverter.c | 265 ++++++++++++++++++++++++++++++
5 files changed, 675 insertions(+), 2 deletions(-)
---
diff --git a/gdk/gnewlineconverter.c b/gdk/gnewlineconverter.c
new file mode 100644
index 0000000000..259c863090
--- /dev/null
+++ b/gdk/gnewlineconverter.c
@@ -0,0 +1,345 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2021 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Benjamin Otte <otte gnome org>
+ */
+
+#include "config.h"
+
+#include "gnewlineconverter.h"
+
+#include "gdkintl.h"
+
+enum {
+ PROP_0,
+ PROP_FROM_NEWLINE,
+ PROP_TO_NEWLINE
+};
+
+/**
+ * SECTION:gnewlineconverter
+ * @short_description: Convert between newlines
+ * @include: gio/gio.h
+ *
+ * #GNewlineConverter is an implementation of #GConverter that converts
+ * between different line endings. This is useful when converting data streams
+ * between Windows and UNIX compatibility.
+ */
+
+/**
+ * GNewlineConverter:
+ *
+ * Conversions of line endings.
+ */
+struct _GNewlineConverter
+{
+ GObject parent_instance;
+
+ GDataStreamNewlineType from;
+ GDataStreamNewlineType to;
+};
+
+static void g_newline_converter_iface_init (GConverterIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GNewlineConverter, g_newline_converter, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER,
+ g_newline_converter_iface_init))
+
+static GConverterResult
+g_newline_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)
+{
+ GNewlineConverter *self = G_NEWLINE_CONVERTER (converter);
+ GConverterResult ret;
+ const char *inbufp, *inbuf_end;
+ char *outbufp, *outbuf_end;
+ gsize size;
+
+ inbufp = inbuf;
+ inbuf_end = inbufp + inbuf_size;
+ outbufp = outbuf;
+ outbuf_end = outbufp + outbuf_size;
+
+ /* shortcut for the easy case, avoids special casing later */
+ if (self->from == self->to ||
+ self->to == G_DATA_STREAM_NEWLINE_TYPE_ANY)
+ {
+ size = MIN (inbuf_size, outbuf_size);
+
+ if (size > 0)
+ memcpy (outbufp, inbufp, size);
+ inbufp += size;
+ outbufp += size;
+
+ goto done;
+ }
+
+ /* ignore \r at end of input when we care about \r\n */
+ if ((flags & G_CONVERTER_INPUT_AT_END) == 0 &&
+ (self->from == G_DATA_STREAM_NEWLINE_TYPE_CR_LF ||
+ self->from == G_DATA_STREAM_NEWLINE_TYPE_ANY) &&
+ inbufp < inbuf_end &&
+ inbuf_end[-1] == '\r')
+ inbuf_end--;
+
+ while (inbufp < inbuf_end && outbufp < outbuf_end)
+ {
+ const char *linebreak;
+
+ switch (self->from)
+ {
+ case G_DATA_STREAM_NEWLINE_TYPE_LF:
+ linebreak = memchr (inbufp, '\n', inbuf_end - inbufp);
+ break;
+ case G_DATA_STREAM_NEWLINE_TYPE_CR:
+ linebreak = memchr (inbufp, '\r', inbuf_end - inbufp);
+ break;
+ case G_DATA_STREAM_NEWLINE_TYPE_CR_LF:
+ linebreak = inbufp;
+ while ((linebreak = memchr (linebreak, '\r', inbuf_end - linebreak)))
+ {
+ if (inbuf_end - linebreak > 1 &&
+ linebreak[1] == '\n')
+ break;
+ linebreak++;
+ }
+ break;
+ case G_DATA_STREAM_NEWLINE_TYPE_ANY:
+ {
+ const char *lf = memchr (inbufp, '\n', inbuf_end - inbufp);
+ linebreak = memchr (inbufp, '\r', (lf ? lf : inbuf_end) - inbufp);
+ if (linebreak == NULL)
+ linebreak = lf;
+ break;
+ }
+ default:
+ g_assert_not_reached();
+ break;
+ }
+
+ /* copy the part without linebreaks */
+ if (linebreak)
+ size = linebreak - inbufp;
+ else
+ size = inbuf_end - inbufp;
+ size = MIN (outbuf_end - outbufp, size);
+ if (size)
+ {
+ memcpy (outbufp, inbufp, size);
+ outbufp += size;
+ inbufp += size;
+ }
+
+ if (inbufp >= inbuf_end || outbufp >= outbuf_end)
+ break;
+
+ /* We should have broken above */
+ g_assert (linebreak != NULL);
+ g_assert (inbufp == linebreak);
+
+ switch (self->to)
+ {
+ case G_DATA_STREAM_NEWLINE_TYPE_LF:
+ *outbufp++ = '\n';
+ break;
+ case G_DATA_STREAM_NEWLINE_TYPE_CR:
+ *outbufp++ = '\r';
+ break;
+ case G_DATA_STREAM_NEWLINE_TYPE_CR_LF:
+ if (outbuf_end - outbufp < 2)
+ goto done;
+ *outbufp++ = '\r';
+ *outbufp++ = '\n';
+ break;
+ case G_DATA_STREAM_NEWLINE_TYPE_ANY:
+ default:
+ g_assert_not_reached();
+ break;
+ }
+ switch (self->from)
+ {
+ case G_DATA_STREAM_NEWLINE_TYPE_LF:
+ case G_DATA_STREAM_NEWLINE_TYPE_CR:
+ inbufp++;
+ break;
+ case G_DATA_STREAM_NEWLINE_TYPE_CR_LF:
+ inbufp += 2;
+ break;
+ case G_DATA_STREAM_NEWLINE_TYPE_ANY:
+ if (inbuf_end - inbufp > 1 && inbufp[0] == '\r' && inbufp[1] == '\n')
+ inbufp += 2;
+ else
+ inbufp++;
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ }
+
+done:
+ if (inbufp == inbuf &&
+ !(flags & G_CONVERTER_FLUSH))
+ {
+ g_assert (outbufp == outbuf);
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT,
+ _("Not enough input"));
+ return G_CONVERTER_ERROR;
+ }
+
+ if ((flags & G_CONVERTER_INPUT_AT_END) &&
+ inbufp == inbuf_end)
+ ret = G_CONVERTER_FINISHED;
+ else if (flags & G_CONVERTER_FLUSH)
+ ret = G_CONVERTER_FLUSHED;
+ else
+ ret = G_CONVERTER_CONVERTED;
+
+ *bytes_read = inbufp - (const char *) inbuf;
+ *bytes_written = outbufp - (char *) outbuf;
+
+ return ret;
+}
+
+static void
+g_newline_converter_reset (GConverter *converter)
+{
+ /* nothing to do here */
+}
+
+static void
+g_newline_converter_iface_init (GConverterIface *iface)
+{
+ iface->convert = g_newline_converter_convert;
+ iface->reset = g_newline_converter_reset;
+}
+
+static void
+g_newline_converter_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GNewlineConverter *conv;
+
+ conv = G_NEWLINE_CONVERTER (object);
+
+ switch (prop_id)
+ {
+ case PROP_TO_NEWLINE:
+ conv->to = g_value_get_enum (value);
+ break;
+
+ case PROP_FROM_NEWLINE:
+ conv->from = g_value_get_enum (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+
+}
+
+static void
+g_newline_converter_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GNewlineConverter *conv;
+
+ conv = G_NEWLINE_CONVERTER (object);
+
+ switch (prop_id)
+ {
+ case PROP_TO_NEWLINE:
+ g_value_set_enum (value, conv->to);
+ break;
+
+ case PROP_FROM_NEWLINE:
+ g_value_set_enum (value, conv->from);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+g_newline_converter_class_init (GNewlineConverterClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->get_property = g_newline_converter_get_property;
+ gobject_class->set_property = g_newline_converter_set_property;
+
+ g_object_class_install_property (gobject_class,
+ PROP_TO_NEWLINE,
+ g_param_spec_enum ("to-newline",
+ P_("To Newline"),
+ P_("The newline type to convert to"),
+ G_TYPE_DATA_STREAM_NEWLINE_TYPE,
+ G_DATA_STREAM_NEWLINE_TYPE_LF,
+
G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_BLURB));
+ g_object_class_install_property (gobject_class,
+ PROP_FROM_NEWLINE,
+ g_param_spec_enum ("from-newline",
+ P_("From Newline"),
+ P_("The newline type to convert from"),
+ G_TYPE_DATA_STREAM_NEWLINE_TYPE,
+ G_DATA_STREAM_NEWLINE_TYPE_LF,
+
G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_BLURB));
+}
+
+static void
+g_newline_converter_init (GNewlineConverter *local)
+{
+}
+
+
+/**
+ * g_newline_converter_new:
+ * @to_newline: destination newline
+ * @from_newline: source newline
+ *
+ * Creates a new #GNewlineConverter.
+ *
+ * Returns: a new #GNewlineConverter
+ **/
+GNewlineConverter *
+g_newline_converter_new (GDataStreamNewlineType to_newline,
+ GDataStreamNewlineType from_newline)
+{
+ GNewlineConverter *conv;
+
+ conv = g_object_new (G_TYPE_NEWLINE_CONVERTER,
+ "to-newline", to_newline,
+ "from-newline", from_newline,
+ NULL);
+
+ return conv;
+}
+
diff --git a/gdk/gnewlineconverter.h b/gdk/gnewlineconverter.h
new file mode 100644
index 0000000000..a50d474846
--- /dev/null
+++ b/gdk/gnewlineconverter.h
@@ -0,0 +1,60 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2021 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Benjamin Otte <otte gnome org>
+ */
+
+#ifndef __G_NEWLINE_CONVERTER_H__
+#define __G_NEWLINE_CONVERTER_H__
+
+#if 0
+#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
+#error "Only <gio/gio.h> can be included directly."
+#endif
+
+#include <gio/gconverter.h>
+#else
+#include <gio/gio.h>
+#endif
+
+G_BEGIN_DECLS
+
+#define G_TYPE_NEWLINE_CONVERTER (g_newline_converter_get_type ())
+#define G_NEWLINE_CONVERTER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_NEWLINE_CONVERTER,
GNewlineConverter))
+#define G_NEWLINE_CONVERTER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_NEWLINE_CONVERTER,
GNewlineConverterClass))
+#define G_IS_NEWLINE_CONVERTER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_NEWLINE_CONVERTER))
+#define G_IS_NEWLINE_CONVERTER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_NEWLINE_CONVERTER))
+#define G_NEWLINE_CONVERTER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_NEWLINE_CONVERTER,
GNewlineConverterClass))
+
+typedef struct _GNewlineConverter GNewlineConverter;
+typedef struct _GNewlineConverterClass GNewlineConverterClass;
+
+struct _GNewlineConverterClass
+{
+ GObjectClass parent_class;
+};
+
+GLIB_AVAILABLE_IN_ALL
+GType g_newline_converter_get_type (void) G_GNUC_CONST;
+
+GLIB_AVAILABLE_IN_ALL
+GNewlineConverter * g_newline_converter_new (GDataStreamNewlineType to_newline,
+ GDataStreamNewlineType from_newline);
+
+G_END_DECLS
+
+#endif /* __G_NEWLINE_CONVERTER_H__ */
diff --git a/gdk/meson.build b/gdk/meson.build
index db64565c2c..133df9ca1f 100644
--- a/gdk/meson.build
+++ b/gdk/meson.build
@@ -50,6 +50,7 @@ gdk_public_sources = files([
'gdktoplevelsize.c',
'gdktoplevel.c',
'gdkdragsurface.c',
+ 'gnewlineconverter.c',
])
gdk_public_headers = files([
@@ -110,6 +111,7 @@ gdk_private_h_sources = files([
'gdkmonitorprivate.h',
'gdkseatdefaultprivate.h',
'gdktoplevelsizeprivate.h',
+ 'gnewlineconverter.h'
])
gdk_gresource_xml = configure_file(output: 'gdk.gresource.xml',
diff --git a/testsuite/gtk/meson.build b/testsuite/gtk/meson.build
index b628b07dc2..681e715ea1 100644
--- a/testsuite/gtk/meson.build
+++ b/testsuite/gtk/meson.build
@@ -113,11 +113,12 @@ internal_tests = [
'../testutils.c'
],
},
- { 'name': 'imcontext' },
{ 'name': 'constraint-solver' },
- { 'name': 'rbtree-crash' },
+ { 'name': 'imcontext' },
+ { 'name': 'newlineconverter' },
{ 'name': 'propertylookuplistmodel' },
{ 'name': 'rbtree' },
+ { 'name': 'rbtree-crash' },
{ 'name': 'timsort' },
{ 'name': 'texthistory' },
{ 'name': 'fnmatch' },
diff --git a/testsuite/gtk/newlineconverter.c b/testsuite/gtk/newlineconverter.c
new file mode 100644
index 0000000000..723dd00ea7
--- /dev/null
+++ b/testsuite/gtk/newlineconverter.c
@@ -0,0 +1,265 @@
+/*
+ * Copyright © 2021 Benjamin Otte
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#include <locale.h>
+
+#include <gdk/gnewlineconverter.h>
+
+#define N 100
+
+#define MAX_SIZE 20
+
+static const char *words[] = { "", "", "lorem", "ipsum", "dolor", "sit", "amet",
+ "consectetur", "adipisci", "elit", "sed", "eiusmod", "tempor", "incidunt",
+ "labore", "et", "dolore", "magna", "aliqua", "ut", "enim", "ad", "minim",
+ "veniam", "quis", "nostrud", "exercitation", "ullamco", "laboris", "nisi",
+ "ut", "aliquid", "ex", "ea", "commodi", "consequat" };
+
+static const char *breaks[] = { "", "\r", "\n", "\r\n" };
+
+static GBytes *
+generate_random_text (gboolean fuzz)
+{
+ GByteArray *array;
+ guint i, n;
+
+ array = g_byte_array_new ();
+
+ n = g_test_rand_int_range (0, 100);
+
+ for (i = 0; i < n; i++)
+ {
+ const char *word;
+
+ word = words[g_test_rand_int_range (0, G_N_ELEMENTS (words))];
+ g_byte_array_append (array, (const guchar *) word, strlen (word));
+
+ word = breaks[g_test_rand_int_range (0, G_N_ELEMENTS (breaks))];
+ g_byte_array_append (array, (const guchar *) word, strlen (word));
+ }
+
+ if (fuzz && array->len > 0)
+ {
+ for (i = 0; i < 100; i++)
+ {
+ array->data[g_test_rand_int_range (0, array->len)] = g_test_rand_int_range (0, 255);
+ }
+ }
+
+ return g_byte_array_free_to_bytes (array);
+}
+
+static GBytes *
+convert (GBytes *input,
+ GDataStreamNewlineType to_newline,
+ GDataStreamNewlineType from_newline)
+{
+ GConverter *converter;
+ GByteArray *output;
+ const guchar *inbuf, *inbuf_end;
+ gsize inbuf_size;
+
+ output = g_byte_array_new ();
+ converter = G_CONVERTER (g_newline_converter_new (to_newline, from_newline));
+ inbuf = g_bytes_get_data (input, &inbuf_size);
+ inbuf_end = inbuf + inbuf_size;
+
+ while (inbuf < inbuf_end)
+ {
+ gsize in_size, out_size, bytes_read, bytes_written;
+ guchar outbuf[MAX_SIZE];
+ GConverterResult res;
+ GError *error = NULL;
+
+ in_size = g_test_rand_int_range (1, MAX_SIZE);
+ in_size = MIN (in_size, inbuf_end - inbuf);
+ out_size = g_test_rand_int_range (1, MAX_SIZE);
+
+ res = g_converter_convert (converter,
+ inbuf,
+ in_size,
+ outbuf,
+ out_size,
+ inbuf + in_size == inbuf_end ? G_CONVERTER_INPUT_AT_END : 0,
+ &bytes_read,
+ &bytes_written,
+ &error);
+ switch (res)
+ {
+ case G_CONVERTER_ERROR:
+ g_assert_nonnull (error);
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT))
+ {
+ g_assert (bytes_read == 0);
+ g_assert (bytes_written == 0);
+ g_clear_error (&error);
+ continue;
+ }
+ /* There should never be any other error, but this check is more informative
+ * than assert_not_reached () */
+ g_assert_no_error (error);
+ break;
+ case G_CONVERTER_CONVERTED:
+ case G_CONVERTER_FINISHED:
+ g_assert_no_error (error);
+ g_assert (bytes_read > 0);
+ g_assert (bytes_written > 0);
+ g_assert (bytes_read <= in_size);
+ g_assert (bytes_written <= out_size);
+ inbuf += bytes_read;
+ g_byte_array_append (output, outbuf, bytes_written);
+ if (res == G_CONVERTER_FINISHED)
+ g_assert (inbuf == inbuf_end);
+ else
+ g_assert (inbuf < inbuf_end);
+ break;
+ case G_CONVERTER_FLUSHED:
+ /* we don't pass FLUSH, so it should never happen */
+ g_assert_not_reached ();
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ }
+
+ return g_byte_array_free_to_bytes (output);
+}
+
+#define assert_bytes_equal(one, two) G_STMT_START{\
+ const char *one_data, *two_data; \
+ gsize one_size, two_size; \
+ one_data = g_bytes_get_data (one, &one_size); \
+ two_data = g_bytes_get_data (two, &two_size); \
+ g_assert_cmpmem (one_data, one_size, two_data, two_size); \
+} G_STMT_END
+
+#define assert_bytes_equal_text(one, two) G_STMT_START{\
+ const char *one_data, *two_data; \
+ char **a, **b; \
+ gsize ai, bi; \
+ one_data = g_bytes_get_data (one, NULL); \
+ two_data = g_bytes_get_data (two, NULL); \
+ a = g_strsplit_set (one_data ? one_data : "", "\r\n", -1); \
+ b = g_strsplit_set (two_data ? two_data : "", "\r\n", -1); \
+ for (ai = bi = 0; a[ai] && b[bi]; ai++) \
+ { \
+ if (*a[ai] == 0) \
+ continue; \
+ for (; b[bi]; bi++) \
+ { \
+ if (*b[bi] == 0) \
+ continue; \
+ } \
+ if (!b[bi]) \
+ break; \
+ g_assert_cmpstr (a[ai], ==, b[bi]); \
+ }\
+ g_strfreev(b);\
+ g_strfreev(a);\
+} G_STMT_END
+
+static void
+test_intermediate (void)
+{
+ GBytes *input, *output1, *output2, *tmp;
+ gsize i;
+ GDataStreamNewlineType target, intermediate;
+
+ for (i = 0; i < N; i++)
+ {
+ target = g_test_rand_int_range (0, 3); /* not including any here */
+ intermediate = g_test_rand_int_range (0, 4); /* can include any */
+
+ input = generate_random_text (TRUE);
+
+ output1 = convert (input, target, G_DATA_STREAM_NEWLINE_TYPE_ANY);
+ tmp = convert (input, intermediate, G_DATA_STREAM_NEWLINE_TYPE_ANY);
+ output2 = convert (tmp, target, intermediate);
+
+ assert_bytes_equal (output1, output2);
+
+ g_bytes_unref (tmp);
+ g_bytes_unref (output2);
+ g_bytes_unref (output1);
+ g_bytes_unref (input);
+ }
+}
+
+static void
+test_conversion_and_back (void)
+{
+ GBytes *input, *output1, *output2, *output3, *tmp;
+ gsize i;
+ GDataStreamNewlineType start, target;
+
+ for (i = 0; i < N; i++)
+ {
+ start = g_test_rand_bit () ? G_DATA_STREAM_NEWLINE_TYPE_CR : G_DATA_STREAM_NEWLINE_TYPE_LF;
+ target = g_test_rand_int_range (0, 3); /* not including any here */
+
+ tmp = generate_random_text (g_test_rand_bit ());
+ /* convert either all CR => LF or all LF => CR */
+ input = convert (tmp, start, start == G_DATA_STREAM_NEWLINE_TYPE_LF ? G_DATA_STREAM_NEWLINE_TYPE_CR :
G_DATA_STREAM_NEWLINE_TYPE_LF);
+ g_bytes_unref (tmp);
+
+ output1 = convert (input, target, start);
+ output2 = convert (output1, start, target);
+ output3 = convert (input, target, G_DATA_STREAM_NEWLINE_TYPE_ANY);
+
+ assert_bytes_equal (output1, output3);
+ assert_bytes_equal (input, output2);
+
+ g_bytes_unref (output3);
+ g_bytes_unref (output2);
+ g_bytes_unref (output1);
+ g_bytes_unref (input);
+ }
+}
+
+static void
+test_simple (void)
+{
+ GBytes *input, *output;
+ gsize i;
+
+ for (i = 0; i < N; i++)
+ {
+ input = generate_random_text (FALSE);
+ output = convert (input, g_test_rand_int_range (0, 4), g_test_rand_int_range (0, 4));
+
+ assert_bytes_equal_text (input, output);
+
+ g_bytes_unref (output);
+ g_bytes_unref (input);
+ }
+}
+
+int
+main (int argc, char *argv[])
+{
+ (g_test_init) (&argc, &argv, NULL);
+ setlocale (LC_ALL, "C");
+
+ g_test_add_func ("/newlineconverter/simple", test_simple);
+ g_test_add_func ("/newlineconverter/intermediate", test_intermediate);
+ g_test_add_func ("/newlineconverter/conversion_and_back", test_conversion_and_back);
+
+ return g_test_run ();
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]