summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorBenjamin Otte <otte@gnome.org>2009-07-01 19:03:19 +0200
committerBenjamin Otte <otte@gnome.org>2009-07-01 19:03:19 +0200
commit2262d76b33094304ece0d0d9cd5920682599a49b (patch)
treec57f89a29fb4d52d81e96521a44b8e44c0a9b9e1 /tests
parent65cc5d895ae125b09f2403761f434fd78ef05af7 (diff)
Move gio tests from gio/tests/ to tests/gio/
This avoids getting tests built every time when working on libgio and running make in the gio/ directory.
Diffstat (limited to 'tests')
-rw-r--r--tests/Makefile.am2
-rw-r--r--tests/gio/.gitignore24
-rw-r--r--tests/gio/Makefile.am119
-rw-r--r--tests/gio/buffered-input-stream.c60
-rw-r--r--tests/gio/contexts.c190
-rw-r--r--tests/gio/data-input-stream.c336
-rw-r--r--tests/gio/data-output-stream.c289
-rw-r--r--tests/gio/desktop-app-info.c259
-rw-r--r--tests/gio/echo-server.c73
-rw-r--r--tests/gio/filter-streams.c239
-rw-r--r--tests/gio/g-file-info.c125
-rw-r--r--tests/gio/g-file.c538
-rw-r--r--tests/gio/g-icon.c245
-rw-r--r--tests/gio/httpd.c183
-rw-r--r--tests/gio/live-g-file.c1211
-rw-r--r--tests/gio/live-g-file.txt27
-rw-r--r--tests/gio/memory-input-stream.c78
-rw-r--r--tests/gio/memory-output-stream.c100
-rw-r--r--tests/gio/readwrite.c293
-rw-r--r--tests/gio/resolver.c506
-rw-r--r--tests/gio/send-data.c163
-rw-r--r--tests/gio/simple-async-result.c107
-rw-r--r--tests/gio/sleepy-stream.c296
-rw-r--r--tests/gio/socket-client.c298
-rw-r--r--tests/gio/socket-server.c308
-rw-r--r--tests/gio/srvtarget.c158
-rw-r--r--tests/gio/unix-streams.c256
27 files changed, 6482 insertions, 1 deletions
diff --git a/tests/Makefile.am b/tests/Makefile.am
index da1397643..162fc4c09 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,6 +1,6 @@
include $(top_srcdir)/Makefile.decl
-SUBDIRS=gobject refcount
+SUBDIRS=gobject refcount gio
AM_CPPFLAGS = \
-I$(top_srcdir) \
diff --git a/tests/gio/.gitignore b/tests/gio/.gitignore
new file mode 100644
index 000000000..b815e877f
--- /dev/null
+++ b/tests/gio/.gitignore
@@ -0,0 +1,24 @@
+buffered-input-stream
+desktop-app-info
+g-icon
+simple-async-result
+unix-streams
+data-input-stream
+data-output-stream
+g-file
+g-file-info
+live-g-file
+memory-input-stream
+memory-output-stream
+filter-streams
+sleepy-stream
+resolver
+connectable
+echo-server
+httpd
+readwrite
+send-data
+socket-client
+socket-server
+srvtarget
+contexts
diff --git a/tests/gio/Makefile.am b/tests/gio/Makefile.am
new file mode 100644
index 000000000..8b5d30bf0
--- /dev/null
+++ b/tests/gio/Makefile.am
@@ -0,0 +1,119 @@
+include $(top_srcdir)/Makefile.decl
+
+INCLUDES = \
+ -g \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/glib \
+ -I$(top_srcdir)/gmodule \
+ -I$(top_srcdir)/gobject \
+ -I$(top_srcdir)/gio \
+ $(GLIB_DEBUG_FLAGS) \
+ -DSRCDIR=\""$(srcdir)"\"
+
+noinst_PROGRAMS = $(TEST_PROGS) $(SAMPLE_PROGS)
+progs_ldadd = \
+ $(top_builddir)/glib/libglib-2.0.la \
+ $(top_builddir)/gobject/libgobject-2.0.la \
+ $(top_builddir)/gio/libgio-2.0.la
+
+
+TEST_PROGS += \
+ memory-input-stream \
+ memory-output-stream \
+ readwrite \
+ g-file \
+ g-file-info \
+ data-input-stream \
+ data-output-stream \
+ g-icon \
+ buffered-input-stream \
+ sleepy-stream \
+ filter-streams \
+ simple-async-result \
+ srvtarget \
+ contexts
+
+SAMPLE_PROGS = resolver socket-server socket-client echo-server httpd send-data
+
+if OS_UNIX
+TEST_PROGS += live-g-file unix-streams desktop-app-info
+endif
+
+memory_input_stream_SOURCES = memory-input-stream.c
+memory_input_stream_LDADD = $(progs_ldadd)
+
+memory_output_stream_SOURCES = memory-output-stream.c
+memory_output_stream_LDADD = $(progs_ldadd)
+
+g_file_SOURCES = g-file.c
+g_file_LDADD = $(progs_ldadd)
+
+readwrite_SOURCES = readwrite.c
+readwrite_LDADD = $(progs_ldadd)
+
+g_file_info_SOURCES = g-file-info.c
+g_file_info_LDADD = $(progs_ldadd)
+
+data_input_stream_SOURCES = data-input-stream.c
+data_input_stream_LDADD = $(progs_ldadd)
+
+data_output_stream_SOURCES = data-output-stream.c
+data_output_stream_LDADD = $(progs_ldadd)
+
+g_icon_SOURCES = g-icon.c
+g_icon_LDADD = $(progs_ldadd)
+
+buffered_input_stream_SOURCES = buffered-input-stream.c
+buffered_input_stream_LDADD = $(progs_ldadd)
+
+live_g_file_SOURCES = live-g-file.c
+live_g_file_LDADD = $(progs_ldadd)
+
+desktop_app_info_SOURCES = desktop-app-info.c
+desktop_app_info_LDADD = $(progs_ldadd)
+
+unix_streams_SOURCES = unix-streams.c
+unix_streams_LDADD = $(progs_ldadd) \
+ $(top_builddir)/gthread/libgthread-2.0.la
+
+simple_async_result_SOURCES = simple-async-result.c
+simple_async_result_LDADD = $(progs_ldadd)
+
+sleepy_stream_SOURCES = sleepy-stream.c
+sleepy_stream_LDADD = $(progs_ldadd)
+
+filter_streams_SOURCES = filter-streams.c
+filter_streams_LDADD = $(progs_ldadd)
+
+resolver_SOURCES = resolver.c
+resolver_LDADD = $(progs_ldadd) \
+ $(top_builddir)/gthread/libgthread-2.0.la
+
+socket_server_SOURCES = socket-server.c
+socket_server_LDADD = $(progs_ldadd) \
+ $(top_builddir)/gthread/libgthread-2.0.la
+
+socket_client_SOURCES = socket-client.c
+socket_client_LDADD = $(progs_ldadd) \
+ $(top_builddir)/gthread/libgthread-2.0.la
+
+echo_server_SOURCES = echo-server.c
+echo_server_LDADD = $(progs_ldadd) \
+ $(top_builddir)/gthread/libgthread-2.0.la
+
+httpd_SOURCES = httpd.c
+httpd_LDADD = $(progs_ldadd) \
+ $(top_builddir)/gthread/libgthread-2.0.la
+
+send_data_SOURCES = send-data.c
+send_data_LDADD = $(progs_ldadd) \
+ $(top_builddir)/gthread/libgthread-2.0.la
+
+srvtarget_SOURCES = srvtarget.c
+srvtarget_LDADD = $(progs_ldadd)
+
+contexts_SOURCES = contexts.c
+contexts_LDADD = $(progs_ldadd) \
+ $(top_builddir)/gthread/libgthread-2.0.la
+
+DISTCLEAN_FILES = applications/mimeinfo.cache
diff --git a/tests/gio/buffered-input-stream.c b/tests/gio/buffered-input-stream.c
new file mode 100644
index 000000000..ceb38b9fb
--- /dev/null
+++ b/tests/gio/buffered-input-stream.c
@@ -0,0 +1,60 @@
+/* GLib testing framework examples and tests
+ * Copyright (C) 2008 Red Hat, Inc.
+ * Authors: Matthias Clasen <mclasen@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>
+
+static void
+test_read_byte (void)
+{
+ GInputStream *base;
+ GInputStream *in;
+
+ g_test_bug ("562393");
+
+ base = g_memory_input_stream_new_from_data ("abcdefghijk", -1, NULL);
+ in = g_buffered_input_stream_new (base);
+
+ g_assert_cmpint (g_buffered_input_stream_read_byte (G_BUFFERED_INPUT_STREAM (in), NULL, NULL), ==, 'a');
+ g_assert_cmpint (g_buffered_input_stream_read_byte (G_BUFFERED_INPUT_STREAM (in), NULL, NULL), ==, 'b');
+ g_assert_cmpint (g_buffered_input_stream_read_byte (G_BUFFERED_INPUT_STREAM (in), NULL, NULL), ==, 'c');
+
+ g_assert_cmpint (g_input_stream_skip (in, 3, NULL, NULL), ==, 3);
+
+ g_assert_cmpint (g_buffered_input_stream_read_byte (G_BUFFERED_INPUT_STREAM (in), NULL, NULL), ==, 'g');
+}
+
+
+int
+main (int argc,
+ char *argv[])
+{
+ g_type_init ();
+ g_test_init (&argc, &argv, NULL);
+ g_test_bug_base ("http://bugzilla.gnome.org/");
+
+ g_test_add_func ("/buffered-input-stream/read-byte", test_read_byte);
+
+ return g_test_run();
+}
diff --git a/tests/gio/contexts.c b/tests/gio/contexts.c
new file mode 100644
index 000000000..3fe16cb1f
--- /dev/null
+++ b/tests/gio/contexts.c
@@ -0,0 +1,190 @@
+#include <gio/gio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define TEST_FILE (SRCDIR "/Makefile.am")
+char *test_file_buffer;
+gsize test_file_size;
+static char async_read_buffer[8192];
+
+static void
+read_data (GObject *source, GAsyncResult *result, gpointer loop)
+{
+ GInputStream *in = G_INPUT_STREAM (source);
+ GError *error = NULL;
+ gssize nread;
+
+ nread = g_input_stream_read_finish (in, result, &error);
+ g_assert_no_error (error);
+
+ g_assert_cmpint (nread, >, 0);
+ g_assert_cmpint (nread, <=, MIN(sizeof (async_read_buffer), test_file_size));
+ g_assert (memcmp (async_read_buffer, test_file_buffer, nread) == 0);
+
+ g_main_loop_quit (loop);
+}
+
+static void
+opened_for_read (GObject *source, GAsyncResult *result, gpointer loop)
+{
+ GFile *file = G_FILE (source);
+ GFileInputStream *in;
+ GError *error = NULL;
+
+ in = g_file_read_finish (file, result, &error);
+ g_assert_no_error (error);
+
+ memset (async_read_buffer, 0, sizeof (async_read_buffer));
+ g_input_stream_read_async (G_INPUT_STREAM (in),
+ async_read_buffer, sizeof (async_read_buffer),
+ G_PRIORITY_DEFAULT, NULL,
+ read_data, loop);
+}
+
+/* Test 1: Async I/O started in a thread with a thread-default context
+ * will stick to that thread, and will complete even if the default
+ * main loop is blocked. (NB: the last part would not be true if we
+ * were testing GFileMonitor!)
+ */
+
+static gboolean idle_start_test1_thread (gpointer loop);
+static gpointer test1_thread (gpointer user_data);
+
+static GCond *test1_cond;
+static GMutex *test1_mutex;
+
+static void
+test_thread_independence (void)
+{
+ GMainLoop *loop;
+
+ test1_cond = g_cond_new ();
+ test1_mutex = g_mutex_new ();
+
+ loop = g_main_loop_new (NULL, FALSE);
+ g_idle_add (idle_start_test1_thread, loop);
+ g_main_loop_run (loop);
+ g_main_loop_unref (loop);
+
+ g_mutex_free (test1_mutex);
+ g_cond_free (test1_cond);
+}
+
+static gboolean
+idle_start_test1_thread (gpointer loop)
+{
+ GTimeVal time;
+ GThread *thread;
+ gboolean io_completed;
+
+ g_mutex_lock (test1_mutex);
+ thread = g_thread_create (test1_thread, NULL, TRUE, NULL);
+
+ g_get_current_time (&time);
+ time.tv_sec += 2;
+ io_completed = g_cond_timed_wait (test1_cond, test1_mutex, &time);
+ g_assert (io_completed);
+ g_thread_join (thread);
+
+ g_mutex_unlock (test1_mutex);
+ g_main_loop_quit (loop);
+ return FALSE;
+}
+
+static gpointer
+test1_thread (gpointer user_data)
+{
+ GMainContext *context;
+ GMainLoop *loop;
+ GFile *file;
+
+ /* Wait for main thread to be waiting on test1_cond */
+ g_mutex_lock (test1_mutex);
+ g_mutex_unlock (test1_mutex);
+
+ context = g_main_context_new ();
+ g_assert (g_main_context_get_thread_default () == NULL);
+ g_main_context_push_thread_default (context);
+ g_assert (g_main_context_get_thread_default () == context);
+
+ file = g_file_new_for_path (TEST_FILE);
+ g_assert (g_file_supports_thread_contexts (file));
+
+ loop = g_main_loop_new (context, FALSE);
+ g_file_read_async (file, G_PRIORITY_DEFAULT, NULL,
+ opened_for_read, loop);
+ g_main_loop_run (loop);
+ g_main_loop_unref (loop);
+
+ g_cond_signal (test1_cond);
+ return NULL;
+}
+
+/* Test 2: If we push a thread-default context in the main thread, we
+ * can run async ops in that context without running the default
+ * context.
+ */
+
+static gboolean test2_fail (gpointer user_data);
+
+static void
+test_context_independence (void)
+{
+ GMainContext *context;
+ GMainLoop *loop;
+ GFile *file;
+ guint default_timeout;
+ GSource *thread_default_timeout;
+
+ context = g_main_context_new ();
+ g_assert (g_main_context_get_thread_default () == NULL);
+ g_main_context_push_thread_default (context);
+ g_assert (g_main_context_get_thread_default () == context);
+
+ file = g_file_new_for_path (TEST_FILE);
+ g_assert (g_file_supports_thread_contexts (file));
+
+ /* Add a timeout to the main loop, to fail immediately if it gets run */
+ default_timeout = g_timeout_add_full (G_PRIORITY_HIGH, 0,
+ test2_fail, NULL, NULL);
+ /* Add a timeout to the alternate loop, to fail if the I/O *doesn't* run */
+ thread_default_timeout = g_timeout_source_new_seconds (2);
+ g_source_set_callback (thread_default_timeout, test2_fail, NULL, NULL);
+ g_source_attach (thread_default_timeout, context);
+
+ loop = g_main_loop_new (context, FALSE);
+ g_file_read_async (file, G_PRIORITY_DEFAULT, NULL,
+ opened_for_read, loop);
+ g_main_loop_run (loop);
+ g_main_loop_unref (loop);
+
+ g_source_remove (default_timeout);
+ g_source_destroy (thread_default_timeout);
+ g_source_unref (thread_default_timeout);
+}
+
+static gboolean
+test2_fail (gpointer user_data)
+{
+ g_assert_not_reached ();
+ return FALSE;
+}
+
+int
+main (int argc, char **argv)
+{
+ GError *error = NULL;
+
+ g_thread_init (NULL);
+ g_type_init ();
+ g_test_init (&argc, &argv, NULL);
+
+ g_file_get_contents (TEST_FILE, &test_file_buffer,
+ &test_file_size, &error);
+ g_assert_no_error (error);
+
+ g_test_add_func ("/gio/contexts/thread-independence", test_thread_independence);
+ g_test_add_func ("/gio/contexts/context-independence", test_context_independence);
+
+ return g_test_run();
+}
diff --git a/tests/gio/data-input-stream.c b/tests/gio/data-input-stream.c
new file mode 100644
index 000000000..368866ebb
--- /dev/null
+++ b/tests/gio/data-input-stream.c
@@ -0,0 +1,336 @@
+/* GLib testing framework examples and tests
+ * Copyright (C) 2008 Red Hat, Inc.
+ * Authors: Tomas Bzatek <tbzatek@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 MAX_LINES 0xFFF
+#define MAX_BYTES 0x10000
+
+static void
+test_seek_to_start (GInputStream *stream)
+{
+ GError *error = NULL;
+ gboolean res = g_seekable_seek (G_SEEKABLE (stream), 0, G_SEEK_SET, NULL, &error);
+ g_assert_cmpint (res, ==, TRUE);
+ g_assert_no_error (error);
+}
+
+static void
+test_read_lines (GDataStreamNewlineType newline_type)
+{
+ GInputStream *stream;
+ GInputStream *base_stream;
+ GError *error = NULL;
+ char *data;
+ int line;
+ const char* lines[MAX_LINES];
+ const char* endl[4] = {"\n", "\r", "\r\n", "\n"};
+
+ /* prepare data */
+ int i;
+ for (i = 0; i < MAX_LINES; i++)
+ lines[i] = "some_text";
+
+ base_stream = g_memory_input_stream_new ();
+ g_assert (base_stream != NULL);
+ stream = G_INPUT_STREAM (g_data_input_stream_new (base_stream));
+ g_assert(stream != NULL);
+
+ /* Byte order testing */
+ g_data_input_stream_set_byte_order (G_DATA_INPUT_STREAM (stream), G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN);
+ g_assert_cmpint (g_data_input_stream_get_byte_order (G_DATA_INPUT_STREAM (stream)), ==, G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN);
+ g_data_input_stream_set_byte_order (G_DATA_INPUT_STREAM (stream), G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN);
+ g_assert_cmpint (g_data_input_stream_get_byte_order (G_DATA_INPUT_STREAM (stream)), ==, G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN);
+
+ /* Line ends testing */
+ g_data_input_stream_set_newline_type (G_DATA_INPUT_STREAM (stream), newline_type);
+ g_assert_cmpint (g_data_input_stream_get_newline_type (G_DATA_INPUT_STREAM (stream)), ==, newline_type);
+
+
+ /* Add sample data */
+ for (i = 0; i < MAX_LINES; i++)
+ g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (base_stream),
+ g_strconcat (lines[i], endl[newline_type], NULL), -1, NULL);
+
+ /* Seek to the start */
+ test_seek_to_start (base_stream);
+
+ /* Test read line */
+ error = NULL;
+ data = (char*)1;
+ line = 0;
+ while (data)
+ {
+ gsize length = -1;
+ data = g_data_input_stream_read_line (G_DATA_INPUT_STREAM (stream), &length, NULL, &error);
+ if (data)
+ {
+ g_assert_cmpstr (data, ==, lines[line]);
+ g_assert_no_error (error);
+ line++;
+ }
+ }
+ g_assert_cmpint (line, ==, MAX_LINES);
+
+
+ g_object_unref (base_stream);
+ g_object_unref (stream);
+}
+
+static void
+test_read_lines_LF (void)
+{
+ test_read_lines (G_DATA_STREAM_NEWLINE_TYPE_LF);
+}
+
+static void
+test_read_lines_CR (void)
+{
+ test_read_lines (G_DATA_STREAM_NEWLINE_TYPE_CR);
+}
+
+static void
+test_read_lines_CR_LF (void)
+{
+ test_read_lines (G_DATA_STREAM_NEWLINE_TYPE_CR_LF);
+}
+
+
+static void
+test_read_until (void)
+{
+ GInputStream *stream;
+ GInputStream *base_stream;
+ GError *error = NULL;
+ char *data;
+ int line;
+ int i;
+
+#define REPEATS 10 /* number of rounds */
+#define DATA_STRING " part1 # part2 $ part3 % part4 ^"
+#define DATA_PART_LEN 7 /* number of characters between separators */
+#define DATA_SEP "#$%^"
+ const int DATA_PARTS_NUM = strlen (DATA_SEP) * REPEATS;
+
+ base_stream = g_memory_input_stream_new ();
+ stream = G_INPUT_STREAM (g_data_input_stream_new (base_stream));
+
+ for (i = 0; i < REPEATS; i++)
+ g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (base_stream), DATA_STRING, -1, NULL);
+
+ /* Test stop characters */
+ error = NULL;
+ data = (char*)1;
+ line = 0;
+ while (data)
+ {
+ gsize length = -1;
+ data = g_data_input_stream_read_until (G_DATA_INPUT_STREAM (stream), DATA_SEP, &length, NULL, &error);
+ if (data)
+ {
+ g_assert_cmpint (strlen (data), ==, DATA_PART_LEN);
+ g_assert_no_error (error);
+ line++;
+ }
+ }
+ g_assert_no_error (error);
+ g_assert_cmpint (line, ==, DATA_PARTS_NUM);
+
+
+ g_object_unref (base_stream);
+ g_object_unref (stream);
+}
+
+enum TestDataType {
+ TEST_DATA_BYTE = 0,
+ TEST_DATA_INT16,
+ TEST_DATA_UINT16,
+ TEST_DATA_INT32,
+ TEST_DATA_UINT32,
+ TEST_DATA_INT64,
+ TEST_DATA_UINT64
+};
+
+#define TEST_DATA_RETYPE_BUFF(a, t, v) \
+ (a == TEST_DATA_BYTE ? (t) *(guchar*)v : \
+ (a == TEST_DATA_INT16 ? (t) *(gint16*)v : \
+ (a == TEST_DATA_UINT16 ? (t) *(guint16*)v : \
+ (a == TEST_DATA_INT32 ? (t) *(gint32*)v : \
+ (a == TEST_DATA_UINT32 ? (t) *(guint32*)v : \
+ (a == TEST_DATA_INT64 ? (t) *(gint64*)v : \
+ (t) *(guint64*)v ))))))
+
+
+static void
+test_data_array (GInputStream *stream, GInputStream *base_stream,
+ gpointer buffer, int len,
+ enum TestDataType data_type, GDataStreamByteOrder byte_order)
+{
+ GError *error = NULL;
+ int pos = 0;
+ int data_size = 1;
+ gint64 data;
+ GDataStreamByteOrder native;
+ gboolean swap;
+
+ /* Seek to start */
+ test_seek_to_start (base_stream);
+
+ /* Set correct data size */
+ switch (data_type)
+ {
+ case TEST_DATA_BYTE:
+ data_size = 1;
+ break;
+ case TEST_DATA_INT16:
+ case TEST_DATA_UINT16:
+ data_size = 2;
+ break;
+ case TEST_DATA_INT32:
+ case TEST_DATA_UINT32:
+ data_size = 4;
+ break;
+ case TEST_DATA_INT64:
+ case TEST_DATA_UINT64:
+ data_size = 8;
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ /* Set flag to swap bytes if needed */
+ native = (G_BYTE_ORDER == G_BIG_ENDIAN) ? G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN : G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN;
+ swap = (byte_order != G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN) && (byte_order != native);
+
+ data = 1;
+ while (data != 0)
+ {
+ switch (data_type)
+ {
+ case TEST_DATA_BYTE:
+ data = g_data_input_stream_read_byte (G_DATA_INPUT_STREAM (stream), NULL, &error);
+ break;
+ case TEST_DATA_INT16:
+ data = g_data_input_stream_read_int16 (G_DATA_INPUT_STREAM (stream), NULL, &error);
+ if (swap)
+ data = (gint16)GUINT16_SWAP_LE_BE((gint16)data);
+ break;
+ case TEST_DATA_UINT16:
+ data = g_data_input_stream_read_uint16 (G_DATA_INPUT_STREAM (stream), NULL, &error);
+ if (swap)
+ data = (guint16)GUINT16_SWAP_LE_BE((guint16)data);
+ break;
+ case TEST_DATA_INT32:
+ data = g_data_input_stream_read_int32 (G_DATA_INPUT_STREAM (stream), NULL, &error);
+ if (swap)
+ data = (gint32)GUINT32_SWAP_LE_BE((gint32)data);
+ break;
+ case TEST_DATA_UINT32:
+ data = g_data_input_stream_read_uint32 (G_DATA_INPUT_STREAM (stream), NULL, &error);
+ if (swap)
+ data = (guint32)GUINT32_SWAP_LE_BE((guint32)data);
+ break;
+ case TEST_DATA_INT64:
+ data = g_data_input_stream_read_int64 (G_DATA_INPUT_STREAM (stream), NULL, &error);
+ if (swap)
+ data = (gint64)GUINT64_SWAP_LE_BE((gint64)data);
+ break;
+ case TEST_DATA_UINT64:
+ data = g_data_input_stream_read_uint64 (G_DATA_INPUT_STREAM (stream), NULL, &error);
+ if (swap)
+ data = (guint64)GUINT64_SWAP_LE_BE((guint64)data);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ if ((data) && (! error))
+ g_assert_cmpint (data, ==, TEST_DATA_RETYPE_BUFF(data_type, gint64, ((guchar*)buffer + pos)));
+
+ pos += data_size;
+ }
+ if (pos < len + 1)
+ g_assert_no_error (error);
+ g_assert_cmpint (pos - data_size, ==, len);
+}
+
+static void
+test_read_int (void)
+{
+ GInputStream *stream;
+ GInputStream *base_stream;
+ GRand *randomizer;
+ int i;
+ gpointer buffer;
+
+ randomizer = g_rand_new ();
+ buffer = g_malloc0 (MAX_BYTES);
+
+ /* Fill in some random data */
+ for (i = 0; i < MAX_BYTES; i++)
+ {
+ guchar x = 0;
+ while (! x)
+ x = (guchar)g_rand_int (randomizer);
+ *(guchar*)((guchar*)buffer + sizeof(guchar) * i) = x;
+ }
+
+ base_stream = g_memory_input_stream_new ();
+ stream = G_INPUT_STREAM (g_data_input_stream_new (base_stream));
+ g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (base_stream), buffer, MAX_BYTES, NULL);
+
+
+ for (i = 0; i < 3; i++)
+ {
+ int j;
+ g_data_input_stream_set_byte_order (G_DATA_INPUT_STREAM (stream), i);
+
+ for (j = 0; j <= TEST_DATA_UINT64; j++)
+ test_data_array (stream, base_stream, buffer, MAX_BYTES, j, i);
+ }
+
+ g_object_unref (base_stream);
+ g_object_unref (stream);
+ g_rand_free (randomizer);
+ g_free (buffer);
+}
+
+
+int
+main (int argc,
+ char *argv[])
+{
+ g_type_init ();
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add_func ("/data-input-stream/read-lines-LF", test_read_lines_LF);
+ g_test_add_func ("/data-input-stream/read-lines-CR", test_read_lines_CR);
+ g_test_add_func ("/data-input-stream/read-lines-CR-LF", test_read_lines_CR_LF);
+ g_test_add_func ("/data-input-stream/read-until", test_read_until);
+ g_test_add_func ("/data-input-stream/read-int", test_read_int);
+
+ return g_test_run();
+}
diff --git a/tests/gio/data-output-stream.c b/tests/gio/data-output-stream.c
new file mode 100644
index 000000000..01723897e
--- /dev/null
+++ b/tests/gio/data-output-stream.c
@@ -0,0 +1,289 @@
+/* GLib testing framework examples and tests
+ * Copyright (C) 2008 Red Hat, Inc.
+ * Authors: Tomas Bzatek <tbzatek@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 MAX_LINES 0xFFF
+#define MAX_LINES_BUFF 0xFFFFFF
+#define MAX_BYTES_BINARY 0x100
+
+static void
+test_read_lines (GDataStreamNewlineType newline_type)
+{
+ GOutputStream *stream;
+ GOutputStream *base_stream;
+ GError *error = NULL;
+ gpointer data;
+ char *lines;
+ int size;
+ int i;
+
+#define TEST_STRING "some_text"
+
+ const char* endl[4] = {"\n", "\r", "\r\n", "\n"};
+
+
+ data = g_malloc0 (MAX_LINES_BUFF);
+ lines = g_malloc0 ((strlen (TEST_STRING) + strlen (endl[newline_type])) * MAX_LINES + 1);
+
+ /* initialize objects */
+ base_stream = g_memory_output_stream_new (data, MAX_LINES_BUFF, NULL, NULL);
+ stream = G_OUTPUT_STREAM (g_data_output_stream_new (base_stream));
+
+
+ /* fill data */
+ for (i = 0; i < MAX_LINES; i++)
+ {
+ gboolean res;
+ char *s = g_strconcat (TEST_STRING, endl[newline_type], NULL);
+ res = g_data_output_stream_put_string (G_DATA_OUTPUT_STREAM (stream), s, NULL, &error);
+ g_stpcpy ((char*)(lines + i*strlen(s)), s);
+ g_assert_no_error (error);
+ g_assert (res == TRUE);
+ }
+
+ /* Byte order testing */
+ g_data_output_stream_set_byte_order (G_DATA_OUTPUT_STREAM (stream), G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN);
+ g_assert_cmpint (g_data_output_stream_get_byte_order (G_DATA_OUTPUT_STREAM (stream)), ==, G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN);
+ g_data_output_stream_set_byte_order (G_DATA_OUTPUT_STREAM (stream), G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN);
+ g_assert_cmpint (g_data_output_stream_get_byte_order (G_DATA_OUTPUT_STREAM (stream)), ==, G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN);
+
+ /* compare data */
+ size = strlen (data);
+ g_assert_cmpint (size, <, MAX_LINES_BUFF);
+ g_assert_cmpstr ((char*)data, ==, lines);
+
+ g_object_unref (base_stream);
+ g_object_unref (stream);
+ g_free (data);
+ g_free (lines);
+}
+
+static void
+test_read_lines_LF (void)
+{
+ test_read_lines (G_DATA_STREAM_NEWLINE_TYPE_LF);
+}
+
+static void
+test_read_lines_CR (void)
+{
+ test_read_lines (G_DATA_STREAM_NEWLINE_TYPE_CR);
+}
+
+static void
+test_read_lines_CR_LF (void)
+{
+ test_read_lines (G_DATA_STREAM_NEWLINE_TYPE_CR_LF);
+}
+
+enum TestDataType {
+ TEST_DATA_BYTE = 0,
+ TEST_DATA_INT16,
+ TEST_DATA_UINT16,
+ TEST_DATA_INT32,
+ TEST_DATA_UINT32,
+ TEST_DATA_INT64,
+ TEST_DATA_UINT64
+};
+
+static void
+test_data_array (guchar *buffer, gsize len,
+ enum TestDataType data_type, GDataStreamByteOrder byte_order)
+{
+ GOutputStream *stream;
+ GOutputStream *base_stream;
+ guchar *stream_data;
+
+ GError *error = NULL;
+ guint pos;
+ GDataStreamByteOrder native;
+ gboolean swap;
+ gboolean res;
+
+ /* create objects */
+ stream_data = g_malloc0 (len);
+ base_stream = g_memory_output_stream_new (stream_data, len, NULL, NULL);
+ stream = G_OUTPUT_STREAM (g_data_output_stream_new (base_stream));
+ g_data_output_stream_set_byte_order (G_DATA_OUTPUT_STREAM (stream), byte_order);
+
+ /* Set flag to swap bytes if needed */
+ native = (G_BYTE_ORDER == G_BIG_ENDIAN) ? G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN : G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN;
+ swap = (byte_order != G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN) && (byte_order != native);
+
+ /* set len to length of buffer cast to actual type */
+ switch (data_type)
+ {
+ case TEST_DATA_BYTE:
+ break;
+ case TEST_DATA_INT16:
+ case TEST_DATA_UINT16:
+ g_assert_cmpint (len % 2, ==, 0);
+ case TEST_DATA_INT32:
+ case TEST_DATA_UINT32:
+ g_assert_cmpint (len % 4, ==, 0);
+ case TEST_DATA_INT64:
+ case TEST_DATA_UINT64:
+ g_assert_cmpint (len % 8, ==, 0);
+ len /= 8;
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ /* Write data to the file */
+ for (pos = 0; pos < len; pos++)
+ {
+ switch (data_type)
+ {
+ case TEST_DATA_BYTE:
+ res = g_data_output_stream_put_byte (G_DATA_OUTPUT_STREAM (stream), buffer[pos], NULL, &error);
+ break;
+ case TEST_DATA_INT16:
+ res = g_data_output_stream_put_int16 (G_DATA_OUTPUT_STREAM (stream), ((gint16 *) buffer)[pos], NULL, &error);
+ break;
+ case TEST_DATA_UINT16:
+ res = g_data_output_stream_put_uint16 (G_DATA_OUTPUT_STREAM (stream), ((guint16 *) buffer)[pos], NULL, &error);
+ break;
+ case TEST_DATA_INT32:
+ res = g_data_output_stream_put_int32 (G_DATA_OUTPUT_STREAM (stream), ((gint32 *) buffer)[pos], NULL, &error);
+ break;
+ case TEST_DATA_UINT32:
+ res = g_data_output_stream_put_uint32 (G_DATA_OUTPUT_STREAM (stream), ((guint32 *) buffer)[pos], NULL, &error);
+ break;
+ case TEST_DATA_INT64:
+ res = g_data_output_stream_put_int64 (G_DATA_OUTPUT_STREAM (stream), ((gint64 *) buffer)[pos], NULL, &error);
+ break;
+ case TEST_DATA_UINT64:
+ res = g_data_output_stream_put_uint64 (G_DATA_OUTPUT_STREAM (stream), ((guint64 *) buffer)[pos], NULL, &error);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ g_assert_no_error (error);
+ g_assert_cmpint (res, ==, TRUE);
+ }
+
+ /* Compare data back */
+ for (pos = 0; pos < len; pos++)
+ {
+ switch (data_type)
+ {
+ case TEST_DATA_BYTE:
+ /* swapping unnecessary */
+ g_assert_cmpint (buffer[pos], ==, stream_data[pos]);
+ break;
+ case TEST_DATA_UINT16:
+ if (swap)
+ g_assert_cmpint (GUINT16_SWAP_LE_BE (((guint16 *) buffer)[pos]), ==, ((guint16 *) stream_data)[pos]);
+ else
+ g_assert_cmpint (((guint16 *) buffer)[pos], ==, ((guint16 *) stream_data)[pos]);
+ break;
+ case TEST_DATA_INT16:
+ if (swap)
+ g_assert_cmpint ((gint16) GUINT16_SWAP_LE_BE (((gint16 *) buffer)[pos]), ==, ((gint16 *) stream_data)[pos]);
+ else
+ g_assert_cmpint (((gint16 *) buffer)[pos], ==, ((gint16 *) stream_data)[pos]);
+ break;
+ case TEST_DATA_UINT32:
+ if (swap)
+ g_assert_cmpint (GUINT32_SWAP_LE_BE (((guint32 *) buffer)[pos]), ==, ((guint32 *) stream_data)[pos]);
+ else
+ g_assert_cmpint (((guint32 *) buffer)[pos], ==, ((guint32 *) stream_data)[pos]);
+ break;
+ case TEST_DATA_INT32:
+ if (swap)
+ g_assert_cmpint ((gint32) GUINT32_SWAP_LE_BE (((gint32 *) buffer)[pos]), ==, ((gint32 *) stream_data)[pos]);
+ else
+ g_assert_cmpint (((gint32 *) buffer)[pos], ==, ((gint32 *) stream_data)[pos]);
+ break;
+ case TEST_DATA_UINT64:
+ if (swap)
+ g_assert_cmpint (GUINT64_SWAP_LE_BE (((guint64 *) buffer)[pos]), ==, ((guint64 *) stream_data)[pos]);
+ else
+ g_assert_cmpint (((guint64 *) buffer)[pos], ==, ((guint64 *) stream_data)[pos]);
+ break;
+ case TEST_DATA_INT64:
+ if (swap)
+ g_assert_cmpint ((gint64) GUINT64_SWAP_LE_BE (((gint64 *) buffer)[pos]), ==, ((gint64 *) stream_data)[pos]);
+ else
+ g_assert_cmpint (((gint64 *) buffer)[pos], ==, ((gint64 *) stream_data)[pos]);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ }
+
+ g_object_unref (base_stream);
+ g_object_unref (stream);
+ g_free (stream_data);
+}
+
+static void
+test_read_int (void)
+{
+ GRand *randomizer;
+ gpointer buffer;
+ int i;
+
+ randomizer = g_rand_new ();
+ buffer = g_malloc0(MAX_BYTES_BINARY);
+
+ /* Fill in some random data */
+ for (i = 0; i < MAX_BYTES_BINARY; i++)
+ {
+ guchar x = 0;
+ while (! x) x = (guchar)g_rand_int (randomizer);
+ *(guchar*)((guchar*)buffer + sizeof (guchar) * i) = x;
+ }
+
+ for (i = 0; i < 3; i++)
+ {
+ int j;
+ for (j = 0; j <= TEST_DATA_UINT64; j++)
+ test_data_array (buffer, MAX_BYTES_BINARY, j, i);
+ }
+
+ g_rand_free (randomizer);
+ g_free (buffer);
+}
+
+int
+main (int argc,
+ char *argv[])
+{
+ g_type_init ();
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add_func ("/data-input-stream/read-lines-LF", test_read_lines_LF);
+ g_test_add_func ("/data-input-stream/read-lines-CR", test_read_lines_CR);
+ g_test_add_func ("/data-input-stream/read-lines-CR-LF", test_read_lines_CR_LF);
+ g_test_add_func ("/data-input-stream/read-int", test_read_int);
+
+ return g_test_run();
+}
diff --git a/tests/gio/desktop-app-info.c b/tests/gio/desktop-app-info.c
new file mode 100644
index 000000000..62ccd03a7
--- /dev/null
+++ b/tests/gio/desktop-app-info.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2008 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Matthias Clasen
+ */
+
+#include <glib/glib.h>
+#include <gio/gio.h>
+#include <gio/gdesktopappinfo.h>
+#include <stdlib.h>
+#include <string.h>
+
+static char *basedir;
+
+static GAppInfo *
+create_app_info (const char *name)
+{
+ GError *error;
+ GAppInfo *info;
+
+ error = NULL;
+ info = g_app_info_create_from_commandline ("/usr/bin/true blah",
+ name,
+ G_APP_INFO_CREATE_NONE,
+ &error);
+ g_assert (error == NULL);
+
+ /* this is necessary to ensure that the info is saved */
+ g_app_info_set_as_default_for_type (info, "application/x-blah", &error);
+ g_assert (error == NULL);
+ g_app_info_remove_supports_type (info, "application/x-blah", &error);
+ g_assert (error == NULL);
+ g_app_info_reset_type_associations ("application/x-blah");
+
+ return info;
+}
+
+static void
+test_delete (void)
+{
+ GAppInfo *info;
+
+ const char *id;
+ char *filename;
+ gboolean res;
+
+ info = create_app_info ("Blah");
+
+ id = g_app_info_get_id (info);
+ g_assert (id != NULL);
+
+ filename = g_build_filename (basedir, "applications", id, NULL);
+
+ res = g_file_test (filename, G_FILE_TEST_EXISTS);
+ g_assert (res);
+
+ res = g_app_info_can_delete (info);
+ g_assert (res);
+
+ res = g_app_info_delete (info);
+ g_assert (res);
+
+ res = g_file_test (filename, G_FILE_TEST_EXISTS);
+ g_assert (!res);
+
+ g_object_unref (info);
+
+ if (g_file_test ("/usr/share/applications/gedit.desktop", G_FILE_TEST_EXISTS))
+ {
+ info = (GAppInfo*)g_desktop_app_info_new ("gedit.desktop");
+ g_assert (info);
+
+ res = g_app_info_can_delete (info);
+ g_assert (!res);
+
+ res = g_app_info_delete (info);
+ g_assert (!res);
+ }
+}
+
+static void
+test_default (void)
+{
+ GAppInfo *info, *info1, *info2, *info3;
+ GList *list;
+ GError *error = NULL;
+
+ info1 = create_app_info ("Blah1");
+ info2 = create_app_info ("Blah2");
+ info3 = create_app_info ("Blah3");
+
+ g_app_info_set_as_default_for_type (info1, "application/x-test", &error);
+ g_assert (error == NULL);
+
+ g_app_info_set_as_default_for_type (info2, "application/x-test", &error);
+ g_assert (error == NULL);
+
+ list = g_app_info_get_all_for_type ("application/x-test");
+ g_assert (g_list_length (list) == 2);
+
+ /* check that both are in the list, info2 before info1 */
+ info = (GAppInfo *)list->data;
+ g_assert (g_strcmp0 (g_app_info_get_id (info), g_app_info_get_id (info2)) == 0);
+
+ info = (GAppInfo *)list->next->data;
+ g_assert (g_strcmp0 (g_app_info_get_id (info), g_app_info_get_id (info1)) == 0);
+
+ g_list_foreach (list, (GFunc)g_object_unref, NULL);
+ g_list_free (list);
+
+ /* now try adding something at the end */
+ g_app_info_add_supports_type (info3, "application/x-test", &error);
+ g_assert (error == NULL);
+
+ list = g_app_info_get_all_for_type ("application/x-test");
+ g_assert (g_list_length (list) == 3);
+
+ /* check that all are in the list, info2, info1, info3 */
+ info = (GAppInfo *)list->data;
+ g_assert (g_strcmp0 (g_app_info_get_id (info), g_app_info_get_id (info2)) == 0);
+
+ info = (GAppInfo *)list->next->data;
+ g_assert (g_strcmp0 (g_app_info_get_id (info), g_app_info_get_id (info1)) == 0);
+
+ info = (GAppInfo *)list->next->next->data;
+ g_assert (g_strcmp0 (g_app_info_get_id (info), g_app_info_get_id (info3)) == 0);
+
+ g_list_foreach (list, (GFunc)g_object_unref, NULL);
+ g_list_free (list);
+
+ /* now remove info1 again */
+ g_app_info_remove_supports_type (info1, "application/x-test", &error);
+ g_assert (error == NULL);
+
+ list = g_app_info_get_all_for_type ("application/x-test");
+ g_assert (g_list_length (list) == 2);
+
+ /* check that both are in the list, info2 before info3 */
+ info = (GAppInfo *)list->data;
+ g_assert (g_strcmp0 (g_app_info_get_id (info), g_app_info_get_id (info2)) == 0);
+
+ info = (GAppInfo *)list->next->data;
+ g_assert (g_strcmp0 (g_app_info_get_id (info), g_app_info_get_id (info3)) == 0);
+
+ g_list_foreach (list, (GFunc)g_object_unref, NULL);
+ g_list_free (list);
+
+ /* now clean it all up */
+ g_app_info_reset_type_associations ("application/x-test");
+
+ list = g_app_info_get_all_for_type ("application/x-test");
+ g_assert (list == NULL);
+
+ g_app_info_delete (info1);
+ g_app_info_delete (info2);
+ g_app_info_delete (info3);
+
+ g_object_unref (info1);
+ g_object_unref (info2);
+}
+
+static void
+cleanup_dir_recurse (GFile *parent, GFile *root)
+{
+ gboolean res;
+ GError *error;
+ GFileEnumerator *enumerator;
+ GFileInfo *info;
+ GFile *descend;
+ char *relative_path;
+
+ g_assert (root != NULL);
+
+ error = NULL;
+ enumerator =
+ g_file_enumerate_children (parent, "*",
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL,
+ &error);
+ if (! enumerator)
+ return;
+ error = NULL;
+ info = g_file_enumerator_next_file (enumerator, NULL, &error);
+ while ((info) && (!error))
+ {
+ descend = g_file_get_child (parent, g_file_info_get_name (info));
+ g_assert (descend != NULL);
+ relative_path = g_file_get_relative_path (root, descend);
+ g_assert (relative_path != NULL);
+
+ if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
+ cleanup_dir_recurse (descend, root);
+
+ error = NULL;
+ res = g_file_delete (descend, NULL, &error);
+ g_assert_cmpint (res, ==, TRUE);
+
+ g_object_unref (descend);
+ error = NULL;
+ info = g_file_enumerator_next_file (enumerator, NULL, &error);
+ }
+ g_assert (error == NULL);
+
+ error = NULL;
+ res = g_file_enumerator_close (enumerator, NULL, &error);
+ g_assert_cmpint (res, ==, TRUE);
+ g_assert (error == NULL);
+}
+
+static void
+cleanup_subdirs (const char *base_dir)
+{
+ GFile *base, *file;
+
+ base = g_file_new_for_path (base_dir);
+ file = g_file_get_child (base, "applications");
+ cleanup_dir_recurse (file, file);
+ g_object_unref (file);
+ file = g_file_get_child (base, "mime");
+ cleanup_dir_recurse (file, file);
+ g_object_unref (file);
+}
+
+int
+main (int argc,
+ char *argv[])
+{
+ gint result;
+
+ g_type_init ();
+ g_test_init (&argc, &argv, NULL);
+
+ basedir = g_get_current_dir ();
+ g_setenv ("XDG_DATA_HOME", basedir, TRUE);
+ cleanup_subdirs (basedir);
+
+ g_test_add_func ("/desktop-app-info/delete", test_delete);
+ g_test_add_func ("/desktop-app-info/default", test_default);
+
+ result = g_test_run ();
+
+ cleanup_subdirs (basedir);
+
+ return result;
+}
diff --git a/tests/gio/echo-server.c b/tests/gio/echo-server.c
new file mode 100644
index 000000000..7e0551098
--- /dev/null
+++ b/tests/gio/echo-server.c
@@ -0,0 +1,73 @@
+#include <gio/gio.h>
+#include <string.h>
+
+#define MESSAGE "Welcome to the echo service!\n"
+
+int port = 7777;
+static GOptionEntry cmd_entries[] = {
+ {"port", 'p', 0, G_OPTION_ARG_INT, &port,
+ "Local port to bind to", NULL},
+ {NULL}
+};
+
+
+static gboolean
+handler (GThreadedSocketService *service,
+ GSocketConnection *connection,
+ GSocketListener *listener,
+ gpointer user_data)
+{
+ GOutputStream *out;
+ GInputStream *in;
+ char buffer[1024];
+ gssize size;
+
+ out = g_io_stream_get_output_stream (G_IO_STREAM (connection));
+ in = g_io_stream_get_input_stream (G_IO_STREAM (connection));
+
+ g_output_stream_write_all (out, MESSAGE, strlen (MESSAGE),
+ NULL, NULL, NULL);
+
+ while (0 < (size = g_input_stream_read (in, buffer,
+ sizeof buffer, NULL, NULL)))
+ g_output_stream_write (out, buffer, size, NULL, NULL);
+
+ return TRUE;
+}
+
+int
+main (int argc, char *argv[])
+{
+ GSocketService *service;
+ GOptionContext *context;
+ GError *error = NULL;
+
+ g_type_init ();
+ g_thread_init (NULL);
+
+ context = g_option_context_new (" - Test GSocket server stuff");
+ g_option_context_add_main_entries (context, cmd_entries, NULL);
+ if (!g_option_context_parse (context, &argc, &argv, &error))
+ {
+ g_printerr ("%s: %s\n", argv[0], error->message);
+ return 1;
+ }
+
+ service = g_threaded_socket_service_new (10);
+
+ if (!g_socket_listener_add_inet_port (G_SOCKET_LISTENER (service),
+ port,
+ NULL,
+ &error))
+ {
+ g_printerr ("%s: %s\n", argv[0], error->message);
+ return 1;
+ }
+
+ g_print ("Echo service listening on port %d\n", port);
+
+ g_signal_connect (service, "run", G_CALLBACK (handler), NULL);
+
+ g_main_loop_run (g_main_loop_new (NULL, FALSE));
+ g_assert_not_reached ();
+}
diff --git a/tests/gio/filter-streams.c b/tests/gio/filter-streams.c
new file mode 100644
index 000000000..fab17ff9f
--- /dev/null
+++ b/tests/gio/filter-streams.c
@@ -0,0 +1,239 @@
+/*
+ * Copyright © 2009 Codethink Limited
+ *
+ * This program 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 of the licence or (at
+ * your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ *
+ * Author: Ryan Lortie <desrt@desrt.ca>
+ */
+
+#include <glib/glib.h>
+#include <gio/gio.h>
+
+static void
+test_input_filter (void)
+{
+ GInputStream *base, *f1, *f2;
+
+ g_test_bug ("568394");
+ base = g_memory_input_stream_new_from_data ("abcdefghijk", -1, NULL);
+ f1 = g_buffered_input_stream_new (base);
+ f2 = g_buffered_input_stream_new (base);
+
+ g_filter_input_stream_set_close_base_stream (G_FILTER_INPUT_STREAM (f1), FALSE);
+
+ g_assert (g_filter_input_stream_get_base_stream (G_FILTER_INPUT_STREAM (f1)) == base);
+ g_assert (g_filter_input_stream_get_base_stream (G_FILTER_INPUT_STREAM (f2)) == base);
+
+ g_assert (!g_input_stream_is_closed (base));
+ g_assert (!g_input_stream_is_closed (f1));
+ g_assert (!g_input_stream_is_closed (f2));
+
+ g_object_unref (f1);
+
+ g_assert (!g_input_stream_is_closed (base));
+ g_assert (!g_input_stream_is_closed (f2));
+
+ g_object_unref (f2);
+
+ g_assert (g_input_stream_is_closed (base));
+
+ g_object_unref (base);
+}
+
+static void
+test_output_filter (void)
+{
+ GOutputStream *base, *f1, *f2;
+
+ base = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
+ f1 = g_buffered_output_stream_new (base);
+ f2 = g_buffered_output_stream_new (base);
+
+ g_filter_output_stream_set_close_base_stream (G_FILTER_OUTPUT_STREAM (f1), FALSE);
+
+ g_assert (g_filter_output_stream_get_base_stream (G_FILTER_OUTPUT_STREAM (f1)) == base);
+ g_assert (g_filter_output_stream_get_base_stream (G_FILTER_OUTPUT_STREAM (f2)) == base);
+
+ g_assert (!g_output_stream_is_closed (base));
+ g_assert (!g_output_stream_is_closed (f1));
+ g_assert (!g_output_stream_is_closed (f2));
+
+ g_object_unref (f1);
+
+ g_assert (!g_output_stream_is_closed (base));
+ g_assert (!g_output_stream_is_closed (f2));
+
+ g_object_unref (f2);
+
+ g_assert (g_output_stream_is_closed (base));
+
+ g_object_unref (base);
+}
+
+gpointer expected_obj;
+gpointer expected_data;
+gboolean callback_happened;
+
+static void
+in_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GError *error = NULL;
+
+ g_assert (object == expected_obj);
+ g_assert (user_data == expected_data);
+ g_assert (callback_happened == FALSE);
+
+ g_input_stream_close_finish (expected_obj, result, &error);
+ g_assert (error == NULL);
+
+ callback_happened = TRUE;
+}
+
+static void
+test_input_async (void)
+{
+ GInputStream *base, *f1, *f2;
+
+ base = g_memory_input_stream_new_from_data ("abcdefghijk", -1, NULL);
+ f1 = g_buffered_input_stream_new (base);
+ f2 = g_buffered_input_stream_new (base);
+
+ g_filter_input_stream_set_close_base_stream (G_FILTER_INPUT_STREAM (f1), FALSE);
+
+ g_assert (g_filter_input_stream_get_base_stream (G_FILTER_INPUT_STREAM (f1)) == base);
+ g_assert (g_filter_input_stream_get_base_stream (G_FILTER_INPUT_STREAM (f2)) == base);
+
+ g_assert (!g_input_stream_is_closed (base));
+ g_assert (!g_input_stream_is_closed (f1));
+ g_assert (!g_input_stream_is_closed (f2));
+
+ expected_obj = f1;
+ expected_data = g_malloc (20);
+ callback_happened = FALSE;
+ g_input_stream_close_async (f1, 0, NULL, in_cb, expected_data);
+
+ g_assert (callback_happened == FALSE);
+ while (g_main_context_pending (NULL))
+ g_main_context_iteration (NULL, FALSE);
+ g_assert (callback_happened == TRUE);
+
+ g_assert (!g_input_stream_is_closed (base));
+ g_assert (!g_input_stream_is_closed (f2));
+ g_free (expected_data);
+ g_object_unref (f1);
+ g_assert (!g_input_stream_is_closed (base));
+ g_assert (!g_input_stream_is_closed (f2));
+
+ expected_obj = f2;
+ expected_data = g_malloc (20);
+ callback_happened = FALSE;
+ g_input_stream_close_async (f2, 0, NULL, in_cb, expected_data);
+
+ g_assert (callback_happened == FALSE);
+ while (g_main_context_pending (NULL))
+ g_main_context_iteration (NULL, FALSE);
+ g_assert (callback_happened == TRUE);
+
+ g_assert (g_input_stream_is_closed (base));
+ g_assert (g_input_stream_is_closed (f2));
+ g_free (expected_data);
+ g_object_unref (f2);
+
+ g_assert (g_input_stream_is_closed (base));
+ g_object_unref (base);
+}
+
+static void
+out_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GError *error = NULL;
+
+ g_assert (object == expected_obj);
+ g_assert (user_data == expected_data);
+ g_assert (callback_happened == FALSE);
+
+ g_output_stream_close_finish (expected_obj, result, &error);
+ g_assert (error == NULL);
+
+ callback_happened = TRUE;
+}
+
+
+static void
+test_output_async (void)
+{
+ GOutputStream *base, *f1, *f2;
+
+ base = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
+ f1 = g_buffered_output_stream_new (base);
+ f2 = g_buffered_output_stream_new (base);
+
+ g_filter_output_stream_set_close_base_stream (G_FILTER_OUTPUT_STREAM (f1), FALSE);
+
+ g_assert (g_filter_output_stream_get_base_stream (G_FILTER_OUTPUT_STREAM (f1)) == base);
+ g_assert (g_filter_output_stream_get_base_stream (G_FILTER_OUTPUT_STREAM (f2)) == base);
+
+ g_assert (!g_output_stream_is_closed (base));
+ g_assert (!g_output_stream_is_closed (f1));
+ g_assert (!g_output_stream_is_closed (f2));
+
+ expected_obj = f1;
+ expected_data = g_malloc (20);
+ callback_happened = FALSE;
+ g_output_stream_close_async (f1, 0, NULL, out_cb, expected_data);
+
+ g_assert (callback_happened == FALSE);
+ while (g_main_context_pending (NULL))
+ g_main_context_iteration (NULL, FALSE);
+ g_assert (callback_happened == TRUE);
+
+ g_assert (!g_output_stream_is_closed (base));
+ g_assert (!g_output_stream_is_closed (f2));
+ g_free (expected_data);
+ g_object_unref (f1);
+ g_assert (!g_output_stream_is_closed (base));
+ g_assert (!g_output_stream_is_closed (f2));
+
+ expected_obj = f2;
+ expected_data = g_malloc (20);
+ callback_happened = FALSE;
+ g_output_stream_close_async (f2, 0, NULL, out_cb, expected_data);
+
+ g_assert (callback_happened == FALSE);
+ while (g_main_context_pending (NULL))
+ g_main_context_iteration (NULL, FALSE);
+ g_assert (callback_happened == TRUE);
+
+ g_assert (g_output_stream_is_closed (base));
+ g_assert (g_output_stream_is_closed (f2));
+ g_free (expected_data);
+ g_object_unref (f2);
+
+ g_assert (g_output_stream_is_closed (base));
+ g_object_unref (base);
+}
+
+
+int
+main (int argc, char **argv)
+{
+ g_test_init (&argc, &argv, NULL);
+ g_test_bug_base ("http://bugzilla.gnome.org/");
+
+ g_type_init ();
+ g_test_add_func ("/filter-stream/input", test_input_filter);
+ g_test_add_func ("/filter-stream/output", test_output_filter);
+ g_test_add_func ("/filter-stream/async-input", test_input_async);
+ g_test_add_func ("/filter-stream/async-output", test_output_async);
+
+ return g_test_run();
+}
diff --git a/tests/gio/g-file-info.c b/tests/gio/g-file-info.c
new file mode 100644
index 000000000..80bdd6e46
--- /dev/null
+++ b/tests/gio/g-file-info.c
@@ -0,0 +1,125 @@
+/* GLib testing framework examples and tests
+ * Copyright (C) 2008 Red Hat, Inc.
+ * Authors: Tomas Bzatek <tbzatek@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 TEST_NAME "Prilis zlutoucky kun"
+#define TEST_DISPLAY_NAME "UTF-8 p\xc5\x99\xc3\xadli\xc5\xa1 \xc5\xbelu\xc5\xa5ou\xc4\x8dk\xc3\xbd k\xc5\xaf\xc5\x88"
+#define TEST_SIZE 0xFFFFFFF0
+
+static void
+test_assigned_values (GFileInfo *info)
+{
+ const char *name, *display_name, *mistake;
+ guint64 size;
+ GFileType type;
+
+ /* Test for attributes presence */
+ g_assert (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_NAME) == TRUE);
+ g_assert (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME) == TRUE);
+ g_assert (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_SIZE) == TRUE);
+ g_assert (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_COPY_NAME) == FALSE);
+
+ /* Retrieve data back and compare */
+
+ name = g_file_info_get_attribute_byte_string (info, G_FILE_ATTRIBUTE_STANDARD_NAME);
+ display_name = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME);
+ mistake = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_COPY_NAME);
+ size = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_STANDARD_SIZE);
+ type = g_file_info_get_file_type (info);
+
+ g_assert_cmpstr (name, ==, TEST_NAME);
+ g_assert_cmpstr (display_name, ==, TEST_DISPLAY_NAME);
+ g_assert (mistake == NULL);
+ g_assert_cmpint (size, ==, TEST_SIZE);
+ g_assert_cmpstr (name, ==, g_file_info_get_name (info));
+ g_assert_cmpstr (display_name, ==, g_file_info_get_display_name (info));
+ g_assert_cmpint (size, ==, g_file_info_get_size (info) );
+ g_assert_cmpint (type, ==, G_FILE_TYPE_DIRECTORY);
+}
+
+
+
+static void
+test_g_file_info (void)
+{
+ GFileInfo *info;
+ GFileInfo *info_dup;
+ GFileInfo *info_copy;
+ char **attr_list;
+
+ info = g_file_info_new ();
+
+ /* Test for empty instance */
+ attr_list = g_file_info_list_attributes (info, NULL);
+ g_assert (attr_list != NULL);
+ g_assert (*attr_list == NULL);
+
+ g_file_info_set_attribute_byte_string (info, G_FILE_ATTRIBUTE_STANDARD_NAME, TEST_NAME);
+ g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME, TEST_DISPLAY_NAME);
+ g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_STANDARD_SIZE, TEST_SIZE);
+ g_file_info_set_file_type (info, G_FILE_TYPE_DIRECTORY);
+
+ /* The attr list should not be empty now */
+ attr_list = g_file_info_list_attributes (info, NULL);
+ g_assert (attr_list != NULL);
+ g_assert (*attr_list != NULL);
+
+ test_assigned_values (info);
+
+ /* Test dups */
+ info_dup = g_file_info_dup (info);
+ g_assert (info_dup != NULL);
+ test_assigned_values (info_dup);
+
+ info_copy = g_file_info_new ();
+ g_file_info_copy_into (info_dup, info_copy);
+ g_assert (info_copy != NULL);
+ test_assigned_values (info_copy);
+
+ /* Test remove attribute */
+ g_assert (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_SORT_ORDER) == FALSE);
+ g_file_info_set_attribute_int32 (info, G_FILE_ATTRIBUTE_STANDARD_SORT_ORDER, 10);
+ g_assert (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_SORT_ORDER) == TRUE);
+
+ g_file_info_remove_attribute (info, G_FILE_ATTRIBUTE_STANDARD_SORT_ORDER);
+ g_assert (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_SORT_ORDER) == FALSE);
+
+ g_object_unref (info);
+ g_object_unref (info_dup);
+ g_object_unref (info_copy);
+}
+
+int
+main (int argc,
+ char *argv[])
+{
+ g_type_init ();
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add_func ("/g-file-info/test_g_file_info", test_g_file_info);
+
+ return g_test_run();
+}
diff --git a/tests/gio/g-file.c b/tests/gio/g-file.c
new file mode 100644
index 000000000..8bba592aa
--- /dev/null
+++ b/tests/gio/g-file.c
@@ -0,0 +1,538 @@
+/* GLib testing framework examples and tests
+ * Copyright (C) 2008 Red Hat, Inc.
+ * Authors: Tomas Bzatek <tbzatek@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>
+
+struct TestPathsWithOper {
+ const char *path1;
+ gboolean equal;
+ gboolean use_uri;
+ const char *path2;
+ const char *path3;
+};
+
+
+
+/* TODO:
+ * - test on Windows
+ *
+ **/
+
+static void
+test_g_file_new_null (void)
+{
+ const char *paths[] = {"/",
+ "/tmp///",
+ "/non-existent-file",
+ "/UTF-8 p\xc5\x99\xc3\xadli\xc5\xa1 \xc5\xbelu\xc5\xa5ou\xc4\x8dk\xc3\xbd k\xc5\xaf\xc5\x88",
+ NULL
+ };
+ const char *uris[] = {"file:///",
+ "file:///tmp///",
+ "non-existent-uri:///some-dir/",
+ "file:///UTF-8%20p%C5%99%C3%ADli%C5%A1%20%C5%BElu%C5%A5ou%C4%8Dk%C3%BD%20k%C5%AF%C5%88",
+ NULL
+ };
+
+ GFile *file = NULL;
+
+ int i = 0;
+ while (paths[i])
+ {
+ file = g_file_new_for_path (paths[i++]);
+ g_assert (file != NULL);
+ g_object_unref (file);
+ }
+
+ i = 0;
+ while (uris[i])
+ {
+ file = g_file_new_for_uri (uris[i++]);
+ g_assert (file != NULL);
+ g_object_unref(file);
+ }
+}
+
+
+
+static gboolean
+compare_two_files (const gboolean use_uri, const char *path1, const char *path2)
+{
+ GFile *file1 = NULL;
+ GFile *file2 = NULL;
+ gboolean equal;
+
+ if (use_uri)
+ {
+ file1 = g_file_new_for_uri (path1);
+ file2 = g_file_new_for_uri (path2);
+ }
+ else
+ {
+ file1 = g_file_new_for_path (path1);
+ file2 = g_file_new_for_path (path2);
+ }
+
+ g_assert (file1 != NULL);
+ g_assert (file2 != NULL);
+
+ equal = g_file_equal (file1, file2);
+
+ g_object_unref (file1);
+ g_object_unref (file2);
+
+ return equal;
+}
+
+static void
+test_g_file_new_for_path (void)
+{
+ const struct TestPathsWithOper cmp_paths[] =
+ {
+ {"/", TRUE, 0, "/./"},
+ {"//", TRUE, 0, "//"},
+ {"//", TRUE, 0, "//./"},
+ {"/", TRUE, 0, "/.//"},
+ {"/", TRUE, 0, "/././"},
+ {"/tmp", TRUE, 0, "/tmp/d/../"},
+ {"/", TRUE, 0, "/somedir/../"},
+ {"/", FALSE, 0, "/somedir/.../"},
+ {"//tmp/dir1", TRUE, 0, "//tmp/dir1"},
+ {"/tmp/dir1", TRUE, 0, "///tmp/dir1"},
+ {"/tmp/dir1", TRUE, 0, "////tmp/dir1"},
+ {"/tmp/dir1", TRUE, 0, "/tmp/./dir1"},
+ {"/tmp/dir1", TRUE, 0, "/tmp//dir1"},
+ {"/tmp/dir1", TRUE, 0, "/tmp///dir1///"},
+ {"/UTF-8 p\xc5\x99\xc3\xadli\xc5\xa1 \xc5\xbelu\xc5\xa5ou\xc4\x8dk\xc3\xbd k\xc5\xaf\xc5\x88", TRUE, 0, "/UTF-8 p\xc5\x99\xc3\xadli\xc5\xa1 \xc5\xbelu\xc5\xa5ou\xc4\x8dk\xc3\xbd k\xc5\xaf\xc5\x88/"}
+ };
+
+ guint i;
+ for (i = 0; i < G_N_ELEMENTS (cmp_paths); i++)
+ {
+ gboolean equal = compare_two_files (FALSE, cmp_paths[i].path1, cmp_paths[i].path2);
+ g_assert_cmpint (equal, ==, cmp_paths[i].equal);
+ }
+}
+
+
+
+static void
+test_g_file_new_for_uri (void)
+{
+ const struct TestPathsWithOper cmp_uris[] = {
+ {"file:///", TRUE, 0, "file:///./"},
+ {"file:////", TRUE, 0, "file:////"},
+ {"file:////", TRUE, 0, "file:////./"},
+ {"file:///", TRUE, 0, "file:///.//"},
+ {"file:///", TRUE, 0, "file:///././"},
+ {"file:///tmp", TRUE, 0, "file:///tmp/d/../"},
+ {"file:///", TRUE, 0, "file:///somedir/../"},
+ {"file:///", FALSE, 0, "file:///somedir/.../"},
+ {"file:////tmp/dir1", TRUE, 0, "file:////tmp/dir1"},
+ {"file:///tmp/dir1", TRUE, 0, "file:///tmp/./dir1"},
+ {"file:///tmp/dir1", TRUE, 0, "file:///tmp//dir1"},
+ {"file:///tmp/dir1", TRUE, 0, "file:///tmp///dir1///"},
+ {"file:///UTF-8%20p%C5%99%C3%ADli%C5%A1%20%C5%BElu%C5%A5ou%C4%8Dk%C3%BD%20k%C5%AF%C5%88", TRUE, 0, "file:///UTF-8%20p%C5%99%C3%ADli%C5%A1%20%C5%BElu%C5%A5ou%C4%8Dk%C3%BD%20k%C5%AF%C5%88/"}
+ };
+
+ guint i;
+ for (i = 0; i < G_N_ELEMENTS (cmp_uris); i++)
+ {
+ gboolean equal = compare_two_files (TRUE, cmp_uris[i].path1, cmp_uris[i].path2);
+ g_assert_cmpint (equal, ==, cmp_uris[i].equal);
+ }
+}
+
+
+
+static gboolean
+dup_equals (const gboolean use_uri, const char *path)
+{
+ GFile *file1 = NULL;
+ GFile *file2 = NULL;
+ gboolean equal;
+
+ if (use_uri)
+ file1 = g_file_new_for_uri (path);
+ else
+ file1 = g_file_new_for_path (path);
+
+ g_assert (file1 != NULL);
+
+ file2 = g_file_dup (file1);
+
+ g_assert (file2 != NULL);
+
+ equal = g_file_equal (file1, file2);
+
+ g_object_unref (file1);
+ g_object_unref (file2);
+
+ return equal;
+}
+
+static void
+test_g_file_dup (void)
+{
+ const struct TestPathsWithOper dup_paths[] =
+ {
+ {"/", 0, FALSE, ""},
+ {"file:///", 0, TRUE, ""},
+ {"totalnonsense", 0, FALSE, ""},
+ {"/UTF-8 p\xc5\x99\xc3\xadli\xc5\xa1 \xc5\xbelu\xc5\xa5ou\xc4\x8dk\xc3\xbd k\xc5\xaf\xc5\x88", 0, FALSE, ""},
+ {"file:///UTF-8%20p%C5%99%C3%ADli%C5%A1%20%C5%BElu%C5%A5ou%C4%8Dk%C3%BD%20k%C5%AF%C5%88", 0, TRUE, ""},
+ };
+
+ guint i;
+ for (i = 0; i < G_N_ELEMENTS (dup_paths); i++)
+ {
+ gboolean equal = dup_equals (dup_paths[i].use_uri, dup_paths[i].path1);
+ g_assert (equal == TRUE);
+ }
+}
+
+
+
+static gboolean
+parse_check_utf8 (const gboolean use_uri, const char *path, const char *result_parse_name)
+{
+ GFile *file1 = NULL;
+ GFile *file2 = NULL;
+ char *parsed_name;
+ gboolean is_utf8_valid;
+ gboolean equal;
+
+ if (use_uri)
+ file1 = g_file_new_for_uri (path);
+ else
+ file1 = g_file_new_for_path (path);
+
+ g_assert (file1 != NULL);
+
+ parsed_name = g_file_get_parse_name (file1);
+
+ g_assert (parsed_name != NULL);
+
+ /* UTF-8 validation */
+ is_utf8_valid = g_utf8_validate (parsed_name, -1, NULL);
+ g_assert (is_utf8_valid == TRUE);
+
+ if (result_parse_name)
+ g_assert_cmpstr (parsed_name, ==, result_parse_name);
+
+ file2 = g_file_parse_name (parsed_name);
+
+ g_assert (file2 != NULL);
+
+ equal = g_file_equal (file1, file2);
+
+ g_object_unref (file1);
+ g_object_unref (file2);
+
+ g_free (parsed_name);
+
+ return equal;
+}
+
+static void
+test_g_file_get_parse_name_utf8 (void)
+{
+ const struct TestPathsWithOper strings[] =
+ {
+ {"/", 0, FALSE, "/"},
+ {"file:///", 0, TRUE, "/"},
+ {"totalnonsense", 0, FALSE, NULL},
+ {"/UTF-8 p\xc5\x99\xc3\xadli\xc5\xa1 \xc5\xbelu\xc5\xa5ou\xc4\x8dk\xc3\xbd k\xc5\xaf\xc5\x88", 0, FALSE, NULL /* Depends on local file encoding */},
+ {"file:///invalid%08/UTF-8%20p%C5%99%C3%ADli%C5%A1%20%C5%BElu%C5%A5ou%C4%8Dk%C3%BD%20k%C5%AF%C5%88/", 0, TRUE, "file:///invalid%08/UTF-8%20p\xc5\x99\xc3\xadli\xc5\xa1%20\xc5\xbelu\xc5\xa5ou\xc4\x8dk\xc3\xbd%20k\xc5\xaf\xc5\x88"},
+ };
+
+ guint i;
+ for (i = 0; i < G_N_ELEMENTS (strings); i++)
+ {
+ gboolean equal = parse_check_utf8 (strings[i].use_uri, strings[i].path1, strings[i].path2);
+ g_assert (equal == TRUE);
+ }
+}
+
+static char *
+resolve_arg (const gboolean is_uri_only, const char *arg)
+{
+ GFile *file1 = NULL;
+ char *uri = NULL;
+ char *path = NULL;
+ char *s = NULL;
+
+ file1 = g_file_new_for_commandline_arg (arg);
+ g_assert (file1 != NULL);
+
+ /* Test if we get URI string */
+ uri = g_file_get_uri (file1);
+ g_assert_cmpstr (uri, !=, NULL);
+ g_print ("%s\n",uri);
+
+ /* Test if we get correct value of the local path */
+ path = g_file_get_path (file1);
+ if (is_uri_only)
+ g_assert_cmpstr (path, ==, NULL);
+ else
+ g_assert (g_path_is_absolute (path) == TRUE);
+
+ /* Get the URI scheme and compare it with expected one */
+ s = g_file_get_uri_scheme (file1);
+
+ g_object_unref (file1);
+ g_free (uri);
+ g_free (path);
+
+ return s;
+}
+
+static void
+test_g_file_new_for_commandline_arg (void)
+{
+ /* TestPathsWithOper.use_uri represents IsURIOnly here */
+ const struct TestPathsWithOper arg_data[] =
+ {
+ {"./", 0, FALSE, "file"},
+ {"../", 0, FALSE, "file"},
+ {"/tmp", 0, FALSE, "file"},
+ {"//UTF-8 p\xc5\x99\xc3\xadli\xc5\xa1 \xc5\xbelu\xc5\xa5ou\xc4\x8dk\xc3\xbd k\xc5\xaf\xc5\x88", 0, FALSE, "file"},
+ {"file:///UTF-8%20p%C5%99%C3%ADli%C5%A1%20%C5%BElu%C5%A5ou%C4%8Dk%C3%BD%20k%C5%AF%C5%88/", 0, FALSE, "file"},
+#if 0
+ {"http://www.gtk.org/", 0, TRUE, "http"},
+ {"ftp://user:pass@ftp.gimp.org/", 0, TRUE, "ftp"},
+#endif
+ };
+ GFile *file;
+ char *resolved;
+ char *cwd;
+ guint i;
+
+ for (i = 0; i < G_N_ELEMENTS (arg_data); i++)
+ {
+ char *s = resolve_arg (arg_data[i].use_uri, arg_data[i].path1);
+ g_assert_cmpstr (s, ==, arg_data[i].path2);
+ g_free (s);
+ }
+
+ /* Manual test for getting correct cwd */
+ file = g_file_new_for_commandline_arg ("./");
+ resolved = g_file_get_path (file);
+ cwd = g_get_current_dir ();
+ g_assert_cmpstr (resolved, ==, cwd);
+ g_object_unref (file);
+ g_free (resolved);
+ g_free (cwd);
+}
+
+static char*
+get_relative_path (const gboolean use_uri, const gboolean should_have_prefix, const char *dir1, const char *dir2)
+{
+ GFile *file1 = NULL;
+ GFile *file2 = NULL;
+ GFile *file3 = NULL;
+ gboolean has_prefix = FALSE;
+ char *relative_path = NULL;
+
+ if (use_uri)
+ {
+ file1 = g_file_new_for_uri (dir1);
+ file2 = g_file_new_for_uri (dir2);
+ }
+ else
+ {
+ file1 = g_file_new_for_path (dir1);
+ file2 = g_file_new_for_path (dir2);
+ }
+
+ g_assert (file1 != NULL);
+ g_assert (file2 != NULL);
+
+ has_prefix = g_file_has_prefix (file2, file1);
+ g_print ("%s %s\n", dir1, dir2);
+ g_assert (has_prefix == should_have_prefix);
+
+ relative_path = g_file_get_relative_path (file1, file2);
+ if (should_have_prefix)
+ {
+ g_assert (relative_path != NULL);
+
+ file3 = g_file_resolve_relative_path (file1, relative_path);
+ g_assert (g_file_equal (file2, file3) == TRUE);
+ }
+
+ if (file1)
+ g_object_unref (file1);
+ if (file2)
+ g_object_unref (file2);
+ if (file3)
+ g_object_unref (file3);
+
+ return relative_path;
+}
+
+static void
+test_g_file_has_prefix (void)
+{
+ /* TestPathsWithOper.equal represents here if the dir belongs to the directory structure */
+ const struct TestPathsWithOper dirs[] =
+ {
+ /* path1 equal uri path2 path3 */
+ {"/dir1", TRUE, FALSE, "/dir1/dir2/dir3/", "dir2/dir3"},
+ {"/dir1/", TRUE, FALSE, "/dir1/dir2/dir3/", "dir2/dir3"},
+ {"/dir1", TRUE, FALSE, "/dir1/dir2/dir3", "dir2/dir3"},
+ {"/dir1/", TRUE, FALSE, "/dir1/dir2/dir3", "dir2/dir3"},
+ {"/tmp/", FALSE, FALSE, "/something/", NULL},
+ {"/dir1/dir2", FALSE, FALSE, "/dir1/", NULL},
+ {"//dir1/new", TRUE, FALSE, "//dir1/new/dir2/dir3", "dir2/dir3"},
+ {"/dir/UTF-8 p\xc5\x99\xc3\xadli\xc5\xa1 \xc5\xbelu\xc5\xa5ou\xc4\x8dk\xc3\xbd k\xc5\xaf\xc5\x88", TRUE, FALSE, "/dir/UTF-8 p\xc5\x99\xc3\xadli\xc5\xa1 \xc5\xbelu\xc5\xa5ou\xc4\x8dk\xc3\xbd k\xc5\xaf\xc5\x88/dir2", "dir2"},
+ {"file:///dir1", TRUE, TRUE, "file:///dir1/dir2/dir3/", "dir2/dir3"},
+ {"file:///dir1/", TRUE, TRUE, "file:///dir1/dir2/dir3/", "dir2/dir3"},
+ {"file:///dir1", TRUE, TRUE, "file:///dir1/dir2/dir3", "dir2/dir3"},
+ {"file:///dir1/", TRUE, TRUE, "file:///dir1/dir2/dir3", "dir2/dir3"},
+ {"file:///tmp/", FALSE, TRUE, "file:///something/", NULL},
+ {"file:///dir1/dir2", FALSE, TRUE, "file:///dir1/", NULL},
+ {"file:////dir1/new", TRUE, TRUE, "file:////dir1/new/dir2/dir3", "dir2/dir3"},
+ {"file:///dir/UTF-8%20p%C5%99%C3%ADli%C5%A1%20%C5%BElu%C5%A5ou%C4%8Dk%C3%BD%20k%C5%AF%C5%88", TRUE, TRUE, "file:///dir/UTF-8%20p%C5%99%C3%ADli%C5%A1%20%C5%BElu%C5%A5ou%C4%8Dk%C3%BD%20k%C5%AF%C5%88/dir2", "dir2"},
+#if 0
+ {"dav://www.gtk.org/plan/", TRUE, TRUE, "dav://www.gtk.org/plan/meetings/20071218.txt", "meetings/20071218.txt"},
+ {"dav://www.gtk.org/plan/meetings", TRUE, TRUE, "dav://www.gtk.org/plan/meetings/20071218.txt", "20071218.txt"},
+#endif
+ };
+
+ guint i;
+ for (i = 0; i < G_N_ELEMENTS (dirs); i++)
+ {
+ char *s = get_relative_path (dirs[i].use_uri, dirs[i].equal, dirs[i].path1, dirs[i].path2);
+ if (dirs[i].equal)
+ g_assert_cmpstr (s, ==, dirs[i].path3);
+ g_free (s);
+ }
+}
+
+static void
+roundtrip_parent_child (const gboolean use_uri, const gboolean under_root_descending,
+ const char *path, const char *dir_holder)
+{
+ GFile *files[6] = {NULL};
+ guint i;
+
+ if (use_uri)
+ {
+ files[0] = g_file_new_for_uri (path);
+ files[1] = g_file_new_for_uri (path);
+ }
+ else
+ {
+ files[0] = g_file_new_for_path (path);
+ files[1] = g_file_new_for_path (path);
+ }
+
+ g_assert (files[0] != NULL);
+ g_assert (files[1] != NULL);
+
+ files[2] = g_file_get_child (files[1], dir_holder);
+ g_assert (files[2] != NULL);
+
+ files[3] = g_file_get_parent (files[2]);
+ g_assert (files[3] != NULL);
+ g_assert (g_file_equal (files[3], files[0]) == TRUE);
+
+ files[4] = g_file_get_parent (files[3]);
+ /* Don't go lower beyond the root */
+ if (under_root_descending)
+ g_assert (files[4] == NULL);
+ else
+ {
+ g_assert (files[4] != NULL);
+
+ files[5] = g_file_get_child (files[4], dir_holder);
+ g_assert (files[5] != NULL);
+ g_assert (g_file_equal (files[5], files[0]) == TRUE);
+ }
+
+ for (i = 0; i < G_N_ELEMENTS (files); i++)
+ {
+ if (files[i])
+ g_object_unref (files[i]);
+ }
+}
+
+static void
+test_g_file_get_parent_child (void)
+{
+ const struct TestPathsWithOper paths[] =
+ {
+ /* path root_desc uri dir_holder */
+ {"/dir1/dir", FALSE, FALSE, "dir"},
+ {"/dir", FALSE, FALSE, "dir"},
+ {"/", TRUE, FALSE, "dir"},
+ {"/UTF-8 p\xc5\x99\xc3\xadli\xc5\xa1 \xc5\xbelu\xc5\xa5ou\xc4\x8dk\xc3\xbd k\xc5\xaf\xc5\x88/", FALSE, FALSE, "UTF-8 p\xc5\x99\xc3\xadli\xc5\xa1 \xc5\xbelu\xc5\xa5ou\xc4\x8dk\xc3\xbd k\xc5\xaf\xc5\x88"},
+ {"file:///dir1/dir", FALSE, TRUE, "dir"},
+ {"file:///dir", FALSE, TRUE, "dir"},
+ {"file:///", TRUE, TRUE, "dir"},
+ {"file:///UTF-8%20p%C5%99%C3%ADli%C5%A1%20%C5%BElu%C5%A5ou%C4%8Dk%C3%BD%20k%C5%AF%C5%88/", FALSE, TRUE, "UTF-8 p\xc5\x99\xc3\xadli\xc5\xa1 \xc5\xbelu\xc5\xa5ou\xc4\x8dk\xc3\xbd k\xc5\xaf\xc5\x88"},
+ {"dav://www.gtk.org/plan/meetings", FALSE, TRUE, "meetings"},
+ };
+
+ guint i;
+ for (i = 0; i < G_N_ELEMENTS (paths); i++)
+ roundtrip_parent_child (paths[i].use_uri, paths[i].equal, paths[i].path1, paths[i].path2);
+}
+
+int
+main (int argc,
+ char *argv[])
+{
+ g_type_init ();
+ g_test_init (&argc, &argv, NULL);
+
+
+ /* Testing whether g_file_new_for_path() or g_file_new_for_uri() always returns non-NULL result */
+ g_test_add_func ("/g-file/test_g_file_new_null", test_g_file_new_null);
+
+ /* Testing whether the g_file_new_for_path() correctly canonicalizes strings and two files equals (g_file_equal()) */
+ g_test_add_func ("/g-file/test_g_file_new_for_path", test_g_file_new_for_path);
+
+ /* Testing whether the g_file_new_for_uri() correctly canonicalizes strings and two files equals (g_file_equal()) */
+ g_test_add_func ("/g-file/test_g_file_new_for_uri", test_g_file_new_for_uri);
+
+ /* Testing g_file_dup() equals original file via g_file_equal() */
+ g_test_add_func ("/g-file/test_g_file_dup", test_g_file_dup);
+
+ /* Testing g_file_get_parse_name() to return correct UTF-8 string */
+ g_test_add_func ("/g-file/test_g_file_get_parse_name_utf8", test_g_file_get_parse_name_utf8);
+
+ /* Testing g_file_new_for_commandline_arg() for correct relavive path resolution and correct path/URI guess */
+ g_test_add_func ("/g-file/test_g_file_new_for_commandline_arg", test_g_file_new_for_commandline_arg);
+
+ /* Testing g_file_has_prefix(), g_file_get_relative_path() and g_file_resolve_relative_path() to return and process correct relative paths */
+ g_test_add_func ("/g-file/test_g_file_has_prefix", test_g_file_has_prefix);
+
+ /* Testing g_file_get_parent() and g_file_get_child() */
+ g_test_add_func ("/g-file/test_g_file_get_parent_child", test_g_file_get_parent_child);
+
+ return g_test_run();
+}
diff --git a/tests/gio/g-icon.c b/tests/gio/g-icon.c
new file mode 100644
index 000000000..5fe457134
--- /dev/null
+++ b/tests/gio/g-icon.c
@@ -0,0 +1,245 @@
+/* GLib testing framework examples and tests
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * 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.
+ *
+ * Authors: David Zeuthen <davidz@redhat.com>
+ */
+
+#include <glib/glib.h>
+#include <gio/gio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static void
+test_g_icon_serialize (void)
+{
+ GIcon *icon;
+ GIcon *icon2;
+ GIcon *icon3;
+ GIcon *icon4;
+ GIcon *icon5;
+ GEmblem *emblem1;
+ GEmblem *emblem2;
+ const char *uri;
+ GFile *location;
+ char *data;
+ GError *error;
+
+ error = NULL;
+
+ /* check that GFileIcon and GThemedIcon serialize to the encoding specified */
+
+ uri = "file:///some/native/path/to/an/icon.png";
+ location = g_file_new_for_uri (uri);
+ icon = g_file_icon_new (location);
+ data = g_icon_to_string (icon);
+ g_assert_cmpstr (data, ==, "/some/native/path/to/an/icon.png");
+ icon2 = g_icon_new_for_string (data, &error);
+ g_assert_no_error (error);
+ g_assert (g_icon_equal (icon, icon2));
+ g_free (data);
+ g_object_unref (icon);
+ g_object_unref (icon2);
+ g_object_unref (location);
+
+ uri = "file:///some/native/path/to/an/icon with spaces.png";
+ location = g_file_new_for_uri (uri);
+ icon = g_file_icon_new (location);
+ data = g_icon_to_string (icon);
+ g_assert_cmpstr (data, ==, "/some/native/path/to/an/icon with spaces.png");
+ icon2 = g_icon_new_for_string (data, &error);
+ g_assert_no_error (error);
+ g_assert (g_icon_equal (icon, icon2));
+ g_free (data);
+ g_object_unref (icon);
+ g_object_unref (icon2);
+ g_object_unref (location);
+
+ uri = "sftp:///some/non-native/path/to/an/icon.png";
+ location = g_file_new_for_uri (uri);
+ icon = g_file_icon_new (location);
+ data = g_icon_to_string (icon);
+ g_assert_cmpstr (data, ==, "sftp:///some/non-native/path/to/an/icon.png");
+ icon2 = g_icon_new_for_string (data, &error);
+ g_assert_no_error (error);
+ g_assert (g_icon_equal (icon, icon2));
+ g_free (data);
+ g_object_unref (icon);
+ g_object_unref (icon2);
+ g_object_unref (location);
+
+#if 0
+ uri = "sftp:///some/non-native/path/to/an/icon with spaces.png";
+ location = g_file_new_for_uri (uri);
+ icon = g_file_icon_new (location);
+ data = g_icon_to_string (icon);
+ g_assert_cmpstr (data, ==, "sftp:///some/non-native/path/to/an/icon%20with%20spaces.png");
+ icon2 = g_icon_new_for_string (data, &error);
+ g_assert_no_error (error);
+ g_assert (g_icon_equal (icon, icon2));
+ g_free (data);
+ g_object_unref (icon);
+ g_object_unref (icon2);
+ g_object_unref (location);
+#endif
+
+ icon = g_themed_icon_new ("network-server");
+ data = g_icon_to_string (icon);
+ g_assert_cmpstr (data, ==, "network-server");
+ icon2 = g_icon_new_for_string (data, &error);
+ g_assert_no_error (error);
+ g_assert (g_icon_equal (icon, icon2));
+ g_free (data);
+ g_object_unref (icon);
+ g_object_unref (icon2);
+
+ /* Check that we can serialize from well-known specified formats */
+ icon = g_icon_new_for_string ("network-server%", &error);
+ g_assert_no_error (error);
+ icon2 = g_themed_icon_new ("network-server%");
+ g_assert (g_icon_equal (icon, icon2));
+ g_object_unref (icon);
+ g_object_unref (icon2);
+
+ icon = g_icon_new_for_string ("/path/to/somewhere.png", &error);
+ g_assert_no_error (error);
+ location = g_file_new_for_commandline_arg ("/path/to/somewhere.png");
+ icon2 = g_file_icon_new (location);
+ g_assert (g_icon_equal (icon, icon2));
+ g_object_unref (icon);
+ g_object_unref (icon2);
+ g_object_unref (location);
+
+ icon = g_icon_new_for_string ("/path/to/somewhere with whitespace.png", &error);
+ g_assert_no_error (error);
+ data = g_icon_to_string (icon);
+ g_assert_cmpstr (data, ==, "/path/to/somewhere with whitespace.png");
+ g_free (data);
+ location = g_file_new_for_commandline_arg ("/path/to/somewhere with whitespace.png");
+ icon2 = g_file_icon_new (location);
+ g_assert (g_icon_equal (icon, icon2));
+ g_object_unref (location);
+ g_object_unref (icon2);
+ location = g_file_new_for_commandline_arg ("/path/to/somewhere%20with%20whitespace.png");
+ icon2 = g_file_icon_new (location);
+ g_assert (!g_icon_equal (icon, icon2));
+ g_object_unref (location);
+ g_object_unref (icon2);
+ g_object_unref (icon);
+
+ icon = g_icon_new_for_string ("sftp:///path/to/somewhere.png", &error);
+ g_assert_no_error (error);
+ data = g_icon_to_string (icon);
+ g_assert_cmpstr (data, ==, "sftp:///path/to/somewhere.png");
+ g_free (data);
+ location = g_file_new_for_commandline_arg ("sftp:///path/to/somewhere.png");
+ icon2 = g_file_icon_new (location);
+ g_assert (g_icon_equal (icon, icon2));
+ g_object_unref (icon);
+ g_object_unref (icon2);
+ g_object_unref (location);
+
+#if 0
+ icon = g_icon_new_for_string ("sftp:///path/to/somewhere with whitespace.png", &error);
+ g_assert_no_error (error);
+ data = g_icon_to_string (icon);
+ g_assert_cmpstr (data, ==, "sftp:///path/to/somewhere%20with%20whitespace.png");
+ g_free (data);
+ location = g_file_new_for_commandline_arg ("sftp:///path/to/somewhere with whitespace.png");
+ icon2 = g_file_icon_new (location);
+ g_assert (g_icon_equal (icon, icon2));
+ g_object_unref (location);
+ g_object_unref (icon2);
+ location = g_file_new_for_commandline_arg ("sftp:///path/to/somewhere%20with%20whitespace.png");
+ icon2 = g_file_icon_new (location);
+ g_assert (g_icon_equal (icon, icon2));
+ g_object_unref (location);
+ g_object_unref (icon2);
+ g_object_unref (icon);
+#endif
+
+ /* Check that GThemedIcon serialization works */
+
+ icon = g_themed_icon_new ("network-server");
+ g_themed_icon_append_name (G_THEMED_ICON (icon), "computer");
+ data = g_icon_to_string (icon);
+ icon2 = g_icon_new_for_string (data, &error);
+ g_assert_no_error (error);
+ g_assert (g_icon_equal (icon, icon2));
+ g_free (data);
+ g_object_unref (icon);
+ g_object_unref (icon2);
+
+ icon = g_themed_icon_new ("icon name with whitespace");
+ g_themed_icon_append_name (G_THEMED_ICON (icon), "computer");
+ data = g_icon_to_string (icon);
+ icon2 = g_icon_new_for_string (data, &error);
+ g_assert_no_error (error);
+ g_assert (g_icon_equal (icon, icon2));
+ g_free (data);
+ g_object_unref (icon);
+ g_object_unref (icon2);
+
+ icon = g_themed_icon_new_with_default_fallbacks ("network-server-xyz");
+ g_themed_icon_append_name (G_THEMED_ICON (icon), "computer");
+ data = g_icon_to_string (icon);
+ icon2 = g_icon_new_for_string (data, &error);
+ g_assert_no_error (error);
+ g_assert (g_icon_equal (icon, icon2));
+ g_free (data);
+ g_object_unref (icon);
+ g_object_unref (icon2);
+
+ /* Check that GEmblemedIcon serialization works */
+
+ icon = g_themed_icon_new ("face-smirk");
+ icon2 = g_themed_icon_new ("emblem-important");
+ g_themed_icon_append_name (G_THEMED_ICON (icon2), "emblem-shared");
+ location = g_file_new_for_uri ("file:///some/path/somewhere.png");
+ icon3 = g_file_icon_new (location);
+ g_object_unref (location);
+ emblem1 = g_emblem_new_with_origin (icon2, G_EMBLEM_ORIGIN_DEVICE);
+ emblem2 = g_emblem_new_with_origin (icon3, G_EMBLEM_ORIGIN_LIVEMETADATA);
+ icon4 = g_emblemed_icon_new (icon, emblem1);
+ g_emblemed_icon_add_emblem (G_EMBLEMED_ICON (icon4), emblem2);
+ data = g_icon_to_string (icon4);
+ icon5 = g_icon_new_for_string (data, &error);
+ g_assert_no_error (error);
+ g_assert (g_icon_equal (icon4, icon5));
+ g_object_unref (emblem1);
+ g_object_unref (emblem2);
+ g_object_unref (icon);
+ g_object_unref (icon2);
+ g_object_unref (icon3);
+ g_object_unref (icon4);
+ g_object_unref (icon5);
+}
+
+int
+main (int argc,
+ char *argv[])
+{
+ g_type_init ();
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add_func ("/g-icon/serialize", test_g_icon_serialize);
+
+ return g_test_run();
+}
diff --git a/tests/gio/httpd.c b/tests/gio/httpd.c
new file mode 100644
index 000000000..c3aaf33bb
--- /dev/null
+++ b/tests/gio/httpd.c
@@ -0,0 +1,183 @@
+#include <gio/gio.h>
+#include <string.h>
+
+static int port = 8080;
+static char *root = NULL;
+static GOptionEntry cmd_entries[] = {
+ {"port", 'p', 0, G_OPTION_ARG_INT, &port,
+ "Local port to bind to", NULL},
+ {NULL}
+};
+
+static void
+send_error (GOutputStream *out,
+ int error_code,
+ const char *reason)
+{
+ char *res;
+
+ res = g_strdup_printf ("HTTP/1.0 %d %s\r\n\r\n"
+ "<html><head><title>%d %s</title></head>"
+ "<body>%s</body></html>",
+ error_code, reason,
+ error_code, reason,
+ reason);
+ g_output_stream_write_all (out, res, strlen (res), NULL, NULL, NULL);
+ g_free (res);
+}
+
+static gboolean
+handler (GThreadedSocketService *service,
+ GSocketConnection *connection,
+ GSocketListener *listener,
+ gpointer user_data)
+{
+ GOutputStream *out;
+ GInputStream *in;
+ GFileInputStream *file_in;
+ GDataInputStream *data;
+ char *line, *escaped, *tmp, *query, *unescaped, *path, *version;
+ GFile *f;
+ GError *error;
+ GFileInfo *info;
+ GString *s;
+
+ in = g_io_stream_get_input_stream (G_IO_STREAM (connection));
+ out = g_io_stream_get_output_stream (G_IO_STREAM (connection));
+
+ data = g_data_input_stream_new (in);
+ /* Be tolerant of input */
+ g_data_input_stream_set_newline_type (data, G_DATA_STREAM_NEWLINE_TYPE_ANY);
+
+ line = g_data_input_stream_read_line (data, NULL, NULL, NULL);
+
+ if (line == NULL)
+ {
+ send_error (out, 400, "Invalid request");
+ goto out;
+ }
+
+ if (!g_str_has_prefix (line, "GET "))
+ {
+ send_error (out, 501, "Only GET implemented");
+ goto out;
+ }
+
+ escaped = line + 4; /* Skip "GET " */
+
+ version = NULL;
+ tmp = strchr (escaped, ' ');
+ if (tmp != NULL)
+ {
+ *tmp = 0;
+ version = tmp + 1;
+ }
+
+ query = strchr (escaped, '?');
+ if (query != NULL)
+ *query++ = 0;
+
+ unescaped = g_uri_unescape_string (escaped, NULL);
+ path = g_build_filename (root, unescaped, NULL);
+ g_free (unescaped);
+ f = g_file_new_for_path (path);
+ g_free (path);
+
+ error = NULL;
+ file_in = g_file_read (f, NULL, &error);
+ if (file_in == NULL)
+ {
+ send_error (out, 404, error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ s = g_string_new ("HTTP/1.0 200 OK\r\n");
+ info = g_file_input_stream_query_info (file_in,
+ G_FILE_ATTRIBUTE_STANDARD_SIZE ","
+ G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+ NULL, NULL);
+ if (info)
+ {
+ const char *content_type;
+ char *mime_type;
+
+ if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_SIZE))
+ g_string_append_printf (s, "Content-Length: %"G_GINT64_FORMAT"\r\n",
+ g_file_info_get_size (info));
+ content_type = g_file_info_get_content_type (info);
+ if (content_type)
+ {
+ mime_type = g_content_type_get_mime_type (content_type);
+ if (mime_type)
+ {
+ g_string_append_printf (s, "Content-Type: %s\r\n",
+ mime_type);
+ g_free (mime_type);
+ }
+ }
+ }
+ g_string_append (s, "\r\n");
+
+ if (g_output_stream_write_all (out,
+ s->str, s->len,
+ NULL, NULL, NULL))
+ {
+ g_output_stream_splice (out,
+ G_INPUT_STREAM (file_in),
+ 0, NULL, NULL);
+ }
+ g_string_free (s, TRUE);
+
+ g_input_stream_close (G_INPUT_STREAM (file_in), NULL, NULL);
+ g_object_unref (file_in);
+
+ out:
+ g_object_unref (data);
+
+ return TRUE;
+}
+
+int
+main (int argc, char *argv[])
+{
+ GSocketService *service;
+ GOptionContext *context;
+ GError *error = NULL;
+
+ g_type_init ();
+ g_thread_init (NULL);
+
+ context = g_option_context_new ("<http root dir> - Simple HTTP server");
+ g_option_context_add_main_entries (context, cmd_entries, NULL);
+ if (!g_option_context_parse (context, &argc, &argv, &error))
+ {
+ g_printerr ("%s: %s\n", argv[0], error->message);
+ return 1;
+ }
+
+ if (argc != 2)
+ {
+ g_printerr ("Root directory not specified\n");
+ return 1;
+ }
+
+ root = g_strdup (argv[1]);
+
+ service = g_threaded_socket_service_new (10);
+ if (!g_socket_listener_add_inet_port (G_SOCKET_LISTENER (service),
+ port,
+ NULL,
+ &error))
+ {
+ g_printerr ("%s: %s\n", argv[0], error->message);
+ return 1;
+ }
+
+ g_print ("Http server listening on port %d\n", port);
+
+ g_signal_connect (service, "run", G_CALLBACK (handler), NULL);
+
+ g_main_loop_run (g_main_loop_new (NULL, FALSE));
+ g_assert_not_reached ();
+}
diff --git a/tests/gio/live-g-file.c b/tests/gio/live-g-file.c
new file mode 100644
index 000000000..e0f9bfff1
--- /dev/null
+++ b/tests/gio/live-g-file.c
@@ -0,0 +1,1211 @@
+/* GLib testing framework examples and tests
+ * Copyright (C) 2008 Red Hat, Inc.
+ * Authors: Tomas Bzatek <tbzatek@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>
+#include <sys/stat.h>
+
+#define DEFAULT_TEST_DIR "testdir_live-g-file"
+
+#define PATTERN_FILE_SIZE 0x10000
+#define TEST_HANDLE_SPECIAL TRUE
+
+enum StructureExtraFlags
+{
+ TEST_DELETE_NORMAL = 1 << 0,
+ TEST_DELETE_TRASH = 1 << 1,
+ TEST_DELETE_NON_EMPTY = 1 << 2,
+ TEST_DELETE_FAILURE = 1 << 3,
+ TEST_NOT_EXISTS = 1 << 4,
+ TEST_ENUMERATE_FILE = 1 << 5,
+ TEST_NO_ACCESS = 1 << 6,
+ TEST_COPY = 1 << 7,
+ TEST_MOVE = 1 << 8,
+ TEST_COPY_ERROR_RECURSE = 1 << 9,
+ TEST_ALREADY_EXISTS = 1 << 10,
+ TEST_TARGET_IS_FILE = 1 << 11,
+ TEST_CREATE = 1 << 12,
+ TEST_REPLACE = 1 << 13,
+ TEST_APPEND = 1 << 14,
+ TEST_OPEN = 1 << 15,
+ TEST_OVERWRITE = 1 << 16,
+ TEST_INVALID_SYMLINK = 1 << 17,
+};
+
+struct StructureItem
+{
+ const char *filename;
+ const char *link_to;
+ GFileType file_type;
+ GFileCreateFlags create_flags;
+ guint32 mode;
+ gboolean handle_special;
+ enum StructureExtraFlags extra_flags;
+};
+
+#define TEST_DIR_NO_ACCESS "dir_no-access"
+#define TEST_DIR_NO_WRITE "dir_no-write"
+#define TEST_DIR_TARGET "dir-target"
+#define TEST_NAME_NOT_EXISTS "not_exists"
+#define TEST_TARGET_FILE "target-file"
+
+
+static const struct StructureItem sample_struct[] = {
+/* filename link file_type create_flags mode | handle_special | extra_flags */
+ {"dir1", NULL, G_FILE_TYPE_DIRECTORY, G_FILE_CREATE_NONE, 0, 0, TEST_DELETE_NORMAL | TEST_DELETE_NON_EMPTY | TEST_REPLACE | TEST_OPEN},
+ {"dir1/subdir", NULL, G_FILE_TYPE_DIRECTORY, G_FILE_CREATE_NONE, 0, 0, TEST_COPY | TEST_COPY_ERROR_RECURSE | TEST_APPEND},
+ {"dir2", NULL, G_FILE_TYPE_DIRECTORY, G_FILE_CREATE_NONE, 0, 0, TEST_DELETE_NORMAL | TEST_MOVE | TEST_CREATE},
+ {TEST_DIR_TARGET, NULL, G_FILE_TYPE_DIRECTORY, G_FILE_CREATE_NONE, 0, 0, TEST_COPY | TEST_COPY_ERROR_RECURSE},
+ {TEST_DIR_NO_ACCESS, NULL, G_FILE_TYPE_DIRECTORY, G_FILE_CREATE_PRIVATE, S_IRUSR + S_IWUSR + S_IRGRP + S_IWGRP + S_IROTH + S_IWOTH, 0, TEST_NO_ACCESS | TEST_OPEN},
+ {TEST_DIR_NO_WRITE, NULL, G_FILE_TYPE_DIRECTORY, G_FILE_CREATE_PRIVATE, S_IRUSR + S_IXUSR + S_IRGRP + S_IXGRP + S_IROTH + S_IXOTH, 0, 0},
+ {TEST_TARGET_FILE, NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, 0, TEST_COPY | TEST_OPEN},
+ {"normal_file", NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, 0, TEST_ENUMERATE_FILE | TEST_CREATE | TEST_OVERWRITE},
+ {"normal_file-symlink", "normal_file", G_FILE_TYPE_SYMBOLIC_LINK, G_FILE_CREATE_NONE, 0, 0, TEST_ENUMERATE_FILE | TEST_COPY | TEST_OPEN},
+ {"executable_file", NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, S_IRWXU + S_IRWXG + S_IRWXO, 0, TEST_DELETE_TRASH | TEST_COPY | TEST_OPEN | TEST_OVERWRITE | TEST_REPLACE},
+ {"private_file", NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_PRIVATE, 0, 0, TEST_COPY | TEST_OPEN | TEST_OVERWRITE | TEST_APPEND},
+ {"normal_file2", NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, 0, TEST_COPY | TEST_OVERWRITE | TEST_REPLACE},
+ {"readonly_file", NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, S_IRUSR + S_IRGRP + S_IROTH, 0, TEST_DELETE_NORMAL | TEST_OPEN},
+ {"UTF_pr\xcc\x8ci\xcc\x81lis\xcc\x8c z",
+ NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, 0, TEST_COPY | TEST_CREATE | TEST_OPEN | TEST_OVERWRITE},
+ {"dir_pr\xcc\x8ci\xcc\x81lis\xcc\x8c z",
+ NULL, G_FILE_TYPE_DIRECTORY, G_FILE_CREATE_NONE, 0, 0, TEST_DELETE_NORMAL | TEST_CREATE},
+ {"pattern_file", NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, TEST_COPY | TEST_OPEN | TEST_APPEND},
+ {TEST_NAME_NOT_EXISTS, NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, TEST_DELETE_NORMAL | TEST_NOT_EXISTS | TEST_COPY | TEST_OPEN},
+ {TEST_NAME_NOT_EXISTS, NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, TEST_DELETE_TRASH | TEST_NOT_EXISTS | TEST_MOVE},
+ {"not_exists2", NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, TEST_NOT_EXISTS | TEST_CREATE},
+ {"not_exists3", NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, TEST_NOT_EXISTS | TEST_REPLACE},
+ {"not_exists4", NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, TEST_NOT_EXISTS | TEST_APPEND},
+ {"dir_no-execute/file", NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, TEST_DELETE_NORMAL | TEST_DELETE_FAILURE | TEST_NOT_EXISTS | TEST_OPEN},
+ {"lost_symlink", "nowhere", G_FILE_TYPE_SYMBOLIC_LINK, G_FILE_CREATE_NONE, 0, 0, TEST_COPY | TEST_DELETE_NORMAL | TEST_OPEN | TEST_INVALID_SYMLINK},
+ };
+
+static gboolean write_test;
+static gboolean verbose;
+static gboolean posix_compat;
+
+#ifdef G_HAVE_ISO_VARARGS
+#define log(...) if (verbose) g_print (__VA_ARGS__)
+#elif defined(G_HAVE_GNUC_VARARGS)
+#define log(msg...) if (verbose) g_print (msg)
+#else /* no varargs macros */
+static void log (const g_char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ if (verbose) g_print (format, args);
+ va_end (args);
+}
+#endif
+
+static GFile *
+create_empty_file (GFile * parent, const char *filename,
+ GFileCreateFlags create_flags)
+{
+ GFile *child;
+ gboolean res;
+ GError *error;
+ GFileOutputStream *outs;
+
+ child = g_file_get_child (parent, filename);
+ g_assert (child != NULL);
+
+ error = NULL;
+ outs = g_file_replace (child, NULL, FALSE, create_flags, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (outs != NULL);
+ error = NULL;
+ res = g_output_stream_close (G_OUTPUT_STREAM (outs), NULL, &error);
+ g_object_unref (outs);
+ return child;
+}
+
+static GFile *
+create_empty_dir (GFile * parent, const char *filename)
+{
+ GFile *child;
+ gboolean res;
+ GError *error;
+
+ child = g_file_get_child (parent, filename);
+ g_assert (child != NULL);
+ error = NULL;
+ res = g_file_make_directory (child, NULL, &error);
+ g_assert_cmpint (res, ==, TRUE);
+ g_assert_no_error (error);
+ return child;
+}
+
+static GFile *
+create_symlink (GFile * parent, const char *filename, const char *points_to)
+{
+ GFile *child;
+ gboolean res;
+ GError *error;
+
+ child = g_file_get_child (parent, filename);
+ g_assert (child != NULL);
+ error = NULL;
+ res = g_file_make_symbolic_link (child, points_to, NULL, &error);
+ g_assert_cmpint (res, ==, TRUE);
+ g_assert_no_error (error);
+ return child;
+}
+
+static void
+test_create_structure (gconstpointer test_data)
+{
+ GFile *root;
+ GFile *child;
+ gboolean res;
+ GError *error;
+ GFileOutputStream *outs;
+ GDataOutputStream *outds;
+ guint i;
+ struct StructureItem item;
+
+ g_assert (test_data != NULL);
+ log ("\n Going to create testing structure in '%s'...\n",
+ (char *) test_data);
+
+ root = g_file_new_for_commandline_arg ((char *) test_data);
+ g_assert (root != NULL);
+
+ /* create root directory */
+ res = g_file_make_directory (root, NULL, NULL);
+ /* don't care about errors here */
+
+ /* create any other items */
+ for (i = 0; i < G_N_ELEMENTS (sample_struct); i++)
+ {
+ item = sample_struct[i];
+ if ((item.handle_special)
+ || ((!posix_compat)
+ && (item.file_type == G_FILE_TYPE_SYMBOLIC_LINK)))
+ continue;
+
+ child = NULL;
+ switch (item.file_type)
+ {
+ case G_FILE_TYPE_REGULAR:
+ log (" Creating file '%s'...\n", item.filename);
+ child = create_empty_file (root, item.filename, item.create_flags);
+ break;
+ case G_FILE_TYPE_DIRECTORY:
+ log (" Creating directory '%s'...\n", item.filename);
+ child = create_empty_dir (root, item.filename);
+ break;
+ case G_FILE_TYPE_SYMBOLIC_LINK:
+ log (" Creating symlink '%s' --> '%s'...\n", item.filename,
+ item.link_to);
+ child = create_symlink (root, item.filename, item.link_to);
+ break;
+ case G_FILE_TYPE_UNKNOWN:
+ case G_FILE_TYPE_SPECIAL:
+ case G_FILE_TYPE_SHORTCUT:
+ case G_FILE_TYPE_MOUNTABLE:
+ default:
+ break;
+ }
+ g_assert (child != NULL);
+
+ if ((item.mode > 0) && (posix_compat))
+ {
+ error = NULL;
+ res =
+ g_file_set_attribute_uint32 (child, G_FILE_ATTRIBUTE_UNIX_MODE,
+ item.mode,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ NULL, &error);
+ g_assert_cmpint (res, ==, TRUE);
+ g_assert_no_error (error);
+ }
+
+ g_object_unref (child);
+ }
+
+ /* create a pattern file */
+ log (" Creating pattern file...");
+ child = g_file_get_child (root, "pattern_file");
+ g_assert (child != NULL);
+
+ error = NULL;
+ outs =
+ g_file_replace (child, NULL, FALSE, G_FILE_CREATE_NONE, NULL, &error);
+ g_assert_no_error (error);
+
+ g_assert (outs != NULL);
+ outds = g_data_output_stream_new (G_OUTPUT_STREAM (outs));
+ g_assert (outds != NULL);
+ for (i = 0; i < PATTERN_FILE_SIZE; i++)
+ {
+ error = NULL;
+ res = g_data_output_stream_put_byte (outds, i % 256, NULL, &error);
+ g_assert_no_error (error);
+ }
+ error = NULL;
+ res = g_output_stream_close (G_OUTPUT_STREAM (outs), NULL, &error);
+ g_assert_no_error (error);
+ g_object_unref (outds);
+ g_object_unref (outs);
+ g_object_unref (child);
+ log (" done.\n");
+
+ g_object_unref (root);
+}
+
+static GFile *
+file_exists (GFile * parent, const char *filename, gboolean * result)
+{
+ GFile *child;
+ gboolean res;
+
+ if (result)
+ *result = FALSE;
+
+ child = g_file_get_child (parent, filename);
+ g_assert (child != NULL);
+ res = g_file_query_exists (child, NULL);
+ if (result)
+ *result = res;
+
+ return child;
+}
+
+static void
+test_attributes (struct StructureItem item, GFileInfo * info)
+{
+ GFileType ftype;
+ guint32 mode;
+ const char *name, *display_name, *edit_name, *copy_name, *symlink_target;
+ gboolean utf8_valid;
+ gboolean has_attr;
+ gboolean is_symlink;
+ gboolean can_read, can_write;
+
+ /* standard::type */
+ has_attr = g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_TYPE);
+ g_assert_cmpint (has_attr, ==, TRUE);
+ ftype = g_file_info_get_file_type (info);
+ g_assert_cmpint (ftype, !=, G_FILE_TYPE_UNKNOWN);
+ g_assert_cmpint (ftype, ==, item.file_type);
+
+ /* unix::mode */
+ if ((item.mode > 0) && (posix_compat))
+ {
+ mode =
+ g_file_info_get_attribute_uint32 (info,
+ G_FILE_ATTRIBUTE_UNIX_MODE) & 0xFFF;
+ g_assert_cmpint (mode, ==, item.mode);
+ }
+
+ /* access::can-read */
+ if (item.file_type != G_FILE_TYPE_SYMBOLIC_LINK)
+ {
+ can_read =
+ g_file_info_get_attribute_boolean (info,
+ G_FILE_ATTRIBUTE_ACCESS_CAN_READ);
+ g_assert_cmpint (can_read, ==, TRUE);
+ }
+
+ /* access::can-write */
+ if ((write_test) && ((item.extra_flags & TEST_OVERWRITE) == TEST_OVERWRITE))
+ {
+ can_write =
+ g_file_info_get_attribute_boolean (info,
+ G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE);
+ g_assert_cmpint (can_write, ==, TRUE);
+ }
+
+ /* standard::name */
+ name = g_file_info_get_name (info);
+ g_assert (name != NULL);
+
+ /* standard::display-name */
+ display_name = g_file_info_get_display_name (info);
+ g_assert (display_name != NULL);
+ utf8_valid = g_utf8_validate (display_name, -1, NULL);
+ g_assert_cmpint (utf8_valid, ==, TRUE);
+
+ /* standard::edit-name */
+ edit_name = g_file_info_get_edit_name (info);
+ if (edit_name)
+ {
+ utf8_valid = g_utf8_validate (edit_name, -1, NULL);
+ g_assert_cmpint (utf8_valid, ==, TRUE);
+ }
+
+ /* standard::copy-name */
+ copy_name =
+ g_file_info_get_attribute_string (info,
+ G_FILE_ATTRIBUTE_STANDARD_COPY_NAME);
+ if (copy_name)
+ {
+ utf8_valid = g_utf8_validate (copy_name, -1, NULL);
+ g_assert_cmpint (utf8_valid, ==, TRUE);
+ }
+
+ /* standard::is-symlink */
+ if (posix_compat)
+ {
+ is_symlink = g_file_info_get_is_symlink (info);
+ g_assert_cmpint (is_symlink, ==,
+ item.file_type == G_FILE_TYPE_SYMBOLIC_LINK);
+ }
+
+ /* standard::symlink-target */
+ if ((item.file_type == G_FILE_TYPE_SYMBOLIC_LINK) && (posix_compat))
+ {
+ symlink_target = g_file_info_get_symlink_target (info);
+ g_assert_cmpstr (symlink_target, ==, item.link_to);
+ }
+}
+
+static void
+test_initial_structure (gconstpointer test_data)
+{
+ GFile *root;
+ GFile *child;
+ gboolean res;
+ GError *error;
+ GFileInputStream *ins;
+ guint i;
+ GFileInfo *info;
+ guint32 size;
+ guchar *buffer;
+ gssize read, total_read;
+ struct StructureItem item;
+
+
+ g_assert (test_data != NULL);
+ log ("\n Testing sample structure in '%s'...\n", (char *) test_data);
+
+ root = g_file_new_for_commandline_arg ((char *) test_data);
+ g_assert (root != NULL);
+ res = g_file_query_exists (root, NULL);
+ g_assert_cmpint (res, ==, TRUE);
+
+ /* test the structure */
+ for (i = 0; i < G_N_ELEMENTS (sample_struct); i++)
+ {
+ item = sample_struct[i];
+ if (((!posix_compat) && (item.file_type == G_FILE_TYPE_SYMBOLIC_LINK))
+ || (item.handle_special))
+ continue;
+
+ log (" Testing file '%s'...\n", item.filename);
+
+ child = file_exists (root, item.filename, &res);
+ g_assert (child != NULL);
+ g_assert_cmpint (res, ==, TRUE);
+
+ error = NULL;
+ info =
+ g_file_query_info (child, "*", G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ NULL, &error);
+ g_assert_no_error (error);
+ g_assert (info != NULL);
+
+ test_attributes (item, info);
+
+ g_object_unref (child);
+ }
+
+ /* read and test the pattern file */
+ log (" Testing pattern file...\n");
+ child = file_exists (root, "pattern_file", &res);
+ g_assert (child != NULL);
+ g_assert_cmpint (res, ==, TRUE);
+
+ error = NULL;
+ info =
+ g_file_query_info (child, "*", G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL,
+ &error);
+ g_assert_no_error (error);
+ g_assert (info != NULL);
+ size = g_file_info_get_size (info);
+ g_assert_cmpint (size, ==, PATTERN_FILE_SIZE);
+
+ error = NULL;
+ ins = g_file_read (child, NULL, &error);
+ g_assert (ins != NULL);
+ g_assert_no_error (error);
+
+ buffer = g_malloc (PATTERN_FILE_SIZE);
+ total_read = 0;
+
+ while (total_read < PATTERN_FILE_SIZE)
+ {
+ error = NULL;
+ read =
+ g_input_stream_read (G_INPUT_STREAM (ins), buffer + total_read,
+ PATTERN_FILE_SIZE, NULL, &error);
+ g_assert_no_error (error);
+ total_read += read;
+ log (" read %"G_GSSIZE_FORMAT" bytes, total = %"G_GSSIZE_FORMAT" of %d.\n",
+ read, total_read, PATTERN_FILE_SIZE);
+ }
+ g_assert_cmpint (total_read, ==, PATTERN_FILE_SIZE);
+
+ error = NULL;
+ res = g_input_stream_close (G_INPUT_STREAM (ins), NULL, &error);
+ g_assert_no_error (error);
+ g_assert_cmpint (res, ==, TRUE);
+
+ for (i = 0; i < PATTERN_FILE_SIZE; i++)
+ g_assert_cmpint (*(buffer + i), ==, i % 256);
+
+ g_object_unref (ins);
+ g_object_unref (child);
+ g_free (buffer);
+ g_object_unref (root);
+}
+
+static void
+traverse_recurse_dirs (GFile * parent, GFile * root)
+{
+ gboolean res;
+ GError *error;
+ GFileEnumerator *enumerator;
+ GFileInfo *info;
+ GFile *descend;
+ char *relative_path;
+ guint i;
+ gboolean found;
+
+ g_assert (root != NULL);
+
+ error = NULL;
+ enumerator =
+ g_file_enumerate_children (parent, "*",
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL,
+ &error);
+ g_assert (enumerator != NULL);
+ g_assert_no_error (error);
+
+ error = NULL;
+ info = g_file_enumerator_next_file (enumerator, NULL, &error);
+ while ((info) && (!error))
+ {
+ descend = g_file_get_child (parent, g_file_info_get_name (info));
+ g_assert (descend != NULL);
+ relative_path = g_file_get_relative_path (root, descend);
+ g_assert (relative_path != NULL);
+
+ found = FALSE;
+ for (i = 0; i < G_N_ELEMENTS (sample_struct); i++)
+ {
+ if (strcmp (sample_struct[i].filename, relative_path) == 0)
+ {
+ /* test the attributes again */
+ test_attributes (sample_struct[i], info);
+
+ found = TRUE;
+ break;
+ }
+ }
+ g_assert_cmpint (found, ==, TRUE);
+
+ log (" Found file %s, relative to root: %s\n",
+ g_file_info_get_display_name (info), relative_path);
+
+ if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
+ traverse_recurse_dirs (descend, root);
+
+ g_object_unref (descend);
+ error = NULL;
+ info = g_file_enumerator_next_file (enumerator, NULL, &error);
+ }
+ g_assert_no_error (error);
+
+ error = NULL;
+ res = g_file_enumerator_close (enumerator, NULL, &error);
+ g_assert_cmpint (res, ==, TRUE);
+ g_assert_no_error (error);
+}
+
+static void
+test_traverse_structure (gconstpointer test_data)
+{
+ GFile *root;
+ gboolean res;
+
+ g_assert (test_data != NULL);
+ log ("\n Traversing through the sample structure in '%s'...\n",
+ (char *) test_data);
+
+ root = g_file_new_for_commandline_arg ((char *) test_data);
+ g_assert (root != NULL);
+ res = g_file_query_exists (root, NULL);
+ g_assert_cmpint (res, ==, TRUE);
+
+ traverse_recurse_dirs (root, root);
+
+ g_object_unref (root);
+}
+
+
+
+
+static void
+test_enumerate (gconstpointer test_data)
+{
+ GFile *root, *child;
+ gboolean res;
+ GError *error;
+ GFileEnumerator *enumerator;
+ GFileInfo *info;
+ guint i;
+ struct StructureItem item;
+
+
+ g_assert (test_data != NULL);
+ log ("\n Test enumerate '%s'...\n", (char *) test_data);
+
+ root = g_file_new_for_commandline_arg ((char *) test_data);
+ g_assert (root != NULL);
+ res = g_file_query_exists (root, NULL);
+ g_assert_cmpint (res, ==, TRUE);
+
+
+ for (i = 0; i < G_N_ELEMENTS (sample_struct); i++)
+ {
+ item = sample_struct[i];
+ if ((!posix_compat) && (item.file_type == G_FILE_TYPE_SYMBOLIC_LINK))
+ continue;
+
+ if (((item.extra_flags & TEST_NOT_EXISTS) == TEST_NOT_EXISTS) ||
+ (((item.extra_flags & TEST_NO_ACCESS) == TEST_NO_ACCESS)
+ && posix_compat)
+ || ((item.extra_flags & TEST_ENUMERATE_FILE) ==
+ TEST_ENUMERATE_FILE))
+ {
+ log (" Testing file '%s'\n", item.filename);
+ child = g_file_get_child (root, item.filename);
+ g_assert (child != NULL);
+ error = NULL;
+ enumerator =
+ g_file_enumerate_children (child, "*",
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ NULL, &error);
+
+ if ((item.extra_flags & TEST_NOT_EXISTS) == TEST_NOT_EXISTS)
+ {
+ g_assert (enumerator == NULL);
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
+ }
+ if ((item.extra_flags & TEST_ENUMERATE_FILE) == TEST_ENUMERATE_FILE)
+ {
+ g_assert (enumerator == NULL);
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY);
+ }
+ if ((item.extra_flags & TEST_NO_ACCESS) == TEST_NO_ACCESS)
+ {
+ g_assert (enumerator != NULL);
+
+ error = NULL;
+ info = g_file_enumerator_next_file (enumerator, NULL, &error);
+ g_assert (info == NULL);
+ g_assert_no_error (error);
+ /* no items should be found, no error should be logged */
+ }
+
+ if (error)
+ g_error_free (error);
+
+ if (enumerator)
+ {
+ error = NULL;
+ res = g_file_enumerator_close (enumerator, NULL, &error);
+ g_assert_cmpint (res, ==, TRUE);
+ g_assert_no_error (error);
+ }
+ g_object_unref (child);
+ }
+ }
+ g_object_unref (root);
+}
+
+static void
+do_copy_move (GFile * root, struct StructureItem item, const char *target_dir,
+ enum StructureExtraFlags extra_flags)
+{
+ GFile *dst_dir, *src_file, *dst_file;
+ gboolean res;
+ GError *error;
+
+ log (" do_copy_move: '%s' --> '%s'\n", item.filename, target_dir);
+
+ dst_dir = g_file_get_child (root, target_dir);
+ g_assert (dst_dir != NULL);
+ src_file = g_file_get_child (root, item.filename);
+ g_assert (src_file != NULL);
+ dst_file = g_file_get_child (dst_dir, item.filename);
+ g_assert (dst_file != NULL);
+
+ error = NULL;
+ if ((item.extra_flags & TEST_COPY) == TEST_COPY)
+ res =
+ g_file_copy (src_file, dst_file,
+ G_FILE_COPY_NOFOLLOW_SYMLINKS |
+ ((extra_flags ==
+ TEST_OVERWRITE) ? G_FILE_COPY_OVERWRITE :
+ G_FILE_COPY_NONE), NULL, NULL, NULL, &error);
+ else
+ res =
+ g_file_move (src_file, dst_file, G_FILE_COPY_NOFOLLOW_SYMLINKS, NULL,
+ NULL, NULL, &error);
+
+ if (error)
+ log (" res = %d, error code %d = %s\n", res, error->code,
+ error->message);
+
+ /* copying file/directory to itself (".") */
+ if (((item.extra_flags & TEST_NOT_EXISTS) != TEST_NOT_EXISTS) &&
+ (extra_flags == TEST_ALREADY_EXISTS))
+ {
+ g_assert_cmpint (res, ==, FALSE);
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS);
+ }
+ /* target file is a file, overwrite is not set */
+ else if (((item.extra_flags & TEST_NOT_EXISTS) != TEST_NOT_EXISTS) &&
+ (extra_flags == TEST_TARGET_IS_FILE))
+ {
+ g_assert_cmpint (res, ==, FALSE);
+ if (item.file_type == G_FILE_TYPE_DIRECTORY)
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_RECURSE);
+ else
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY);
+ }
+ /* source file is directory */
+ else if ((item.extra_flags & TEST_COPY_ERROR_RECURSE) ==
+ TEST_COPY_ERROR_RECURSE)
+ {
+ g_assert_cmpint (res, ==, FALSE);
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_RECURSE);
+ }
+ /* source or target path doesn't exist */
+ else if (((item.extra_flags & TEST_NOT_EXISTS) == TEST_NOT_EXISTS) ||
+ (extra_flags == TEST_NOT_EXISTS))
+ {
+ g_assert_cmpint (res, ==, FALSE);
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
+ }
+ /* source or target path permission denied */
+ else if (((item.extra_flags & TEST_NO_ACCESS) == TEST_NO_ACCESS) ||
+ (extra_flags == TEST_NO_ACCESS))
+ {
+ g_assert_cmpint (res, ==, FALSE);
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED);
+ }
+ /* no error should be found, all exceptions defined above */
+ else
+ {
+ g_assert_cmpint (res, ==, TRUE);
+ g_assert_no_error (error);
+ }
+
+ if (error)
+ g_error_free (error);
+
+
+ g_object_unref (dst_dir);
+ g_object_unref (src_file);
+ g_object_unref (dst_file);
+}
+
+static void
+test_copy_move (gconstpointer test_data)
+{
+ GFile *root;
+ gboolean res;
+ guint i;
+ struct StructureItem item;
+
+ log ("\n");
+
+ g_assert (test_data != NULL);
+ root = g_file_new_for_commandline_arg ((char *) test_data);
+ g_assert (root != NULL);
+ res = g_file_query_exists (root, NULL);
+ g_assert_cmpint (res, ==, TRUE);
+
+
+ for (i = 0; i < G_N_ELEMENTS (sample_struct); i++)
+ {
+ item = sample_struct[i];
+
+ if ((!posix_compat) && (item.file_type == G_FILE_TYPE_SYMBOLIC_LINK))
+ continue;
+
+ if (((item.extra_flags & TEST_COPY) == TEST_COPY) ||
+ ((item.extra_flags & TEST_MOVE) == TEST_MOVE))
+ {
+ /* test copy/move to a directory, expecting no errors if source files exist */
+ do_copy_move (root, item, TEST_DIR_TARGET, 0);
+
+ /* some files have been already moved so we can't count with them in the tests */
+ if ((item.extra_flags & TEST_COPY) == TEST_COPY)
+ {
+ /* test overwrite for flagged files */
+ if ((item.extra_flags & TEST_OVERWRITE) == TEST_OVERWRITE)
+ {
+ do_copy_move (root, item, TEST_DIR_TARGET, TEST_OVERWRITE);
+ }
+ /* source = target, should return G_IO_ERROR_EXISTS */
+ do_copy_move (root, item, ".", TEST_ALREADY_EXISTS);
+ /* target is file */
+ do_copy_move (root, item, TEST_TARGET_FILE,
+ TEST_TARGET_IS_FILE);
+ /* target path is invalid */
+ do_copy_move (root, item, TEST_NAME_NOT_EXISTS,
+ TEST_NOT_EXISTS);
+
+ /* tests on POSIX-compatible filesystems */
+ if (posix_compat)
+ {
+ /* target directory is not accessible (no execute flag) */
+ do_copy_move (root, item, TEST_DIR_NO_ACCESS,
+ TEST_NO_ACCESS);
+ /* target directory is readonly */
+ do_copy_move (root, item, TEST_DIR_NO_WRITE,
+ TEST_NO_ACCESS);
+ }
+ }
+ }
+ }
+ g_object_unref (root);
+}
+
+static void
+test_create (gconstpointer test_data)
+{
+ GFile *root, *child;
+ gboolean res;
+ GError *error;
+ guint i;
+ struct StructureItem item;
+ GFileOutputStream *os;
+
+ g_assert (test_data != NULL);
+ log ("\n");
+
+ root = g_file_new_for_commandline_arg ((char *) test_data);
+ g_assert (root != NULL);
+ res = g_file_query_exists (root, NULL);
+ g_assert_cmpint (res, ==, TRUE);
+
+ for (i = 0; i < G_N_ELEMENTS (sample_struct); i++)
+ {
+ item = sample_struct[i];
+
+ if (((item.extra_flags & TEST_CREATE) == TEST_CREATE) ||
+ ((item.extra_flags & TEST_REPLACE) == TEST_REPLACE) ||
+ ((item.extra_flags & TEST_APPEND) == TEST_APPEND))
+ {
+ log (" test_create: '%s'\n", item.filename);
+
+ child = g_file_get_child (root, item.filename);
+ g_assert (child != NULL);
+ error = NULL;
+ os = NULL;
+
+ if ((item.extra_flags & TEST_CREATE) == TEST_CREATE)
+ os = g_file_create (child, item.create_flags, NULL, &error);
+ else if ((item.extra_flags & TEST_REPLACE) == TEST_REPLACE)
+ os =
+ g_file_replace (child, NULL, TRUE, item.create_flags, NULL,
+ &error);
+ else if ((item.extra_flags & TEST_APPEND) == TEST_APPEND)
+ os = g_file_append_to (child, item.create_flags, NULL, &error);
+
+
+ if (error)
+ log (" error code %d = %s\n", error->code, error->message);
+
+ if (((item.extra_flags & TEST_NOT_EXISTS) == 0) &&
+ ((item.extra_flags & TEST_CREATE) == TEST_CREATE))
+ {
+ g_assert (os == NULL);
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS);
+ }
+ else if (item.file_type == G_FILE_TYPE_DIRECTORY)
+ {
+ g_assert (os == NULL);
+ if ((item.extra_flags & TEST_CREATE) == TEST_CREATE)
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS);
+ else
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY);
+ }
+ else
+ {
+ g_assert (os != NULL);
+ g_assert_no_error (error);
+ }
+
+ if (error)
+ g_error_free (error);
+
+ if (os)
+ {
+ error = NULL;
+ res =
+ g_output_stream_close (G_OUTPUT_STREAM (os), NULL, &error);
+ if (error)
+ log (" g_output_stream_close: error %d = %s\n",
+ error->code, error->message);
+ g_assert_cmpint (res, ==, TRUE);
+ g_assert_no_error (error);
+ }
+ g_object_unref (child);
+ }
+ }
+ g_object_unref (root);
+}
+
+static void
+test_open (gconstpointer test_data)
+{
+ GFile *root, *child;
+ gboolean res;
+ GError *error;
+ guint i;
+ struct StructureItem item;
+ GFileInputStream *input_stream;
+
+ g_assert (test_data != NULL);
+ log ("\n");
+
+ root = g_file_new_for_commandline_arg ((char *) test_data);
+ g_assert (root != NULL);
+ res = g_file_query_exists (root, NULL);
+ g_assert_cmpint (res, ==, TRUE);
+
+ for (i = 0; i < G_N_ELEMENTS (sample_struct); i++)
+ {
+ item = sample_struct[i];
+
+ if ((!posix_compat) && (item.file_type == G_FILE_TYPE_SYMBOLIC_LINK))
+ continue;
+
+ if ((item.extra_flags & TEST_OPEN) == TEST_OPEN)
+ {
+ log (" test_open: '%s'\n", item.filename);
+
+ child = g_file_get_child (root, item.filename);
+ g_assert (child != NULL);
+ error = NULL;
+ input_stream = g_file_read (child, NULL, &error);
+
+ if (((item.extra_flags & TEST_NOT_EXISTS) == TEST_NOT_EXISTS) ||
+ ((item.extra_flags & TEST_INVALID_SYMLINK) ==
+ TEST_INVALID_SYMLINK))
+ {
+ g_assert (input_stream == NULL);
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
+ }
+ else if (item.file_type == G_FILE_TYPE_DIRECTORY)
+ {
+ g_assert (input_stream == NULL);
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY);
+ }
+ else
+ {
+ g_assert (input_stream != NULL);
+ g_assert_no_error (error);
+ }
+
+ if (error)
+ g_error_free (error);
+
+ if (input_stream)
+ {
+ error = NULL;
+ res =
+ g_input_stream_close (G_INPUT_STREAM (input_stream), NULL,
+ &error);
+ g_assert_cmpint (res, ==, TRUE);
+ g_assert_no_error (error);
+ }
+ g_object_unref (child);
+ }
+ }
+ g_object_unref (root);
+}
+
+static void
+test_delete (gconstpointer test_data)
+{
+ GFile *root;
+ GFile *child;
+ gboolean res;
+ GError *error;
+ guint i;
+ struct StructureItem item;
+
+ g_assert (test_data != NULL);
+ log ("\n");
+
+ root = g_file_new_for_commandline_arg ((char *) test_data);
+ g_assert (root != NULL);
+ res = g_file_query_exists (root, NULL);
+ g_assert_cmpint (res, ==, TRUE);
+
+ for (i = 0; i < G_N_ELEMENTS (sample_struct); i++)
+ {
+ item = sample_struct[i];
+
+ if ((!posix_compat) && (item.file_type == G_FILE_TYPE_SYMBOLIC_LINK))
+ continue;
+
+ if (((item.extra_flags & TEST_DELETE_NORMAL) == TEST_DELETE_NORMAL) ||
+ ((item.extra_flags & TEST_DELETE_TRASH) == TEST_DELETE_TRASH))
+ {
+ child = file_exists (root, item.filename, &res);
+ g_assert (child != NULL);
+ /* we don't care about result here */
+
+ log (" Deleting %s, path = %s\n", item.filename,
+ g_file_get_path (child));
+ error = NULL;
+ if ((item.extra_flags & TEST_DELETE_NORMAL) == TEST_DELETE_NORMAL)
+ res = g_file_delete (child, NULL, &error);
+ else
+ res = g_file_trash (child, NULL, &error);
+
+ if ((item.extra_flags & TEST_DELETE_NON_EMPTY) ==
+ TEST_DELETE_NON_EMPTY)
+ {
+ g_assert_cmpint (res, ==, FALSE);
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_EMPTY);
+ }
+ if ((item.extra_flags & TEST_DELETE_FAILURE) == TEST_DELETE_FAILURE)
+ {
+ g_assert_cmpint (res, ==, FALSE);
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
+ }
+ if ((item.extra_flags & TEST_NOT_EXISTS) == TEST_NOT_EXISTS)
+ {
+ g_assert_cmpint (res, ==, FALSE);
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
+ }
+
+ if (error)
+ {
+ log (" result = %d, error = %s\n", res, error->message);
+ g_error_free (error);
+ }
+
+ g_object_unref (child);
+ }
+ }
+ g_object_unref (root);
+}
+
+
+static void
+cleanup_dir_recurse (GFile *parent, GFile *root)
+{
+ gboolean res;
+ GError *error;
+ GFileEnumerator *enumerator;
+ GFileInfo *info;
+ GFile *descend;
+ char *relative_path;
+
+ g_assert (root != NULL);
+
+ error = NULL;
+ enumerator =
+ g_file_enumerate_children (parent, "*",
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL,
+ &error);
+ if (! enumerator)
+ return;
+
+ error = NULL;
+ info = g_file_enumerator_next_file (enumerator, NULL, &error);
+ while ((info) && (!error))
+ {
+ descend = g_file_get_child (parent, g_file_info_get_name (info));
+ g_assert (descend != NULL);
+ relative_path = g_file_get_relative_path (root, descend);
+ g_assert (relative_path != NULL);
+
+ log (" deleting '%s'\n", g_file_info_get_display_name (info));
+
+ if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
+ cleanup_dir_recurse (descend, root);
+
+ error = NULL;
+ res = g_file_delete (descend, NULL, &error);
+ g_assert_cmpint (res, ==, TRUE);
+
+ g_object_unref (descend);
+ error = NULL;
+ info = g_file_enumerator_next_file (enumerator, NULL, &error);
+ }
+ g_assert_no_error (error);
+
+ error = NULL;
+ res = g_file_enumerator_close (enumerator, NULL, &error);
+ g_assert_cmpint (res, ==, TRUE);
+ g_assert_no_error (error);
+}
+
+static void
+prep_clean_structure (gconstpointer test_data)
+{
+ GFile *root;
+
+ g_assert (test_data != NULL);
+ log ("\n Cleaning target testing structure in '%s'...\n",
+ (char *) test_data);
+
+ root = g_file_new_for_commandline_arg ((char *) test_data);
+ g_assert (root != NULL);
+
+ cleanup_dir_recurse (root, root);
+
+ g_file_delete (root, NULL, NULL);
+
+ g_object_unref (root);
+}
+
+int
+main (int argc, char *argv[])
+{
+ static gboolean only_create_struct;
+ const char *target_path;
+ GError *error;
+ GOptionContext *context;
+
+ static GOptionEntry cmd_entries[] = {
+ {"read-write", 'w', 0, G_OPTION_ARG_NONE, &write_test,
+ "Perform write tests (incl. structure creation)", NULL},
+ {"create-struct", 'c', 0, G_OPTION_ARG_NONE, &only_create_struct,
+ "Only create testing structure (no tests)", NULL},
+ {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Be verbose", NULL},
+ {"posix", 'x', 0, G_OPTION_ARG_NONE, &posix_compat,
+ "Test POSIX-specific features (unix permissions, symlinks)", NULL},
+ {NULL}
+ };
+
+ verbose = FALSE;
+ write_test = FALSE;
+ only_create_struct = FALSE;
+ target_path = NULL;
+ posix_compat = FALSE;
+
+ /* strip all gtester-specific args */
+ g_type_init ();
+ g_test_init (&argc, &argv, NULL);
+
+ /* no extra parameters specified, assume we're executed from glib test suite */
+ if (argc < 2)
+ {
+ verbose = TRUE;
+ write_test = TRUE;
+ only_create_struct = FALSE;
+ target_path = DEFAULT_TEST_DIR;
+#ifdef G_PLATFORM_WIN32
+ posix_compat = FALSE;
+#else
+ posix_compat = TRUE;
+#endif
+ }
+
+ /* add trailing args */
+ error = NULL;
+ context = g_option_context_new ("target_path");
+ g_option_context_add_main_entries (context, cmd_entries, NULL);
+ if (!g_option_context_parse (context, &argc, &argv, &error))
+ {
+ g_print ("option parsing failed: %s\n", error->message);
+ return g_test_run ();
+ }
+
+ /* remaining arg should is the target path; we don't care of the extra args here */
+ if (argc >= 2)
+ target_path = strdup (argv[1]);
+
+ if (! target_path)
+ {
+ g_print ("error: target path was not specified\n");
+ g_print ("%s", g_option_context_get_help (context, TRUE, NULL));
+ return g_test_run ();
+ }
+
+
+ /* Write test - clean target directory first */
+ /* this can be also considered as a test - enumerate + delete */
+ if (write_test || only_create_struct)
+ g_test_add_data_func ("/live-g-file/prep_clean_structure", target_path,
+ prep_clean_structure);
+
+ /* Write test - create new testing structure */
+ if (write_test || only_create_struct)
+ g_test_add_data_func ("/live-g-file/create_structure", target_path,
+ test_create_structure);
+
+ /* Read test - test the sample structure - expect defined attributes to be there */
+ if (!only_create_struct)
+ g_test_add_data_func ("/live-g-file/test_initial_structure", target_path,
+ test_initial_structure);
+
+ /* Read test - test traverse the structure - no special file should appear */
+ if (!only_create_struct)
+ g_test_add_data_func ("/live-g-file/test_traverse_structure", target_path,
+ test_traverse_structure);
+
+ /* Read test - enumerate */
+ if (!only_create_struct)
+ g_test_add_data_func ("/live-g-file/test_enumerate", target_path,
+ test_enumerate);
+
+ /* Read test - open (g_file_read()) */
+ if (!only_create_struct)
+ g_test_add_data_func ("/live-g-file/test_open", target_path, test_open);
+
+ /* Write test - create */
+ if (write_test && (!only_create_struct))
+ g_test_add_data_func ("/live-g-file/test_create", target_path,
+ test_create);
+
+ /* Write test - copy, move */
+ if (write_test && (!only_create_struct))
+ g_test_add_data_func ("/live-g-file/test_copy_move", target_path,
+ test_copy_move);
+
+ /* Write test - delete, trash */
+ if (write_test && (!only_create_struct))
+ g_test_add_data_func ("/live-g-file/test_delete", target_path,
+ test_delete);
+
+ if (write_test || only_create_struct)
+ g_test_add_data_func ("/live-g-file/final_clean", target_path,
+ prep_clean_structure);
+
+ return g_test_run ();
+
+}
diff --git a/tests/gio/live-g-file.txt b/tests/gio/live-g-file.txt
new file mode 100644
index 000000000..95da0e0ad
--- /dev/null
+++ b/tests/gio/live-g-file.txt
@@ -0,0 +1,27 @@
+Before you start testing it would be good to explain how it works.
+
+The script works in three modes:
+ 1. read-only (no special arguments) - suitable for read-only backends. Just
+ create the sample structure using the second mode, pack it (tar -p is
+ preffered to preserve unix modes) and put it on a reachable place.
+ 2. create-structure - only creates reference structure for later testing
+ in read-only mode
+ 3. write mode - full test suite, creates testing structure and performs all
+ read and write tests. Please note the delete/move tests are included
+ in this mode and target directory structure is unusable after the script
+ is finished.
+
+
+To see the list of available parameters just run 'live-g-file --help'
+
+
+Notes:
+ - it's advised to clean target directory first, otherwise some tests might fail
+ (i.e. the tests creating testing structure)
+
+
+Tested:
+ - local filesystem (/tmp/...)
+ - file:// uri (file:///tmp/...)
+ - locatest:// gvfs backend (localtest:///tmp/...)
+ - FAT16 filesystem (no POSIX extensions)
diff --git a/tests/gio/memory-input-stream.c b/tests/gio/memory-input-stream.c
new file mode 100644
index 000000000..6ffee8683
--- /dev/null
+++ b/tests/gio/memory-input-stream.c
@@ -0,0 +1,78 @@
+/* GLib testing framework examples and tests
+ * Copyright (C) 2007 Imendio AB
+ * Authors: Tim Janik
+ *
+ * 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>
+
+static void
+test_read_chunks (void)
+{
+ const char *data1 = "abcdefghijklmnopqrstuvwxyz";
+ const char *data2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ const char *result = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ char buffer[128];
+ gsize bytes_read, pos, len, chunk_size;
+ GError *error = NULL;
+ GInputStream *stream;
+ gboolean res;
+
+ stream = g_memory_input_stream_new ();
+
+ g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (stream),
+ data1, -1, NULL);
+ g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (stream),
+ data2, -1, NULL);
+ len = strlen (data1) + strlen (data2);
+
+ for (chunk_size = 1; chunk_size < len - 1; chunk_size++)
+ {
+ pos = 0;
+ while (pos < len)
+ {
+ bytes_read = g_input_stream_read (stream, buffer, chunk_size, NULL, &error);
+ g_assert_no_error (error);
+ g_assert_cmpint (bytes_read, ==, MIN (chunk_size, len - pos));
+ g_assert (strncmp (buffer, result + pos, bytes_read) == 0);
+
+ pos += bytes_read;
+ }
+
+ g_assert_cmpint (pos, ==, len);
+ res = g_seekable_seek (G_SEEKABLE (stream), 0, G_SEEK_SET, NULL, &error);
+ g_assert_cmpint (res, ==, TRUE);
+ g_assert_no_error (error);
+ }
+}
+
+int
+main (int argc,
+ char *argv[])
+{
+ g_type_init ();
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add_func ("/memory-input-stream/read-chunks", test_read_chunks);
+
+ return g_test_run();
+}
diff --git a/tests/gio/memory-output-stream.c b/tests/gio/memory-output-stream.c
new file mode 100644
index 000000000..cc1e1ea37
--- /dev/null
+++ b/tests/gio/memory-output-stream.c
@@ -0,0 +1,100 @@
+/* GLib testing framework examples and tests
+ * Copyright (C) 2008 Red Hat, Inc.
+ * Author: Matthias Clasen
+ *
+ * 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>
+
+static void
+test_truncate (void)
+{
+ GOutputStream *mo;
+ GDataOutputStream *o;
+ int i;
+ GError *error = NULL;
+
+ g_test_bug ("540423");
+
+ mo = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
+ o = g_data_output_stream_new (mo);
+ for (i = 0; i < 1000; i++)
+ {
+ g_data_output_stream_put_byte (o, 1, NULL, &error);
+ g_assert_no_error (error);
+ }
+ g_seekable_truncate (G_SEEKABLE (mo), 0, NULL, &error);
+ g_assert_no_error (error);
+ for (i = 0; i < 2000; i++)
+ {
+ g_data_output_stream_put_byte (o, 1, NULL, &error);
+ g_assert_no_error (error);
+ }
+
+ g_object_unref (o);
+ g_object_unref (mo);
+}
+
+static void
+test_data_size (void)
+{
+ GOutputStream *mo;
+ GDataOutputStream *o;
+ int pos;
+
+ g_test_bug ("540459");
+
+ mo = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
+ o = g_data_output_stream_new (mo);
+ g_data_output_stream_put_byte (o, 1, NULL, NULL);
+ pos = g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (mo));
+ g_assert_cmpint (pos, ==, 1);
+
+ g_seekable_seek (G_SEEKABLE (mo), 0, G_SEEK_CUR, NULL, NULL);
+ pos = g_seekable_tell (G_SEEKABLE (mo));
+ g_assert_cmpint (pos, ==, 1);
+
+ g_test_bug ("540461");
+
+ g_seekable_seek (G_SEEKABLE (mo), 0, G_SEEK_SET, NULL, NULL);
+ pos = g_seekable_tell (G_SEEKABLE (mo));
+ g_assert_cmpint (pos, ==, 0);
+
+ pos = g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (mo));
+ g_assert_cmpint (pos, ==, 1);
+
+ g_object_unref (o);
+ g_object_unref (mo);
+}
+
+int
+main (int argc,
+ char *argv[])
+{
+ g_type_init ();
+ g_test_init (&argc, &argv, NULL);
+ g_test_bug_base ("http://bugzilla.gnome.org/");
+
+ g_test_add_func ("/memory-output-stream/truncate", test_truncate);
+ g_test_add_func ("/memory-output-stream/get-data-size", test_data_size);
+
+ return g_test_run();
+}
diff --git a/tests/gio/readwrite.c b/tests/gio/readwrite.c
new file mode 100644
index 000000000..0d561851b
--- /dev/null
+++ b/tests/gio/readwrite.c
@@ -0,0 +1,293 @@
+#include <glib/glib.h>
+#include <glib/gstdio.h>
+#include <gio/gio.h>
+#include <unistd.h>
+#include <string.h>
+
+static const char *original_data = "This is some test data that we can put in a file...";
+static const char *new_data = "new data..";
+
+static void
+verify_pos (GIOStream *iostream, goffset expected_pos)
+{
+ goffset pos;
+
+ pos = g_seekable_tell (G_SEEKABLE (iostream));
+ g_assert_cmpint (pos, ==, expected_pos);
+
+ pos = g_seekable_tell (G_SEEKABLE (g_io_stream_get_input_stream (iostream)));
+ g_assert_cmpint (pos, ==, expected_pos);
+
+ pos = g_seekable_tell (G_SEEKABLE (g_io_stream_get_output_stream (iostream)));
+ g_assert_cmpint (pos, ==, expected_pos);
+}
+
+static void
+verify_iostream (GFileIOStream *file_iostream)
+{
+ gboolean res;
+ GIOStream *iostream;
+ GError *error;
+ GInputStream *in;
+ GOutputStream *out;
+ char buffer[1024];
+ gsize n_bytes;
+ char *modified_data;
+
+ iostream = G_IO_STREAM (file_iostream);
+
+ verify_pos (iostream, 0);
+
+ in = g_io_stream_get_input_stream (iostream);
+ out = g_io_stream_get_output_stream (iostream);
+
+ res = g_input_stream_read_all (in, buffer, 20, &n_bytes, NULL, NULL);
+ g_assert (res);
+ g_assert_cmpint ((int)n_bytes, ==, 20);
+
+ g_assert (memcmp (buffer, original_data, 20) == 0);
+
+ verify_pos (iostream, 20);
+
+ res = g_seekable_seek (G_SEEKABLE (iostream),
+ -10, G_SEEK_END,
+ NULL, NULL);
+ g_assert (res);
+ verify_pos (iostream, strlen (original_data) - 10);
+
+ res = g_input_stream_read_all (in, buffer, 20, &n_bytes, NULL, NULL);
+ g_assert (res);
+ g_assert_cmpint ((int)n_bytes, ==, 10);
+ g_assert (memcmp (buffer, original_data + strlen (original_data) - 10, 10) == 0);
+
+ verify_pos (iostream, strlen (original_data));
+
+ res = g_seekable_seek (G_SEEKABLE (iostream),
+ 10, G_SEEK_SET,
+ NULL, NULL);
+
+ verify_pos (iostream, 10);
+
+ res = g_output_stream_write_all (out, new_data, strlen (new_data),
+ &n_bytes, NULL, NULL);
+ g_assert (res);
+ g_assert_cmpint (n_bytes, ==, strlen (new_data));
+
+ verify_pos (iostream, 10 + strlen (new_data));
+
+ res = g_seekable_seek (G_SEEKABLE (iostream),
+ 0, G_SEEK_SET,
+ NULL, NULL);
+ g_assert (res);
+ verify_pos (iostream, 0);
+
+ res = g_input_stream_read_all (in, buffer, strlen (original_data), &n_bytes, NULL, NULL);
+ g_assert (res);
+ g_assert_cmpint ((int)n_bytes, ==, strlen (original_data));
+ buffer[n_bytes] = 0;
+
+ modified_data = g_strdup (original_data);
+ memcpy (modified_data + 10, new_data, strlen (new_data));
+ g_assert_cmpstr (buffer, ==, modified_data);
+
+ verify_pos (iostream, strlen (original_data));
+
+ res = g_seekable_seek (G_SEEKABLE (iostream),
+ 0, G_SEEK_SET,
+ NULL, NULL);
+ g_assert (res);
+ verify_pos (iostream, 0);
+
+ res = g_output_stream_close (out, NULL, NULL);
+ g_assert (res);
+
+ res = g_input_stream_read_all (in, buffer, 15, &n_bytes, NULL, NULL);
+ g_assert (res);
+ g_assert_cmpint ((int)n_bytes, ==, 15);
+ g_assert (memcmp (buffer, modified_data, 15) == 0);
+
+ error = NULL;
+ res = g_output_stream_write_all (out, new_data, strlen (new_data),
+ &n_bytes, NULL, &error);
+ g_assert (!res);
+ g_assert (error != NULL);
+ g_assert (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED));
+
+ error = NULL;
+ res = g_io_stream_close (iostream, NULL, &error);
+ g_assert (res && error == NULL);
+
+ g_free (modified_data);
+}
+
+static void
+test_g_file_open_readwrite (void)
+{
+ char *tmp_file;
+ int fd;
+ gboolean res;
+ GFileIOStream *file_iostream;
+ char *path;
+ GFile *file;
+ GError *error;
+
+ fd = g_file_open_tmp ("readwrite_XXXXXX",
+ &tmp_file, NULL);
+ g_assert (fd != -1);
+ close (fd);
+
+ res = g_file_set_contents (tmp_file,
+ original_data, -1, NULL);
+ g_assert (res);
+
+ path = g_build_filename (g_get_home_dir (), "g-a-nonexisting-file", NULL);
+ file = g_file_new_for_path (path);
+ g_free (path);
+ error = NULL;
+ file_iostream = g_file_open_readwrite (file, NULL, &error);
+ g_assert (file_iostream == NULL);
+ g_assert (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND));
+ g_error_free (error);
+ g_object_unref (file);
+
+ file = g_file_new_for_path (tmp_file);
+ error = NULL;
+ file_iostream = g_file_open_readwrite (file, NULL, &error);
+ g_assert (file_iostream != NULL);
+
+ verify_iostream (file_iostream);
+
+ g_object_unref (file_iostream);
+
+ g_unlink (tmp_file);
+ g_free (tmp_file);
+}
+
+static void
+test_g_file_create_readwrite (void)
+{
+ char *tmp_file;
+ int fd;
+ gboolean res;
+ GFileIOStream *file_iostream;
+ GOutputStream *out;
+ GFile *file;
+ GError *error;
+ gsize n_bytes;
+
+ fd = g_file_open_tmp ("readwrite_XXXXXX",
+ &tmp_file, NULL);
+ g_assert (fd != -1);
+ close (fd);
+
+ file = g_file_new_for_path (tmp_file);
+ error = NULL;
+ file_iostream = g_file_create_readwrite (file, 0, NULL, &error);
+ g_assert (file_iostream == NULL);
+ g_assert (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS));
+
+ g_unlink (tmp_file);
+ file_iostream = g_file_create_readwrite (file, 0, NULL, &error);
+ g_assert (file_iostream != NULL);
+
+ out = g_io_stream_get_output_stream (G_IO_STREAM (file_iostream));
+ res = g_output_stream_write_all (out, original_data, strlen (original_data),
+ &n_bytes, NULL, NULL);
+ g_assert (res);
+ g_assert_cmpint (n_bytes, ==, strlen (original_data));
+
+ res = g_seekable_seek (G_SEEKABLE (file_iostream),
+ 0, G_SEEK_SET,
+ NULL, NULL);
+ g_assert (res);
+
+ verify_iostream (file_iostream);
+
+ g_object_unref (file_iostream);
+
+ g_unlink (tmp_file);
+ g_free (tmp_file);
+}
+
+static void
+test_g_file_replace_readwrite (void)
+{
+ char *tmp_file, *backup, *data;
+ int fd;
+ gboolean res;
+ GFileIOStream *file_iostream;
+ GInputStream *in;
+ GOutputStream *out;
+ GFile *file;
+ GError *error;
+ char buffer[1024];
+ gsize n_bytes;
+
+ fd = g_file_open_tmp ("readwrite_XXXXXX",
+ &tmp_file, NULL);
+ g_assert (fd != -1);
+ close (fd);
+
+ res = g_file_set_contents (tmp_file,
+ new_data, -1, NULL);
+ g_assert (res);
+
+ file = g_file_new_for_path (tmp_file);
+ error = NULL;
+ file_iostream = g_file_replace_readwrite (file, NULL,
+ TRUE, 0, NULL, &error);
+ g_assert (file_iostream != NULL);
+
+ in = g_io_stream_get_input_stream (G_IO_STREAM (file_iostream));
+
+ /* Ensure its empty */
+ res = g_input_stream_read_all (in, buffer, sizeof buffer, &n_bytes, NULL, NULL);
+ g_assert (res);
+ g_assert_cmpint ((int)n_bytes, ==, 0);
+
+ out = g_io_stream_get_output_stream (G_IO_STREAM (file_iostream));
+ res = g_output_stream_write_all (out, original_data, strlen (original_data),
+ &n_bytes, NULL, NULL);
+ g_assert (res);
+ g_assert_cmpint (n_bytes, ==, strlen (original_data));
+
+ res = g_seekable_seek (G_SEEKABLE (file_iostream),
+ 0, G_SEEK_SET,
+ NULL, NULL);
+ g_assert (res);
+
+ verify_iostream (file_iostream);
+
+ g_object_unref (file_iostream);
+
+ backup = g_strconcat (tmp_file, "~", NULL);
+ res = g_file_get_contents (backup,
+ &data,
+ NULL, NULL);
+ g_assert (res);
+ g_assert_cmpstr (data, ==, new_data);
+ g_free (data);
+ g_unlink (backup);
+ g_free (backup);
+
+ g_unlink (tmp_file);
+ g_free (tmp_file);
+}
+
+
+int
+main (int argc,
+ char *argv[])
+{
+ g_type_init ();
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add_func ("/readwrite/test_g_file_open_readwrite",
+ test_g_file_open_readwrite);
+ g_test_add_func ("/readwrite/test_g_file_create_readwrite",
+ test_g_file_create_readwrite);
+ g_test_add_func ("/readwrite/test_g_file_replace_readwrite",
+ test_g_file_replace_readwrite);
+
+ return g_test_run();
+}
diff --git a/tests/gio/resolver.c b/tests/gio/resolver.c
new file mode 100644
index 000000000..055e152ac
--- /dev/null
+++ b/tests/gio/resolver.c
@@ -0,0 +1,506 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2008 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include <glib.h>
+#include "glibintl.h"
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <gio/gio.h>
+
+static GResolver *resolver;
+static GCancellable *cancellable;
+static GMainLoop *loop;
+static int nlookups = 0;
+
+static void G_GNUC_NORETURN
+usage (void)
+{
+ fprintf (stderr, "Usage: resolver [-t] [-s] [hostname | IP | service/protocol/domain ] ...\n");
+ fprintf (stderr, " resolver [-t] [-s] -c [hostname | IP | service/protocol/domain ]\n");
+ fprintf (stderr, " Use -t to enable threading.\n");
+ fprintf (stderr, " Use -s to do synchronous lookups.\n");
+ fprintf (stderr, " Both together will result in simultaneous lookups in multiple threads\n");
+ fprintf (stderr, " Use -c (and only a single resolvable argument) to test GSocketConnectable.\n");
+ exit (1);
+}
+
+G_LOCK_DEFINE_STATIC (response);
+
+static void
+done_lookup (void)
+{
+ nlookups--;
+ if (nlookups == 0)
+ {
+ /* In the sync case we need to make sure we don't call
+ * g_main_loop_quit before the loop is actually running...
+ */
+ g_idle_add ((GSourceFunc)g_main_loop_quit, loop);
+ }
+}
+
+static void
+print_resolved_name (const char *phys,
+ char *name,
+ GError *error)
+{
+ G_LOCK (response);
+ printf ("Address: %s\n", phys);
+ if (error)
+ {
+ printf ("Error: %s\n", error->message);
+ g_error_free (error);
+ }
+ else
+ {
+ printf ("Name: %s\n", name);
+ g_free (name);
+ }
+ printf ("\n");
+
+ done_lookup ();
+ G_UNLOCK (response);
+}
+
+static void
+print_resolved_addresses (const char *name,
+ GList *addresses,
+ GError *error)
+{
+ char *phys;
+ GList *a;
+
+ G_LOCK (response);
+ printf ("Name: %s\n", name);
+ if (error)
+ {
+ printf ("Error: %s\n", error->message);
+ g_error_free (error);
+ }
+ else
+ {
+ for (a = addresses; a; a = a->next)
+ {
+ phys = g_inet_address_to_string (a->data);
+ printf ("Address: %s\n", phys);
+ g_free (phys);
+ g_object_unref (a->data);
+ }
+ g_list_free (addresses);
+ }
+ printf ("\n");
+
+ done_lookup ();
+ G_UNLOCK (response);
+}
+
+static void
+print_resolved_service (const char *service,
+ GList *targets,
+ GError *error)
+{
+ GList *t;
+
+ G_LOCK (response);
+ printf ("Service: %s\n", service);
+ if (error)
+ {
+ printf ("Error: %s\n", error->message);
+ g_error_free (error);
+ }
+ else
+ {
+ for (t = targets; t; t = t->next)
+ {
+ printf ("%s:%u (pri %u, weight %u)\n",
+ g_srv_target_get_hostname (t->data),
+ g_srv_target_get_port (t->data),
+ g_srv_target_get_priority (t->data),
+ g_srv_target_get_weight (t->data));
+ g_srv_target_free (t->data);
+ }
+ g_list_free (targets);
+ }
+ printf ("\n");
+
+ done_lookup ();
+ G_UNLOCK (response);
+}
+
+static void
+lookup_one_sync (const char *arg)
+{
+ GError *error = NULL;
+
+ if (strchr (arg, '/'))
+ {
+ GList *targets;
+ /* service/protocol/domain */
+ char **parts = g_strsplit (arg, "/", 3);
+
+ if (!parts || !parts[2])
+ usage ();
+
+ targets = g_resolver_lookup_service (resolver,
+ parts[0], parts[1], parts[2],
+ cancellable, &error);
+ print_resolved_service (arg, targets, error);
+ }
+ else if (g_hostname_is_ip_address (arg))
+ {
+ GInetAddress *addr = g_inet_address_new_from_string (arg);
+ char *name;
+
+ name = g_resolver_lookup_by_address (resolver, addr, cancellable, &error);
+ print_resolved_name (arg, name, error);
+ g_object_unref (addr);
+ }
+ else
+ {
+ GList *addresses;
+
+ addresses = g_resolver_lookup_by_name (resolver, arg, cancellable, &error);
+ print_resolved_addresses (arg, addresses, error);
+ }
+}
+
+static gpointer
+lookup_thread (gpointer arg)
+{
+ lookup_one_sync (arg);
+ return NULL;
+}
+
+static void
+start_threaded_lookups (char **argv, int argc)
+{
+ int i;
+
+ for (i = 0; i < argc; i++)
+ g_thread_create (lookup_thread, argv[i], FALSE, NULL);
+}
+
+static void
+start_sync_lookups (char **argv, int argc)
+{
+ int i;
+
+ for (i = 0; i < argc; i++)
+ lookup_one_sync (argv[i]);
+}
+
+static void
+lookup_by_addr_callback (GObject *source, GAsyncResult *result,
+ gpointer user_data)
+{
+ const char *phys = user_data;
+ GError *error = NULL;
+ char *name;
+
+ name = g_resolver_lookup_by_address_finish (resolver, result, &error);
+ print_resolved_name (phys, name, error);
+}
+
+static void
+lookup_by_name_callback (GObject *source, GAsyncResult *result,
+ gpointer user_data)
+{
+ const char *name = user_data;
+ GError *error = NULL;
+ GList *addresses;
+
+ addresses = g_resolver_lookup_by_name_finish (resolver, result, &error);
+ print_resolved_addresses (name, addresses, error);
+}
+
+static void
+lookup_service_callback (GObject *source, GAsyncResult *result,
+ gpointer user_data)
+{
+ const char *service = user_data;
+ GError *error = NULL;
+ GList *targets;
+
+ targets = g_resolver_lookup_service_finish (resolver, result, &error);
+ print_resolved_service (service, targets, error);
+}
+
+static void
+start_async_lookups (char **argv, int argc)
+{
+ int i;
+
+ for (i = 0; i < argc; i++)
+ {
+ if (strchr (argv[i], '/'))
+ {
+ /* service/protocol/domain */
+ char **parts = g_strsplit (argv[i], "/", 3);
+
+ if (!parts || !parts[2])
+ usage ();
+
+ g_resolver_lookup_service_async (resolver,
+ parts[0], parts[1], parts[2],
+ cancellable,
+ lookup_service_callback, argv[i]);
+ }
+ else if (g_hostname_is_ip_address (argv[i]))
+ {
+ GInetAddress *addr = g_inet_address_new_from_string (argv[i]);
+
+ g_resolver_lookup_by_address_async (resolver, addr, cancellable,
+ lookup_by_addr_callback, argv[i]);
+ g_object_unref (addr);
+ }
+ else
+ {
+ g_resolver_lookup_by_name_async (resolver, argv[i], cancellable,
+ lookup_by_name_callback,
+ argv[i]);
+ }
+ }
+}
+
+static void
+print_connectable_sockaddr (GSocketAddress *sockaddr,
+ GError *error)
+{
+ char *phys;
+
+ if (error)
+ {
+ printf ("Error: %s\n", error->message);
+ g_error_free (error);
+ }
+ else if (!G_IS_INET_SOCKET_ADDRESS (sockaddr))
+ {
+ printf ("Error: Unexpected sockaddr type '%s'\n", g_type_name_from_instance ((GTypeInstance *)sockaddr));
+ g_object_unref (sockaddr);
+ }
+ else
+ {
+ GInetSocketAddress *isa = G_INET_SOCKET_ADDRESS (sockaddr);
+ phys = g_inet_address_to_string (g_inet_socket_address_get_address (isa));
+ printf ("Address: %s%s%s:%d\n",
+ strchr (phys, ':') ? "[" : "", phys, strchr (phys, ':') ? "]" : "",
+ g_inet_socket_address_get_port (isa));
+ g_free (phys);
+ g_object_unref (sockaddr);
+ }
+}
+
+static void
+do_sync_connectable (GSocketAddressEnumerator *enumerator)
+{
+ GSocketAddress *sockaddr;
+ GError *error = NULL;
+
+ while ((sockaddr = g_socket_address_enumerator_next (enumerator, cancellable, &error)))
+ print_connectable_sockaddr (sockaddr, error);
+
+ g_object_unref (enumerator);
+ done_lookup ();
+}
+
+static void do_async_connectable (GSocketAddressEnumerator *enumerator);
+
+static void
+got_next_async (GObject *source, GAsyncResult *result, gpointer user_data)
+{
+ GSocketAddressEnumerator *enumerator = G_SOCKET_ADDRESS_ENUMERATOR (source);
+ GSocketAddress *sockaddr;
+ GError *error = NULL;
+
+ sockaddr = g_socket_address_enumerator_next_finish (enumerator, result, &error);
+ if (sockaddr || error)
+ print_connectable_sockaddr (sockaddr, error);
+ if (sockaddr)
+ do_async_connectable (enumerator);
+ else
+ {
+ g_object_unref (enumerator);
+ done_lookup ();
+ }
+}
+
+static void
+do_async_connectable (GSocketAddressEnumerator *enumerator)
+{
+ g_socket_address_enumerator_next_async (enumerator, cancellable,
+ got_next_async, NULL);
+}
+
+static void
+do_connectable (const char *arg, gboolean synchronous)
+{
+ char **parts;
+ GSocketConnectable *connectable;
+ GSocketAddressEnumerator *enumerator;
+
+ if (strchr (arg, '/'))
+ {
+ /* service/protocol/domain */
+ parts = g_strsplit (arg, "/", 3);
+ if (!parts || !parts[2])
+ usage ();
+
+ connectable = g_network_service_new (parts[0], parts[1], parts[2]);
+ }
+ else
+ {
+ guint16 port;
+
+ parts = g_strsplit (arg, ":", 2);
+ if (parts && parts[1])
+ {
+ arg = parts[0];
+ port = strtoul (parts[1], NULL, 10);
+ }
+ else
+ port = 0;
+
+ if (g_hostname_is_ip_address (arg))
+ {
+ GInetAddress *addr = g_inet_address_new_from_string (arg);
+ GSocketAddress *sockaddr = g_inet_socket_address_new (addr, port);
+
+ g_object_unref (addr);
+ connectable = G_SOCKET_CONNECTABLE (sockaddr);
+ }
+ else
+ connectable = g_network_address_new (arg, port);
+ }
+
+ enumerator = g_socket_connectable_enumerate (connectable);
+ g_object_unref (connectable);
+
+ if (synchronous)
+ do_sync_connectable (enumerator);
+ else
+ do_async_connectable (enumerator);
+}
+
+#ifdef G_OS_UNIX
+static int cancel_fds[2];
+
+static void
+interrupted (int sig)
+{
+ signal (SIGINT, SIG_DFL);
+ write (cancel_fds[1], "x", 1);
+}
+
+static gboolean
+async_cancel (GIOChannel *source, GIOCondition cond, gpointer cancel)
+{
+ g_cancellable_cancel (cancel);
+ return FALSE;
+}
+#endif
+
+int
+main (int argc, char **argv)
+{
+ gboolean threaded = FALSE, synchronous = FALSE;
+ gboolean use_connectable = FALSE;
+#ifdef G_OS_UNIX
+ GIOChannel *chan;
+ guint watch;
+#endif
+
+ /* We can't use GOptionContext because we use the arguments to
+ * decide whether or not to call g_thread_init().
+ */
+ while (argc >= 2 && argv[1][0] == '-')
+ {
+ if (!strcmp (argv[1], "-t"))
+ {
+ g_thread_init (NULL);
+ threaded = TRUE;
+ }
+ else if (!strcmp (argv[1], "-s"))
+ synchronous = TRUE;
+ else if (!strcmp (argv[1], "-c"))
+ use_connectable = TRUE;
+ else
+ usage ();
+
+ argv++;
+ argc--;
+ }
+ g_type_init ();
+
+ if (argc < 2 || (argc > 2 && use_connectable))
+ usage ();
+
+ resolver = g_resolver_get_default ();
+
+ cancellable = g_cancellable_new ();
+
+#ifdef G_OS_UNIX
+ /* Set up cancellation; we want to cancel if the user ^C's the
+ * program, but we can't cancel directly from an interrupt.
+ */
+ signal (SIGINT, interrupted);
+
+ if (pipe (cancel_fds) == -1)
+ {
+ perror ("pipe");
+ exit (1);
+ }
+ chan = g_io_channel_unix_new (cancel_fds[0]);
+ watch = g_io_add_watch (chan, G_IO_IN, async_cancel, cancellable);
+ g_io_channel_unref (chan);
+#endif
+
+ nlookups = argc - 1;
+ loop = g_main_loop_new (NULL, TRUE);
+
+ if (use_connectable)
+ do_connectable (argv[1], synchronous);
+ else
+ {
+ if (threaded && synchronous)
+ start_threaded_lookups (argv + 1, argc - 1);
+ else if (synchronous)
+ start_sync_lookups (argv + 1, argc - 1);
+ else
+ start_async_lookups (argv + 1, argc - 1);
+ }
+
+ g_main_loop_run (loop);
+ g_main_loop_unref (loop);
+
+#ifdef G_OS_UNIX
+ g_source_remove (watch);
+#endif
+ g_object_unref (cancellable);
+
+ return 0;
+}
diff --git a/tests/gio/send-data.c b/tests/gio/send-data.c
new file mode 100644
index 000000000..d2a702b44
--- /dev/null
+++ b/tests/gio/send-data.c
@@ -0,0 +1,163 @@
+#include <gio/gio.h>
+#include <string.h>
+#include <stdio.h>
+
+GMainLoop *loop;
+
+int cancel_timeout = 0;
+gboolean async = FALSE;
+gboolean graceful = FALSE;
+static GOptionEntry cmd_entries[] = {
+ {"cancel", 'c', 0, G_OPTION_ARG_INT, &cancel_timeout,
+ "Cancel any op after the specified amount of seconds", NULL},
+ {"async", 'a', 0, G_OPTION_ARG_NONE, &async,
+ "Use async ops", NULL},
+ {"graceful-disconnect", 'g', 0, G_OPTION_ARG_NONE, &graceful,
+ "Use graceful disconnect", NULL},
+ {NULL}
+};
+
+static gpointer
+cancel_thread (gpointer data)
+{
+ GCancellable *cancellable = data;
+
+ g_usleep (1000*1000*cancel_timeout);
+ g_print ("Cancelling\n");
+ g_cancellable_cancel (cancellable);
+ return NULL;
+}
+
+static char *
+socket_address_to_string (GSocketAddress *address)
+{
+ GInetAddress *inet_address;
+ char *str, *res;
+ int port;
+
+ inet_address = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (address));
+ str = g_inet_address_to_string (inet_address);
+ port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (address));
+ res = g_strdup_printf ("%s:%d", str, port);
+ g_free (str);
+ return res;
+}
+
+static void
+async_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GAsyncResult **resp = user_data;
+ *resp = g_object_ref (res);
+ g_main_loop_quit (loop);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+ GOptionContext *context;
+ GSocketClient *client;
+ GSocketConnection *connection;
+ GSocketAddress *address;
+ GCancellable *cancellable;
+ GOutputStream *out;
+ GError *error = NULL;
+ char buffer[1000];
+
+ g_type_init ();
+ g_thread_init (NULL);
+
+ context = g_option_context_new (" <hostname>[:port] - send data to tcp host");
+ g_option_context_add_main_entries (context, cmd_entries, NULL);
+ if (!g_option_context_parse (context, &argc, &argv, &error))
+ {
+ g_printerr ("%s: %s\n", argv[0], error->message);
+ return 1;
+ }
+
+ if (argc != 2)
+ {
+ g_printerr ("%s: %s\n", argv[0], "Need to specify hostname");
+ return 1;
+ }
+
+ if (async)
+ loop = g_main_loop_new (NULL, FALSE);
+
+ if (cancel_timeout)
+ {
+ cancellable = g_cancellable_new ();
+ g_thread_create (cancel_thread, cancellable, FALSE, NULL);
+ }
+ else
+ {
+ cancellable = NULL;
+ }
+
+ client = g_socket_client_new ();
+ connection = g_socket_client_connect_to_host (client,
+ argv[1],
+ 7777,
+ cancellable, &error);
+ if (connection == NULL)
+ {
+ g_printerr ("%s can't connect: %s\n", argv[0], error->message);
+ return 1;
+ }
+
+ address = g_socket_connection_get_remote_address (connection, &error);
+ if (!address)
+ {
+ g_printerr ("Error getting remote address: %s\n",
+ error->message);
+ return 1;
+ }
+ g_print ("Connected to address: %s\n",
+ socket_address_to_string (address));
+ g_object_unref (address);
+
+ if (graceful)
+ g_tcp_connection_set_graceful_disconnect (G_TCP_CONNECTION (connection), TRUE);
+
+ out = g_io_stream_get_output_stream (G_IO_STREAM (connection));
+
+ while (fgets(buffer, sizeof (buffer), stdin) != NULL)
+ {
+ if (!g_output_stream_write_all (out, buffer, strlen (buffer),
+ NULL, cancellable, &error))
+ {
+ g_warning ("send error: %s\n", error->message);
+ g_error_free (error);
+ error = NULL;
+ }
+ }
+
+ g_print ("closing stream\n");
+ if (async)
+ {
+ GAsyncResult *res;
+ g_io_stream_close_async (G_IO_STREAM (connection),
+ 0, cancellable, async_cb, &res);
+ g_main_loop_run (loop);
+ if (!g_io_stream_close_finish (G_IO_STREAM (connection),
+ res, &error))
+ {
+ g_object_unref (res);
+ g_warning ("close error: %s\n", error->message);
+ return 1;
+ }
+ g_object_unref (res);
+ }
+ else
+ {
+ if (!g_io_stream_close (G_IO_STREAM (connection), cancellable, &error))
+ {
+ g_warning ("close error: %s\n", error->message);
+ return 1;
+ }
+ }
+
+ return 0;
+}
diff --git a/tests/gio/simple-async-result.c b/tests/gio/simple-async-result.c
new file mode 100644
index 000000000..2c4f62b50
--- /dev/null
+++ b/tests/gio/simple-async-result.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright © 2009 Ryan Lortie
+ *
+ * This program 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 of the licence or (at
+ * your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ */
+
+#include <glib/glib.h>
+#include <gio/gio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static GObject *got_source;
+static GAsyncResult *got_result;
+static gpointer got_user_data;
+
+static void
+ensure_destroyed (gpointer obj)
+{
+ g_object_add_weak_pointer (obj, &obj);
+ g_object_unref (obj);
+ g_assert (obj == NULL);
+}
+
+static void
+reset (void)
+{
+ got_source = NULL;
+
+ if (got_result)
+ ensure_destroyed (got_result);
+
+ got_result = NULL;
+ got_user_data = NULL;
+}
+
+static void
+check (gpointer a, gpointer b, gpointer c)
+{
+ g_assert (a == got_source);
+ g_assert (b == got_result);
+ g_assert (c == got_user_data);
+}
+
+static void
+callback_func (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ got_source = source;
+ got_result = g_object_ref (result);
+ got_user_data = user_data;
+}
+
+static void
+test_simple_async (void)
+{
+ GSimpleAsyncResult *result;
+ GObject *a, *b, *c;
+
+ a = g_object_new (G_TYPE_OBJECT, NULL);
+ b = g_object_new (G_TYPE_OBJECT, NULL);
+ c = g_object_new (G_TYPE_OBJECT, NULL);
+
+ result = g_simple_async_result_new (a, callback_func, b, test_simple_async);
+ check (NULL, NULL, NULL);
+ g_simple_async_result_complete (result);
+ check (a, result, b);
+ g_object_unref (result);
+
+ g_assert (g_simple_async_result_is_valid (got_result, a, test_simple_async));
+ g_assert (!g_simple_async_result_is_valid (got_result, b, test_simple_async));
+ g_assert (!g_simple_async_result_is_valid (got_result, c, test_simple_async));
+ g_assert (!g_simple_async_result_is_valid (got_result, b, callback_func));
+ g_assert (!g_simple_async_result_is_valid ((gpointer) a, NULL, NULL));
+ reset ();
+ reset ();
+ reset ();
+
+ result = g_simple_async_result_new (a, callback_func, b, test_simple_async);
+ check (NULL, NULL, NULL);
+ g_simple_async_result_complete_in_idle (result);
+ g_object_unref (result);
+ check (NULL, NULL, NULL);
+ g_main_context_iteration (NULL, FALSE);
+ check (a, result, b);
+ reset ();
+
+ ensure_destroyed (a);
+ ensure_destroyed (b);
+ ensure_destroyed (c);
+}
+
+int
+main (int argc, char **argv)
+{
+ g_type_init ();
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add_func ("/gio/simple-async-result/test", test_simple_async);
+
+ return g_test_run();
+}
diff --git a/tests/gio/sleepy-stream.c b/tests/gio/sleepy-stream.c
new file mode 100644
index 000000000..1c6613e4b
--- /dev/null
+++ b/tests/gio/sleepy-stream.c
@@ -0,0 +1,296 @@
+/*
+ * Copyright © 2009 Codethink Limited
+ *
+ * This program 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 of the licence or (at
+ * your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ *
+ * Author: Ryan Lortie <desrt@desrt.ca>
+ */
+
+#include <gio/gio.h>
+#include <string.h>
+
+#define MAX_PIECE_SIZE 100
+#define MAX_PIECES 60
+
+static gchar *
+cook_piece (void)
+{
+ char buffer[MAX_PIECE_SIZE * 2];
+ gint symbols, i = 0;
+
+ symbols = g_test_rand_int_range (1, MAX_PIECE_SIZE + 1);
+
+ while (symbols--)
+ {
+ gint c = g_test_rand_int_range (0, 30);
+
+ switch (c)
+ {
+ case 26:
+ buffer[i++] = '\n';
+ case 27:
+ buffer[i++] = '\r';
+ break;
+
+ case 28:
+ buffer[i++] = '\r';
+ case 29:
+ buffer[i++] = '\n';
+ break;
+
+ default:
+ buffer[i++] = c + 'a';
+ break;
+ }
+
+ g_assert_cmpint (i, <=, sizeof buffer);
+ }
+
+ return g_strndup (buffer, i);
+}
+
+static gchar **
+cook_pieces (void)
+{
+ gchar **array;
+ gint pieces;
+
+ pieces = g_test_rand_int_range (0, MAX_PIECES + 1);
+ array = g_new (char *, pieces + 1);
+ array[pieces] = NULL;
+
+ while (pieces--)
+ array[pieces] = cook_piece ();
+
+ return array;
+}
+
+typedef struct
+{
+ GInputStream parent_instance;
+
+ gboolean built_to_fail;
+ gchar **pieces;
+ gint index;
+
+ const gchar *current;
+} SleepyStream;
+
+typedef GInputStreamClass SleepyStreamClass;
+
+GType sleepy_stream_get_type (void);
+
+G_DEFINE_TYPE (SleepyStream, sleepy_stream, G_TYPE_INPUT_STREAM)
+
+static gssize
+sleepy_stream_read (GInputStream *stream,
+ void *buffer,
+ gsize length,
+ GCancellable *cancellable,
+ GError **error)
+{
+ SleepyStream *sleepy = (SleepyStream *) stream;
+
+ if (sleepy->pieces[sleepy->index] == NULL)
+ {
+ if (sleepy->built_to_fail)
+ {
+ g_set_error (error, 0, 0, "fail");
+ return -1;
+ }
+ else
+ return 0;
+ }
+ else
+ {
+ if (!sleepy->current)
+ sleepy->current = sleepy->pieces[sleepy->index++];
+
+ length = MIN (strlen (sleepy->current), length);
+ memcpy (buffer, sleepy->current, length);
+
+ sleepy->current += length;
+ if (*sleepy->current == '\0')
+ sleepy->current = NULL;
+
+ return length;
+ }
+}
+
+static void
+sleepy_stream_init (SleepyStream *sleepy)
+{
+ sleepy->pieces = cook_pieces ();
+ sleepy->built_to_fail = FALSE;
+ sleepy->index = 0;
+}
+
+static void
+sleepy_stream_finalize (GObject *object)
+{
+ SleepyStream *sleepy = (SleepyStream *) object;
+
+ g_strfreev (sleepy->pieces);
+ G_OBJECT_CLASS (sleepy_stream_parent_class)
+ ->finalize (object);
+}
+
+static void
+sleepy_stream_class_init (SleepyStreamClass *class)
+{
+ G_OBJECT_CLASS (class)->finalize = sleepy_stream_finalize;
+ class->read_fn = sleepy_stream_read;
+
+ /* no read_async implementation.
+ * main thread will sleep while read runs in a worker.
+ */
+}
+
+static SleepyStream *
+sleepy_stream_new (void)
+{
+ return g_object_new (sleepy_stream_get_type (), NULL);
+}
+
+static gboolean
+read_line (GDataInputStream *stream,
+ GString *string,
+ const gchar *eol,
+ GError **error)
+{
+ gsize length;
+ int eol_len;
+ char *str;
+
+ eol_len = 1 + (eol[1] != '\0');
+
+ str = g_data_input_stream_read_line (stream, &length, NULL, error);
+
+ if (str == NULL)
+ return FALSE;
+
+ g_assert (strstr (str, eol) == NULL);
+ g_assert (strlen (str) == length);
+
+ g_string_append (string, str);
+ g_string_append (string, eol);
+ g_free (str);
+
+ return TRUE;
+}
+
+static void
+build_comparison (GString *str,
+ SleepyStream *stream)
+{
+ /* build this for comparison */
+ gint i;
+
+ for (i = 0; stream->pieces[i]; i++)
+ g_string_append (str, stream->pieces[i]);
+
+ if (str->len && str->str[str->len - 1] != '\n')
+ g_string_append_c (str, '\n');
+}
+
+
+static void
+test (void)
+{
+ SleepyStream *stream = sleepy_stream_new ();
+ GDataInputStream *data;
+ GError *error = NULL;
+ GString *one;
+ GString *two;
+
+ one = g_string_new (NULL);
+ two = g_string_new (NULL);
+
+ data = g_data_input_stream_new (G_INPUT_STREAM (stream));
+ g_data_input_stream_set_newline_type (data, G_DATA_STREAM_NEWLINE_TYPE_LF);
+ build_comparison (one, stream);
+
+ while (read_line (data, two, "\n", &error));
+
+ g_assert_cmpstr (one->str, ==, two->str);
+ g_string_free (one, TRUE);
+ g_string_free (two, TRUE);
+ g_object_unref (stream);
+ g_object_unref (data);
+}
+
+static GDataInputStream *data;
+static GString *one, *two;
+static GMainLoop *loop;
+static const gchar *eol;
+
+static void
+asynch_ready (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GError *error = NULL;
+ gsize length;
+ gchar *str;
+
+ g_assert (data == G_DATA_INPUT_STREAM (object));
+
+ str = g_data_input_stream_read_line_finish (data, result, &length, &error);
+
+ if (str == NULL)
+ {
+ g_main_loop_quit (loop);
+ if (error)
+ g_error_free (error);
+ }
+ else
+ {
+ g_assert (length == strlen (str));
+ g_string_append (two, str);
+ g_string_append (two, eol);
+ g_free (str);
+
+ /* MOAR!! */
+ g_data_input_stream_read_line_async (data, 0, NULL, asynch_ready, NULL);
+ }
+}
+
+
+static void
+asynch (void)
+{
+ SleepyStream *sleepy = sleepy_stream_new ();
+
+ data = g_data_input_stream_new (G_INPUT_STREAM (sleepy));
+ one = g_string_new (NULL);
+ two = g_string_new (NULL);
+ eol = "\n";
+
+ build_comparison (one, sleepy);
+ g_data_input_stream_read_line_async (data, 0, NULL, asynch_ready, NULL);
+ g_main_loop_run (loop = g_main_loop_new (NULL, FALSE));
+
+ g_assert_cmpstr (one->str, ==, two->str);
+ g_string_free (one, TRUE);
+ g_string_free (two, TRUE);
+ g_object_unref (sleepy);
+ g_object_unref (data);
+}
+
+int
+main (int argc, char **argv)
+{
+ g_test_init (&argc, &argv, NULL);
+ g_test_bug_base ("http://bugzilla.gnome.org/");
+
+ g_type_init ();
+ g_test_add_func ("/filter-stream/input", test);
+ g_test_add_func ("/filter-stream/async", asynch);
+
+ return g_test_run();
+}
diff --git a/tests/gio/socket-client.c b/tests/gio/socket-client.c
new file mode 100644
index 000000000..8409a5fd4
--- /dev/null
+++ b/tests/gio/socket-client.c
@@ -0,0 +1,298 @@
+#include <gio/gio.h>
+#include <glib.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+GMainLoop *loop;
+
+gboolean verbose = FALSE;
+gboolean non_blocking = FALSE;
+gboolean use_udp = FALSE;
+gboolean use_source = FALSE;
+int cancel_timeout = 0;
+
+static GOptionEntry cmd_entries[] = {
+ {"cancel", 'c', 0, G_OPTION_ARG_INT, &cancel_timeout,
+ "Cancel any op after the specified amount of seconds", NULL},
+ {"udp", 'u', 0, G_OPTION_ARG_NONE, &use_udp,
+ "Use udp instead of tcp", NULL},
+ {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
+ "Be verbose", NULL},
+ {"non-blocking", 'n', 0, G_OPTION_ARG_NONE, &non_blocking,
+ "Enable non-blocking i/o", NULL},
+ {"use-source", 's', 0, G_OPTION_ARG_NONE, &use_source,
+ "Use GSource to wait for non-blocking i/o", NULL},
+ {NULL}
+};
+
+static char *
+socket_address_to_string (GSocketAddress *address)
+{
+ GInetAddress *inet_address;
+ char *str, *res;
+ int port;
+
+ inet_address = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (address));
+ str = g_inet_address_to_string (inet_address);
+ port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (address));
+ res = g_strdup_printf ("%s:%d", str, port);
+ g_free (str);
+ return res;
+}
+
+static gboolean
+source_ready (gpointer data,
+ GIOCondition condition)
+{
+ g_main_loop_quit (loop);
+ return FALSE;
+}
+
+static void
+ensure_condition (GSocket *socket,
+ const char *where,
+ GCancellable *cancellable,
+ GIOCondition condition)
+{
+ GError *error = NULL;
+ GSource *source;
+
+ if (!non_blocking)
+ return;
+
+ if (use_source)
+ {
+ source = g_socket_create_source (socket,
+ condition,
+ cancellable);
+ g_source_set_callback (source,
+ (GSourceFunc) source_ready,
+ NULL, NULL);
+ g_source_attach (source, NULL);
+ g_source_unref (source);
+ g_main_loop_run (loop);
+ }
+ else
+ {
+ if (!g_socket_condition_wait (socket, condition, cancellable, &error))
+ {
+ g_printerr ("condition wait error for %s: %s\n",
+ where,
+ error->message);
+ exit (1);
+ }
+ }
+}
+
+static gpointer
+cancel_thread (gpointer data)
+{
+ GCancellable *cancellable = data;
+
+ g_usleep (1000*1000*cancel_timeout);
+ g_print ("Cancelling\n");
+ g_cancellable_cancel (cancellable);
+ return NULL;
+}
+
+int
+main (int argc,
+ char *argv[])
+{
+ GSocket *socket;
+ GSocketAddress *src_address;
+ GSocketAddress *address;
+ GSocketType socket_type;
+ GError *error = NULL;
+ GOptionContext *context;
+ GCancellable *cancellable;
+ GSocketAddressEnumerator *enumerator;
+ GSocketConnectable *connectable;
+
+ g_thread_init (NULL);
+
+ g_type_init ();
+
+ context = g_option_context_new (" <hostname>[:port] - Test GSocket client stuff");
+ g_option_context_add_main_entries (context, cmd_entries, NULL);
+ if (!g_option_context_parse (context, &argc, &argv, &error))
+ {
+ g_printerr ("%s: %s\n", argv[0], error->message);
+ return 1;
+ }
+
+ if (argc != 2)
+ {
+ g_printerr ("%s: %s\n", argv[0], "Need to specify hostname");
+ return 1;
+ }
+
+ if (cancel_timeout)
+ {
+ cancellable = g_cancellable_new ();
+ g_thread_create (cancel_thread, cancellable, FALSE, NULL);
+ }
+ else
+ {
+ cancellable = NULL;
+ }
+
+ loop = g_main_loop_new (NULL, FALSE);
+
+ if (use_udp)
+ socket_type = G_SOCKET_TYPE_DATAGRAM;
+ else
+ socket_type = G_SOCKET_TYPE_STREAM;
+
+ socket = g_socket_new (G_SOCKET_FAMILY_IPV4, socket_type, 0, &error);
+ if (socket == NULL)
+ {
+ g_printerr ("%s: %s\n", argv[0], error->message);
+ return 1;
+ }
+
+ connectable = g_network_address_parse (argv[1], 7777, &error);
+ if (connectable == NULL)
+ {
+ g_printerr ("%s: %s\n", argv[0], error->message);
+ return 1;
+ }
+
+ enumerator = g_socket_connectable_enumerate (connectable);
+ while (TRUE)
+ {
+ address = g_socket_address_enumerator_next (enumerator, cancellable, &error);
+ if (address == NULL)
+ {
+ if (error == NULL)
+ g_printerr ("%s: No more addresses to try\n", argv[0]);
+ else
+ g_printerr ("%s: %s\n", argv[0], error->message);
+ return 1;
+ }
+
+ if (g_socket_connect (socket, address, cancellable, &error))
+ break;
+ g_printerr ("%s: Connection to %s failed: %s, trying next\n", argv[0], socket_address_to_string (address), error->message);
+ g_error_free (error);
+ error = NULL;
+
+ g_object_unref (address);
+ }
+ g_object_unref (enumerator);
+
+ g_print ("Connected to %s\n",
+ socket_address_to_string (address));
+
+ /* TODO: Test non-blocking connect */
+ if (non_blocking)
+ g_socket_set_blocking (socket, FALSE);
+
+ src_address = g_socket_get_local_address (socket, &error);
+ if (!src_address)
+ {
+ g_printerr ("Error getting local address: %s\n",
+ error->message);
+ return 1;
+ }
+ g_print ("local address: %s\n",
+ socket_address_to_string (src_address));
+ g_object_unref (src_address);
+
+ while (TRUE)
+ {
+ gchar buffer[4096] = { };
+ gssize size;
+ gsize to_send;
+
+ if (fgets (buffer, sizeof buffer, stdin) == NULL)
+ break;
+
+ to_send = strlen (buffer);
+ while (to_send > 0)
+ {
+ ensure_condition (socket, "send", cancellable, G_IO_OUT);
+ if (use_udp)
+ size = g_socket_send_to (socket, address,
+ buffer, to_send,
+ cancellable, &error);
+ else
+ size = g_socket_send (socket, buffer, to_send,
+ cancellable, &error);
+
+ if (size < 0)
+ {
+ if (g_error_matches (error,
+ G_IO_ERROR,
+ G_IO_ERROR_WOULD_BLOCK))
+ {
+ g_print ("socket send would block, handling\n");
+ g_error_free (error);
+ error = NULL;
+ continue;
+ }
+ else
+ {
+ g_printerr ("Error sending to socket: %s\n",
+ error->message);
+ return 1;
+ }
+ }
+
+ g_print ("sent %" G_GSSIZE_FORMAT " bytes of data\n", size);
+
+ if (size == 0)
+ {
+ g_printerr ("Unexpected short write\n");
+ return 1;
+ }
+
+ to_send -= size;
+ }
+
+ ensure_condition (socket, "receive", cancellable, G_IO_IN);
+ if (use_udp)
+ size = g_socket_receive_from (socket, &src_address,
+ buffer, sizeof buffer,
+ cancellable, &error);
+ else
+ size = g_socket_receive (socket, buffer, sizeof buffer,
+ cancellable, &error);
+
+ if (size < 0)
+ {
+ g_printerr ("Error receiving from socket: %s\n",
+ error->message);
+ return 1;
+ }
+
+ if (size == 0)
+ break;
+
+ g_print ("received %" G_GSSIZE_FORMAT " bytes of data", size);
+ if (use_udp)
+ g_print (" from %s", socket_address_to_string (src_address));
+ g_print ("\n");
+
+ if (verbose)
+ g_print ("-------------------------\n"
+ "%.*s"
+ "-------------------------\n",
+ (int)size, buffer);
+
+ }
+
+ g_print ("closing socket\n");
+
+ if (!g_socket_close (socket, &error))
+ {
+ g_printerr ("Error closing master socket: %s\n",
+ error->message);
+ return 1;
+ }
+
+ g_object_unref (G_OBJECT (socket));
+
+ return 0;
+}
diff --git a/tests/gio/socket-server.c b/tests/gio/socket-server.c
new file mode 100644
index 000000000..b98c696e4
--- /dev/null
+++ b/tests/gio/socket-server.c
@@ -0,0 +1,308 @@
+#include <gio/gio.h>
+#include <glib.h>
+#include <stdlib.h>
+
+GMainLoop *loop;
+
+int port = 7777;
+gboolean verbose = FALSE;
+gboolean dont_reuse_address = FALSE;
+gboolean non_blocking = FALSE;
+gboolean use_udp = FALSE;
+gboolean use_source = FALSE;
+int cancel_timeout = 0;
+
+static GOptionEntry cmd_entries[] = {
+ {"port", 'p', 0, G_OPTION_ARG_INT, &port,
+ "Local port to bind to", NULL},
+ {"cancel", 'c', 0, G_OPTION_ARG_INT, &cancel_timeout,
+ "Cancel any op after the specified amount of seconds", NULL},
+ {"udp", 'u', 0, G_OPTION_ARG_NONE, &use_udp,
+ "Use udp instead of tcp", NULL},
+ {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
+ "Be verbose", NULL},
+ {"no-reuse", 0, 0, G_OPTION_ARG_NONE, &dont_reuse_address,
+ "Don't SOADDRREUSE", NULL},
+ {"non-blocking", 'n', 0, G_OPTION_ARG_NONE, &non_blocking,
+ "Enable non-blocking i/o", NULL},
+ {"use-source", 's', 0, G_OPTION_ARG_NONE, &use_source,
+ "Use GSource to wait for non-blocking i/o", NULL},
+ {NULL}
+};
+
+static char *
+socket_address_to_string (GSocketAddress *address)
+{
+ GInetAddress *inet_address;
+ char *str, *res;
+ int the_port;
+
+ inet_address = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (address));
+ str = g_inet_address_to_string (inet_address);
+ the_port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (address));
+ res = g_strdup_printf ("%s:%d", str, the_port);
+ g_free (str);
+ return res;
+}
+
+static gboolean
+source_ready (gpointer data,
+ GIOCondition condition)
+{
+ g_main_loop_quit (loop);
+ return FALSE;
+}
+
+static void
+ensure_condition (GSocket *socket,
+ const char *where,
+ GCancellable *cancellable,
+ GIOCondition condition)
+{
+ GError *error = NULL;
+ GSource *source;
+
+ if (!non_blocking)
+ return;
+
+ if (use_source)
+ {
+ source = g_socket_create_source (socket,
+ condition,
+ cancellable);
+ g_source_set_callback (source,
+ (GSourceFunc) source_ready,
+ NULL, NULL);
+ g_source_attach (source, NULL);
+ g_source_unref (source);
+ g_main_loop_run (loop);
+ }
+ else
+ {
+ if (!g_socket_condition_wait (socket, condition, cancellable, &error))
+ {
+ g_printerr ("condition wait error for %s: %s\n",
+ where,
+ error->message);
+ exit (1);
+ }
+ }
+}
+
+static gpointer
+cancel_thread (gpointer data)
+{
+ GCancellable *cancellable = data;
+
+ g_usleep (1000*1000*cancel_timeout);
+ g_print ("Cancelling\n");
+ g_cancellable_cancel (cancellable);
+ return NULL;
+}
+
+int
+main (int argc,
+ char *argv[])
+{
+ GSocket *socket, *new_socket, *recv_socket;
+ GSocketAddress *src_address;
+ GSocketAddress *address;
+ GSocketType socket_type;
+ GError *error = NULL;
+ GOptionContext *context;
+ GCancellable *cancellable;
+
+ g_thread_init (NULL);
+
+ g_type_init ();
+
+ context = g_option_context_new (" - Test GSocket server stuff");
+ g_option_context_add_main_entries (context, cmd_entries, NULL);
+ if (!g_option_context_parse (context, &argc, &argv, &error))
+ {
+ g_printerr ("%s: %s\n", argv[0], error->message);
+ return 1;
+ }
+
+ if (cancel_timeout)
+ {
+ cancellable = g_cancellable_new ();
+ g_thread_create (cancel_thread, cancellable, FALSE, NULL);
+ }
+ else
+ {
+ cancellable = NULL;
+ }
+
+ loop = g_main_loop_new (NULL, FALSE);
+
+ if (use_udp)
+ socket_type = G_SOCKET_TYPE_DATAGRAM;
+ else
+ socket_type = G_SOCKET_TYPE_STREAM;
+
+ socket = g_socket_new (G_SOCKET_FAMILY_IPV4, socket_type, 0, &error);
+
+ if (socket == NULL)
+ {
+ g_printerr ("%s: %s\n", argv[0], error->message);
+ return 1;
+ }
+
+ if (non_blocking)
+ g_socket_set_blocking (socket, FALSE);
+
+ src_address = g_inet_socket_address_new (g_inet_address_new_any (G_SOCKET_FAMILY_IPV4), port);
+ if (!g_socket_bind (socket, src_address, !dont_reuse_address, &error))
+ {
+ g_printerr ("Can't bind socket: %s\n", error->message);
+ return 1;
+ }
+
+ if (!use_udp)
+ {
+ if (!g_socket_listen (socket, &error))
+ {
+ g_printerr ("Can't listen on socket: %s\n", error->message);
+ return 1;
+ }
+
+ g_print ("listening on port %d...\n", port);
+
+ ensure_condition (socket, "accept", cancellable, G_IO_IN);
+ new_socket = g_socket_accept (socket, cancellable, &error);
+ if (!new_socket)
+ {
+ g_printerr ("Error accepting socket: %s\n",
+ error->message);
+ return 1;
+ }
+
+ if (non_blocking)
+ g_socket_set_blocking (new_socket, FALSE);
+
+ address = g_socket_get_remote_address (new_socket, &error);
+ if (!address)
+ {
+ g_printerr ("Error getting remote address: %s\n",
+ error->message);
+ return 1;
+ }
+
+ g_print ("got a new connection from %s\n",
+ socket_address_to_string (address));
+ g_object_unref (address);
+
+ recv_socket = new_socket;
+ }
+ else
+ {
+ recv_socket = socket;
+ new_socket = NULL;
+ }
+
+
+ while (TRUE)
+ {
+ gchar buffer[4096] = { };
+ gssize size;
+ gsize to_send;
+
+ ensure_condition (recv_socket, "receive", cancellable, G_IO_IN);
+ if (use_udp)
+ size = g_socket_receive_from (recv_socket, &address,
+ buffer, sizeof buffer,
+ cancellable, &error);
+ else
+ size = g_socket_receive (recv_socket, buffer, sizeof buffer,
+ cancellable, &error);
+
+ if (size < 0)
+ {
+ g_printerr ("Error receiving from socket: %s\n",
+ error->message);
+ return 1;
+ }
+
+ if (size == 0)
+ break;
+
+ g_print ("received %" G_GSSIZE_FORMAT " bytes of data", size);
+ if (use_udp)
+ g_print (" from %s", socket_address_to_string (address));
+ g_print ("\n");
+
+ if (verbose)
+ g_print ("-------------------------\n"
+ "%.*s\n"
+ "-------------------------\n",
+ (int)size, buffer);
+
+ to_send = size;
+
+ while (to_send > 0)
+ {
+ ensure_condition (recv_socket, "send", cancellable, G_IO_OUT);
+ if (use_udp)
+ size = g_socket_send_to (recv_socket, address,
+ buffer, to_send, cancellable, &error);
+ else
+ size = g_socket_send (recv_socket, buffer, to_send,
+ cancellable, &error);
+
+ if (size < 0)
+ {
+ if (g_error_matches (error,
+ G_IO_ERROR,
+ G_IO_ERROR_WOULD_BLOCK))
+ {
+ g_print ("socket send would block, handling\n");
+ g_error_free (error);
+ error = NULL;
+ continue;
+ }
+ else
+ {
+ g_printerr ("Error sending to socket: %s\n",
+ error->message);
+ return 1;
+ }
+ }
+
+ g_print ("sent %" G_GSSIZE_FORMAT " bytes of data\n", size);
+
+ if (size == 0)
+ {
+ g_printerr ("Unexpected short write\n");
+ return 1;
+ }
+
+ to_send -= size;
+ }
+ }
+
+ g_print ("connection closed\n");
+
+ if (new_socket)
+ {
+ if (!g_socket_close (new_socket, &error))
+ {
+ g_printerr ("Error closing connection socket: %s\n",
+ error->message);
+ return 1;
+ }
+
+ g_object_unref (G_OBJECT (new_socket));
+ }
+
+ if (!g_socket_close (socket, &error))
+ {
+ g_printerr ("Error closing master socket: %s\n",
+ error->message);
+ return 1;
+ }
+
+ g_object_unref (G_OBJECT (socket));
+
+ return 0;
+}
diff --git a/tests/gio/srvtarget.c b/tests/gio/srvtarget.c
new file mode 100644
index 000000000..c7330f9ae
--- /dev/null
+++ b/tests/gio/srvtarget.c
@@ -0,0 +1,158 @@
+/* GLib testing framework examples and tests
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * 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 NUM_TRIALS 250000
+
+struct {
+ const char *order;
+ int expected, seen;
+} ordering[] = {
+ /* There are 32 legitimate orderings; the result always has to start
+ * with either "fe" (usually) or "ef" (rarely). For the remaining
+ * letters, "cbda" is the most likely, with various other orders
+ * possible, down to "adbc" being the most improbable. However,
+ * almost all "fe" orderings are more likely than almost any "ef"
+ * orderings. The complete probability ordering, from most-likely
+ * to least-likely is something roughly like:
+ */
+ { "fecbda", 0.2468 * NUM_TRIALS, 0},
+ { "febcda", 0.1885 * NUM_TRIALS, 0},
+ { "fecdba", 0.1346 * NUM_TRIALS, 0},
+ { "fedcba", 0.0830 * NUM_TRIALS, 0},
+ { "febdca", 0.0706 * NUM_TRIALS, 0},
+ { "fedbca", 0.0571 * NUM_TRIALS, 0},
+ { "fecbad", 0.0496 * NUM_TRIALS, 0},
+ { "febcad", 0.0374 * NUM_TRIALS, 0},
+ { "fecabd", 0.0185 * NUM_TRIALS, 0},
+ { "fecdab", 0.0136 * NUM_TRIALS, 0},
+ { "fecadb", 0.0110 * NUM_TRIALS, 0},
+ { "febacd", 0.0108 * NUM_TRIALS, 0},
+ { "feacbd", 0.0096 * NUM_TRIALS, 0},
+ { "fedcab", 0.0083 * NUM_TRIALS, 0},
+ { "feabcd", 0.0073 * NUM_TRIALS, 0},
+ { "feacdb", 0.0058 * NUM_TRIALS, 0},
+ { "efcbda", 0.0049 * NUM_TRIALS, 0},
+ { "febdac", 0.0048 * NUM_TRIALS, 0},
+ { "febadc", 0.0043 * NUM_TRIALS, 0},
+ { "fedbac", 0.0038 * NUM_TRIALS, 0},
+ { "efbcda", 0.0038 * NUM_TRIALS, 0},
+ { "feadcb", 0.0036 * NUM_TRIALS, 0},
+ { "fedacb", 0.0035 * NUM_TRIALS, 0},
+ { "feabdc", 0.0029 * NUM_TRIALS, 0},
+ { "feadbc", 0.0026 * NUM_TRIALS, 0},
+ { "fedabc", 0.0026 * NUM_TRIALS, 0},
+ { "efcdba", 0.0026 * NUM_TRIALS, 0},
+ { "efdcba", 0.0017 * NUM_TRIALS, 0},
+ { "efbdca", 0.0014 * NUM_TRIALS, 0},
+ { "efdbca", 0.0011 * NUM_TRIALS, 0},
+ { "efcbad", 0.0010 * NUM_TRIALS, 0},
+ { "efbcad", 0.0008 * NUM_TRIALS, 0},
+ { "efcabd", 0.0004 * NUM_TRIALS, 0},
+ { "efcdab", 0.0003 * NUM_TRIALS, 0},
+ { "efcadb", 0.0002 * NUM_TRIALS, 0},
+ { "efbacd", 0.0002 * NUM_TRIALS, 0},
+ { "efacbd", 0.0002 * NUM_TRIALS, 0},
+ { "efdcab", 0.0002 * NUM_TRIALS, 0},
+ { "efabcd", 0.0002 * NUM_TRIALS, 0},
+ { "efacdb", 0.0001 * NUM_TRIALS, 0},
+ { "efbdac", 0.0001 * NUM_TRIALS, 0},
+ { "efadcb", 0.0001 * NUM_TRIALS, 0},
+ { "efdbac", 0.0001 * NUM_TRIALS, 0},
+ { "efbadc", 0.0001 * NUM_TRIALS, 0},
+ { "efdacb", 0.0001 * NUM_TRIALS, 0},
+ { "efabdc", 0.0001 * NUM_TRIALS, 0},
+ { "efadbc", 0.00005 * NUM_TRIALS, 0},
+ { "efdabc", 0.00005 * NUM_TRIALS, 0}
+};
+#define NUM_ORDERINGS G_N_ELEMENTS (ordering)
+
+static void
+test_srv_target_ordering (void)
+{
+ GList *targets, *sorted, *t;
+ char result[7], *p;
+ int i;
+ guint o;
+
+ targets = NULL;
+ /* name, port, priority, weight */
+ targets = g_list_append (targets, g_srv_target_new ("a", 0, 2, 0));
+ targets = g_list_append (targets, g_srv_target_new ("b", 0, 2, 10));
+ targets = g_list_append (targets, g_srv_target_new ("c", 0, 2, 15));
+ targets = g_list_append (targets, g_srv_target_new ("d", 0, 2, 5));
+ targets = g_list_append (targets, g_srv_target_new ("e", 0, 1, 0));
+ targets = g_list_append (targets, g_srv_target_new ("f", 0, 1, 50));
+
+ for (i = 0; i < NUM_TRIALS; i++)
+ {
+ g_random_set_seed (i);
+
+ sorted = g_srv_target_list_sort (g_list_copy (targets));
+
+ for (t = sorted, p = result; t; t = t->next)
+ *(p++) = *g_srv_target_get_hostname (t->data);
+ *p = '\0';
+ g_list_free (sorted);
+
+ for (o = 0; o < NUM_ORDERINGS; o++)
+ {
+ if (!strcmp (result, ordering[o].order))
+ {
+ ordering[o].seen++;
+ break;
+ }
+ }
+
+ /* Assert that @result matched one of the valid orderings */
+ if (o == NUM_ORDERINGS)
+ {
+ char *msg = g_strdup_printf ("result '%s' is invalid", result);
+ g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg);
+ }
+ }
+
+ /* Assert that each ordering appeared roughly the expected
+ * number of times.
+ */
+ for (o = 0; o < NUM_ORDERINGS; o++)
+ {
+ g_assert_cmpint (ordering[o].seen, >, ordering[o].expected / 2);
+ g_assert_cmpint (ordering[o].seen, <, ordering[o].expected * 2);
+ }
+
+ g_resolver_free_targets (targets);
+}
+
+int
+main (int argc, char **argv)
+{
+ g_type_init ();
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add_func ("/srvtarget/srv-target-ordering", test_srv_target_ordering);
+
+ return g_test_run();
+}
diff --git a/tests/gio/unix-streams.c b/tests/gio/unix-streams.c
new file mode 100644
index 000000000..07c7b9f82
--- /dev/null
+++ b/tests/gio/unix-streams.c
@@ -0,0 +1,256 @@
+/* GLib testing framework examples and tests
+ * Copyright (C) 2008 Red Hat, Inc
+ *
+ * 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 <gio/gunixinputstream.h>
+#include <gio/gunixoutputstream.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define DATA "abcdefghijklmnopqrstuvwxyz"
+
+int writer_pipe[2], reader_pipe[2];
+GCancellable *writer_cancel, *reader_cancel, *main_cancel;
+GMainLoop *loop;
+
+static gpointer
+writer_thread (gpointer user_data)
+{
+ GOutputStream *out;
+ gssize nwrote, offset;
+ GError *err = NULL;
+
+ out = g_unix_output_stream_new (writer_pipe[1], TRUE);
+
+ do
+ {
+ g_usleep (10);
+
+ offset = 0;
+ while (offset < (gssize) sizeof (DATA))
+ {
+ nwrote = g_output_stream_write (out, DATA + offset,
+ sizeof (DATA) - offset,
+ writer_cancel, &err);
+ if (nwrote <= 0 || err != NULL)
+ break;
+ offset += nwrote;
+ }
+
+ g_assert (nwrote > 0 || err != NULL);
+ }
+ while (err == NULL);
+
+ if (g_cancellable_is_cancelled (writer_cancel))
+ {
+ g_cancellable_cancel (main_cancel);
+ g_object_unref (out);
+ return NULL;
+ }
+
+ g_warning ("writer: %s", err->message);
+ g_assert_not_reached ();
+}
+
+static gpointer
+reader_thread (gpointer user_data)
+{
+ GInputStream *in;
+ gssize nread, total;
+ GError *err = NULL;
+ char buf[sizeof (DATA)];
+
+ in = g_unix_input_stream_new (reader_pipe[0], TRUE);
+
+ do
+ {
+ total = 0;
+ while (total < (gssize) sizeof (DATA))
+ {
+ nread = g_input_stream_read (in, buf + total, sizeof (buf) - total,
+ reader_cancel, &err);
+ if (nread <= 0 || err != NULL)
+ break;
+ total += nread;
+ }
+
+ if (err)
+ break;
+
+ if (nread == 0)
+ {
+ g_assert (err == NULL);
+ /* pipe closed */
+ g_object_unref (in);
+ return NULL;
+ }
+
+ g_assert_cmpstr (buf, ==, DATA);
+ g_assert (!g_cancellable_is_cancelled (reader_cancel));
+ }
+ while (err == NULL);
+
+ g_warning ("reader: %s", err->message);
+ g_assert_not_reached ();
+}
+
+char main_buf[sizeof (DATA)];
+gssize main_len, main_offset;
+
+static void readable (GObject *source, GAsyncResult *res, gpointer user_data);
+static void writable (GObject *source, GAsyncResult *res, gpointer user_data);
+
+static void
+do_main_cancel (GOutputStream *out)
+{
+ g_output_stream_close (out, NULL, NULL);
+ g_main_loop_quit (loop);
+}
+
+static void
+readable (GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ GInputStream *in = G_INPUT_STREAM (source);
+ GOutputStream *out = user_data;
+ GError *err = NULL;
+
+ main_len = g_input_stream_read_finish (in, res, &err);
+
+ if (g_cancellable_is_cancelled (main_cancel))
+ {
+ do_main_cancel (out);
+ return;
+ }
+
+ g_assert (err == NULL);
+
+ main_offset = 0;
+ g_output_stream_write_async (out, main_buf, main_len,
+ G_PRIORITY_DEFAULT, main_cancel,
+ writable, in);
+}
+
+static void
+writable (GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ GOutputStream *out = G_OUTPUT_STREAM (source);
+ GInputStream *in = user_data;
+ GError *err = NULL;
+ gssize nwrote;
+
+ nwrote = g_output_stream_write_finish (out, res, &err);
+
+ if (g_cancellable_is_cancelled (main_cancel))
+ {
+ do_main_cancel (out);
+ return;
+ }
+
+ g_assert (err == NULL);
+ g_assert_cmpint (nwrote, <=, main_len - main_offset);
+
+ main_offset += nwrote;
+ if (main_offset == main_len)
+ {
+ g_input_stream_read_async (in, main_buf, sizeof (main_buf),
+ G_PRIORITY_DEFAULT, main_cancel,
+ readable, out);
+ }
+ else
+ {
+ g_output_stream_write_async (out, main_buf + main_offset,
+ main_len - main_offset,
+ G_PRIORITY_DEFAULT, main_cancel,
+ writable, in);
+ }
+}
+
+static gboolean
+timeout (gpointer cancellable)
+{
+ g_cancellable_cancel (cancellable);
+ return FALSE;
+}
+
+static void
+test_pipe_io (void)
+{
+ GThread *writer, *reader;
+ GInputStream *in;
+ GOutputStream *out;
+
+ /* Split off two (additional) threads, a reader and a writer. From
+ * the writer thread, write data synchronously in small chunks,
+ * which gets read asynchronously by the main thread and then
+ * written asynchronously to the reader thread, which reads it
+ * synchronously. Eventually a timeout in the main thread will cause
+ * it to cancel the writer thread, which will in turn cancel the
+ * read op in the main thread, which will then close the pipe to
+ * the reader thread, causing the read op to fail.
+ */
+
+ g_assert (pipe (writer_pipe) == 0 && pipe (reader_pipe) == 0);
+
+ writer_cancel = g_cancellable_new ();
+ reader_cancel = g_cancellable_new ();
+ main_cancel = g_cancellable_new ();
+
+ writer = g_thread_create (writer_thread, NULL, TRUE, NULL);
+ reader = g_thread_create (reader_thread, NULL, TRUE, NULL);
+
+ in = g_unix_input_stream_new (writer_pipe[0], TRUE);
+ out = g_unix_output_stream_new (reader_pipe[1], TRUE);
+
+ g_input_stream_read_async (in, main_buf, sizeof (main_buf),
+ G_PRIORITY_DEFAULT, main_cancel,
+ readable, out);
+
+ g_timeout_add (500, timeout, writer_cancel);
+
+ loop = g_main_loop_new (NULL, TRUE);
+ g_main_loop_run (loop);
+ g_main_loop_unref (loop);
+
+ g_thread_join (reader);
+ g_thread_join (writer);
+
+ g_object_unref (main_cancel);
+ g_object_unref (reader_cancel);
+ g_object_unref (writer_cancel);
+ g_object_unref (in);
+ g_object_unref (out);
+}
+
+int
+main (int argc,
+ char *argv[])
+{
+ g_thread_init (NULL);
+ g_type_init ();
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add_func ("/unix-streams/pipe-io-test", test_pipe_io);
+
+ return g_test_run();
+}