From a9c978a354d236a2cb6eb55ae8ff3dbd2c797960 Mon Sep 17 00:00:00 2001 From: Ryan Lortie Date: Wed, 21 Jan 2009 14:09:56 +0000 Subject: [PATCH] =?utf8?q?Bug=20568394=20=E2=80=93=20dropping=20the=20last?= =?utf8?q?=20reference=20to=20a=20stream=20filter=20closes=20the?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 2009-01-20 Ryan Lortie Bug 568394 – dropping the last reference to a stream filter closes the base stream * gfilterinputstream.h: * gfilterinputstream.c: add "close-base-stream" property and only close the base stream if it is true. issue async close callbacks from correct source object. * gfilteroutputstream.h: * gfilteroutputstream.c: add a "close-base-stream" property and only close the base stream if it is true. issue async close callbacks from correct source object. * gbufferedoutputstream: check g_filter_output_stream_get_close_base() before closing the base stream. fix invalid source tag comparison in close_async (was comparing to flush_async). * ../docs/reference/gio/gio-sections.txt: * gio.symbols: add g_filter_{in,out}put_stream_{g,s}et_close_base_stream * tests/filter-streams.c: new test cases * tests/Makefile.am: add new test * tests/.gitignore: add new test svn path=/trunk/; revision=7825 --- docs/reference/gio/gio-sections.txt | 4 + gio/ChangeLog | 23 ++++ gio/gbufferedoutputstream.c | 26 ++-- gio/gfilterinputstream.c | 153 +++++++++++++++++++---- gio/gfilterinputstream.h | 8 +- gio/gfilteroutputstream.c | 146 ++++++++++++++++++---- gio/gfilteroutputstream.h | 8 +- gio/gio.symbols | 4 + gio/tests/.gitignore | 1 + gio/tests/Makefile.am | 4 + gio/tests/filter-streams.c | 239 ++++++++++++++++++++++++++++++++++++ 11 files changed, 551 insertions(+), 65 deletions(-) create mode 100644 gio/tests/filter-streams.c diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt index b2754bd..6018131 100644 --- a/docs/reference/gio/gio-sections.txt +++ b/docs/reference/gio/gio-sections.txt @@ -518,6 +518,8 @@ GFileInputStreamPrivate GFilterInputStream GFilterInputStream g_filter_input_stream_get_base_stream +g_filter_input_stream_get_close_base_stream +g_filter_input_stream_set_close_base_stream GFilterInputStreamClass G_FILTER_INPUT_STREAM @@ -694,6 +696,8 @@ GFileOutputStreamPrivate GFilterOutputStream GFilterOutputStream g_filter_output_stream_get_base_stream +g_filter_output_stream_get_close_base_stream +g_filter_output_stream_set_close_base_stream GFilterOutputStreamClass G_FILTER_OUTPUT_STREAM diff --git a/gio/ChangeLog b/gio/ChangeLog index 4c89223..e5ded97 100644 --- a/gio/ChangeLog +++ b/gio/ChangeLog @@ -1,3 +1,26 @@ +2009-01-20 Ryan Lortie + + Bug 568394 – dropping the last reference to a stream filter closes the + base stream + + * gfilterinputstream.h: + * gfilterinputstream.c: add "close-base-stream" property and only + close the base stream if it is true. issue async close callbacks from + correct source object. + * gfilteroutputstream.h: + * gfilteroutputstream.c: add a "close-base-stream" property and only + close the base stream if it is true. issue async close callbacks from + correct source object. + * gbufferedoutputstream: check g_filter_output_stream_get_close_base() + before closing the base stream. fix invalid source tag comparison in + close_async (was comparing to flush_async). + * ../docs/reference/gio/gio-sections.txt: + * gio.symbols: add + g_filter_{in,out}put_stream_{g,s}et_close_base_stream + * tests/filter-streams.c: new test cases + * tests/Makefile.am: add new test + * tests/.gitignore: add new test + 2009-01-19 Matthias Clasen * gdesktopappinfo.c (g_desktop_app_info_new): Expand the docs. diff --git a/gio/gbufferedoutputstream.c b/gio/gbufferedoutputstream.c index 92b5f43..5bb6a98 100644 --- a/gio/gbufferedoutputstream.c +++ b/gio/gbufferedoutputstream.c @@ -508,11 +508,14 @@ g_buffered_output_stream_close (GOutputStream *stream, res = flush_buffer (bstream, cancellable, error); - /* report the first error but still close the stream */ - if (res) - res = g_output_stream_close (base_stream, cancellable, error); - else - g_output_stream_close (base_stream, cancellable, NULL); + if (g_filter_output_stream_get_close_base_stream (G_FILTER_OUTPUT_STREAM (stream))) + { + /* report the first error but still close the stream */ + if (res) + res = g_output_stream_close (base_stream, cancellable, error); + else + g_output_stream_close (base_stream, cancellable, NULL); + } return res; } @@ -569,10 +572,13 @@ flush_buffer_thread (GSimpleAsyncResult *result, /* if flushing the buffer or the stream returned * an error report that first error but still try * close the stream */ - if (res == FALSE) - g_output_stream_close (base_stream, cancellable, NULL); - else - res = g_output_stream_close (base_stream, cancellable, &error); + if (g_filter_output_stream_get_close_base_stream (G_FILTER_OUTPUT_STREAM (stream))) + { + if (res == FALSE) + g_output_stream_close (base_stream, cancellable, NULL); + else + res = g_output_stream_close (base_stream, cancellable, &error); + } } if (res == FALSE) @@ -758,7 +764,7 @@ g_buffered_output_stream_close_finish (GOutputStream *stream, simple = G_SIMPLE_ASYNC_RESULT (result); g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == - g_buffered_output_stream_flush_async); + g_buffered_output_stream_close_async); return TRUE; } diff --git a/gio/gfilterinputstream.c b/gio/gfilterinputstream.c index 14b7cde..86d001e 100644 --- a/gio/gfilterinputstream.c +++ b/gio/gfilterinputstream.c @@ -23,6 +23,7 @@ #include "config.h" #include "gfilterinputstream.h" #include "ginputstream.h" +#include "gsimpleasyncresult.h" #include "glibintl.h" #include "gioalias.h" @@ -36,7 +37,8 @@ enum { PROP_0, - PROP_BASE_STREAM + PROP_BASE_STREAM, + PROP_CLOSE_BASE }; static void g_filter_input_stream_set_property (GObject *object, @@ -93,6 +95,13 @@ static gboolean g_filter_input_stream_close_finish (GInputStream *stream G_DEFINE_TYPE (GFilterInputStream, g_filter_input_stream, G_TYPE_INPUT_STREAM) +#define GET_PRIVATE(inst) G_TYPE_INSTANCE_GET_PRIVATE (inst, \ + G_TYPE_FILTER_INPUT_STREAM, GFilterInputStreamPrivate) + +typedef struct +{ + gboolean close_base; +} GFilterInputStreamPrivate; static void g_filter_input_stream_class_init (GFilterInputStreamClass *klass) @@ -117,6 +126,8 @@ g_filter_input_stream_class_init (GFilterInputStreamClass *klass) istream_class->close_async = g_filter_input_stream_close_async; istream_class->close_finish = g_filter_input_stream_close_finish; + g_type_class_add_private (klass, sizeof (GFilterInputStreamPrivate)); + g_object_class_install_property (object_class, PROP_BASE_STREAM, g_param_spec_object ("base-stream", @@ -126,6 +137,13 @@ g_filter_input_stream_class_init (GFilterInputStreamClass *klass) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB)); + g_object_class_install_property (object_class, + PROP_CLOSE_BASE, + g_param_spec_boolean ("close-base-stream", + P_("Close Base Stream"), + P_("If the base stream be closed when the filter stream is"), + TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB)); } static void @@ -146,6 +164,11 @@ g_filter_input_stream_set_property (GObject *object, filter_stream->base_stream = G_INPUT_STREAM (obj); break; + case PROP_CLOSE_BASE: + g_filter_input_stream_set_close_base_stream (filter_stream, + g_value_get_boolean (value)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -169,6 +192,10 @@ g_filter_input_stream_get_property (GObject *object, g_value_set_object (value, filter_stream->base_stream); break; + case PROP_CLOSE_BASE: + g_value_set_boolean (value, GET_PRIVATE (filter_stream)->close_base); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -210,6 +237,49 @@ g_filter_input_stream_get_base_stream (GFilterInputStream *stream) return stream->base_stream; } +/** + * g_filter_input_stream_get_close_base_stream: + * @stream: a #GFilterInputStream. + * + * Returns whether the base stream will be closed when @stream is + * closed. + * + * Return value: %TRUE if the base stream will be closed. + **/ +gboolean +g_filter_input_stream_get_close_base_stream (GFilterInputStream *stream) +{ + g_return_val_if_fail (G_IS_FILTER_INPUT_STREAM (stream), FALSE); + + return GET_PRIVATE (stream)->close_base; +} + +/** + * g_filter_input_stream_set_close_base_stream: + * @stream: a #GFilterInputStream. + * @close_base: %TRUE to close the base stream. + * + * Sets whether the base stream will be closed when @stream is closed. + **/ +void +g_filter_input_stream_set_close_base_stream (GFilterInputStream *stream, + gboolean close_base) +{ + GFilterInputStreamPrivate *priv; + + g_return_if_fail (G_IS_FILTER_INPUT_STREAM (stream)); + + close_base = !!close_base; + + priv = GET_PRIVATE (stream); + + if (priv->close_base != close_base) + { + priv->close_base = close_base; + g_object_notify (G_OBJECT (stream), "close-base-stream"); + } +} + static gssize g_filter_input_stream_read (GInputStream *stream, void *buffer, @@ -258,16 +328,20 @@ g_filter_input_stream_close (GInputStream *stream, GCancellable *cancellable, GError **error) { - GFilterInputStream *filter_stream; - GInputStream *base_stream; - gboolean res; + gboolean res = TRUE; - filter_stream = G_FILTER_INPUT_STREAM (stream); - base_stream = filter_stream->base_stream; + if (GET_PRIVATE (stream)->close_base) + { + GFilterInputStream *filter_stream; + GInputStream *base_stream; - res = g_input_stream_close (base_stream, - cancellable, - error); + filter_stream = G_FILTER_INPUT_STREAM (stream); + base_stream = filter_stream->base_stream; + + res = g_input_stream_close (base_stream, + cancellable, + error); + } return res; } @@ -358,23 +432,52 @@ g_filter_input_stream_skip_finish (GInputStream *stream, } static void +g_filter_input_stream_close_ready (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *simple = user_data; + GError *error = NULL; + + g_input_stream_close_finish (G_INPUT_STREAM (object), result, &error); + + if (error) + { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); + } + + g_simple_async_result_complete (simple); + g_object_unref (simple); +} + +static void g_filter_input_stream_close_async (GInputStream *stream, int io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { - GFilterInputStream *filter_stream; - GInputStream *base_stream; + GSimpleAsyncResult *simple; - filter_stream = G_FILTER_INPUT_STREAM (stream); - base_stream = filter_stream->base_stream; + simple = g_simple_async_result_new (G_OBJECT (stream), + callback, user_data, + g_filter_input_stream_close_async); + + if (GET_PRIVATE (stream)->close_base) + { + GFilterInputStream *filter_stream = G_FILTER_INPUT_STREAM (stream); - g_input_stream_close_async (base_stream, - io_priority, - cancellable, - callback, - user_data); + g_input_stream_close_async (filter_stream->base_stream, + io_priority, cancellable, + g_filter_input_stream_close_ready, + g_object_ref (simple)); + } + else + /* do nothing */ + g_simple_async_result_complete_in_idle (simple); + + g_object_unref (simple); } static gboolean @@ -382,18 +485,14 @@ g_filter_input_stream_close_finish (GInputStream *stream, GAsyncResult *result, GError **error) { - GFilterInputStream *filter_stream; - GInputStream *base_stream; - gboolean res; + GSimpleAsyncResult *simple; - filter_stream = G_FILTER_INPUT_STREAM (stream); - base_stream = filter_stream->base_stream; + g_return_val_if_fail (g_simple_async_result_is_valid ( + result, G_OBJECT (stream), g_filter_input_stream_close_async), FALSE); - res = g_input_stream_close_finish (stream, - result, - error); + simple = G_SIMPLE_ASYNC_RESULT (result); - return res; + return !g_simple_async_result_propagate_error (simple, error); } #define __G_FILTER_INPUT_STREAM_C__ diff --git a/gio/gfilterinputstream.h b/gio/gfilterinputstream.h index 91ba7b5..1514104 100644 --- a/gio/gfilterinputstream.h +++ b/gio/gfilterinputstream.h @@ -44,7 +44,6 @@ G_BEGIN_DECLS * A base class for all input streams that work on an underlying stream. **/ typedef struct _GFilterInputStreamClass GFilterInputStreamClass; -typedef struct _GFilterInputStreamPrivate GFilterInputStreamPrivate; struct _GFilterInputStream { @@ -66,8 +65,11 @@ struct _GFilterInputStreamClass }; -GType g_filter_input_stream_get_type (void) G_GNUC_CONST; -GInputStream * g_filter_input_stream_get_base_stream (GFilterInputStream *stream); +GType g_filter_input_stream_get_type (void) G_GNUC_CONST; +GInputStream * g_filter_input_stream_get_base_stream (GFilterInputStream *stream); +gboolean g_filter_input_stream_get_close_base_stream (GFilterInputStream *stream); +void g_filter_input_stream_set_close_base_stream (GFilterInputStream *stream, + gboolean close_base); G_END_DECLS diff --git a/gio/gfilteroutputstream.c b/gio/gfilteroutputstream.c index 9881ab1..8706941 100644 --- a/gio/gfilteroutputstream.c +++ b/gio/gfilteroutputstream.c @@ -22,6 +22,7 @@ #include "config.h" #include "gfilteroutputstream.h" +#include "gsimpleasyncresult.h" #include "goutputstream.h" #include "glibintl.h" @@ -36,7 +37,8 @@ enum { PROP_0, - PROP_BASE_STREAM + PROP_BASE_STREAM, + PROP_CLOSE_BASE }; static void g_filter_output_stream_set_property (GObject *object, @@ -93,7 +95,13 @@ static gboolean g_filter_output_stream_close_finish (GOutputStream *strea G_DEFINE_TYPE (GFilterOutputStream, g_filter_output_stream, G_TYPE_OUTPUT_STREAM) +#define GET_PRIVATE(inst) G_TYPE_INSTANCE_GET_PRIVATE (inst, \ + G_TYPE_FILTER_OUTPUT_STREAM, GFilterOutputStreamPrivate) +typedef struct +{ + gboolean close_base; +} GFilterOutputStreamPrivate; static void g_filter_output_stream_class_init (GFilterOutputStreamClass *klass) @@ -117,6 +125,8 @@ g_filter_output_stream_class_init (GFilterOutputStreamClass *klass) ostream_class->close_async = g_filter_output_stream_close_async; ostream_class->close_finish = g_filter_output_stream_close_finish; + g_type_class_add_private (klass, sizeof (GFilterOutputStreamPrivate)); + g_object_class_install_property (object_class, PROP_BASE_STREAM, g_param_spec_object ("base-stream", @@ -126,6 +136,13 @@ g_filter_output_stream_class_init (GFilterOutputStreamClass *klass) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB)); + g_object_class_install_property (object_class, + PROP_CLOSE_BASE, + g_param_spec_boolean ("close-base-stream", + P_("Close Base Stream"), + P_("If the base stream be closed when the filter stream is"), + TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB)); } static void @@ -146,6 +163,11 @@ g_filter_output_stream_set_property (GObject *object, filter_stream->base_stream = G_OUTPUT_STREAM (obj); break; + case PROP_CLOSE_BASE: + g_filter_output_stream_set_close_base_stream (filter_stream, + g_value_get_boolean (value)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -169,6 +191,10 @@ g_filter_output_stream_get_property (GObject *object, g_value_set_object (value, filter_stream->base_stream); break; + case PROP_CLOSE_BASE: + g_value_set_boolean (value, GET_PRIVATE (filter_stream)->close_base); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -214,6 +240,49 @@ g_filter_output_stream_get_base_stream (GFilterOutputStream *stream) return stream->base_stream; } +/** + * g_filter_output_stream_get_close_base_stream: + * @stream: a #GFilterOutputStream. + * + * Returns whether the base stream will be closed when @stream is + * closed. + * + * Return value: %TRUE if the base stream will be closed. + **/ +gboolean +g_filter_output_stream_get_close_base_stream (GFilterOutputStream *stream) +{ + g_return_val_if_fail (G_IS_FILTER_OUTPUT_STREAM (stream), FALSE); + + return GET_PRIVATE (stream)->close_base; +} + +/** + * g_filter_output_stream_set_close_base_stream: + * @stream: a #GFilterOutputStream. + * @close_base: %TRUE to close the base stream. + * + * Sets whether the base stream will be closed when @stream is closed. + **/ +void +g_filter_output_stream_set_close_base_stream (GFilterOutputStream *stream, + gboolean close_base) +{ + GFilterOutputStreamPrivate *priv; + + g_return_if_fail (G_IS_FILTER_OUTPUT_STREAM (stream)); + + close_base = !!close_base; + + priv = GET_PRIVATE (stream); + + if (priv->close_base != close_base) + { + priv->close_base = close_base; + g_object_notify (G_OBJECT (stream), "close-base-stream"); + } +} + static gssize g_filter_output_stream_write (GOutputStream *stream, const void *buffer, @@ -257,14 +326,18 @@ g_filter_output_stream_close (GOutputStream *stream, GCancellable *cancellable, GError **error) { - GFilterOutputStream *filter_stream; - gboolean res; + gboolean res = TRUE; - filter_stream = G_FILTER_OUTPUT_STREAM (stream); + if (GET_PRIVATE (stream)->close_base) + { + GFilterOutputStream *filter_stream; - res = g_output_stream_close (filter_stream->base_stream, - cancellable, - error); + filter_stream = G_FILTER_OUTPUT_STREAM (stream); + + res = g_output_stream_close (filter_stream->base_stream, + cancellable, + error); + } return res; } @@ -345,21 +418,52 @@ g_filter_output_stream_flush_finish (GOutputStream *stream, } static void +g_filter_output_stream_close_ready (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *simple = user_data; + GError *error = NULL; + + g_output_stream_close_finish (G_OUTPUT_STREAM (object), result, &error); + + if (error) + { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); + } + + g_simple_async_result_complete (simple); + g_object_unref (simple); +} + +static void g_filter_output_stream_close_async (GOutputStream *stream, int io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, - gpointer data) + gpointer user_data) { - GFilterOutputStream *filter_stream; + GSimpleAsyncResult *simple; - filter_stream = G_FILTER_OUTPUT_STREAM (stream); + simple = g_simple_async_result_new (G_OBJECT (stream), + callback, user_data, + g_filter_output_stream_close_async); - g_output_stream_close_async (filter_stream->base_stream, - io_priority, - cancellable, - callback, - data); + if (GET_PRIVATE (stream)->close_base) + { + GFilterOutputStream *filter_stream = G_FILTER_OUTPUT_STREAM (stream); + + g_output_stream_close_async (filter_stream->base_stream, + io_priority, cancellable, + g_filter_output_stream_close_ready, + g_object_ref (simple)); + } + else + /* do nothing */ + g_simple_async_result_complete_in_idle (simple); + + g_object_unref (simple); } static gboolean @@ -367,16 +471,14 @@ g_filter_output_stream_close_finish (GOutputStream *stream, GAsyncResult *result, GError **error) { - GFilterOutputStream *filter_stream; - gboolean res; + GSimpleAsyncResult *simple; - filter_stream = G_FILTER_OUTPUT_STREAM (stream); + g_return_val_if_fail (g_simple_async_result_is_valid ( + result, G_OBJECT (stream), g_filter_output_stream_close_async), FALSE); - res = g_output_stream_close_finish (filter_stream->base_stream, - result, - error); + simple = G_SIMPLE_ASYNC_RESULT (result); - return res; + return !g_simple_async_result_propagate_error (simple, error); } #define __G_FILTER_OUTPUT_STREAM_C__ diff --git a/gio/gfilteroutputstream.h b/gio/gfilteroutputstream.h index 6ccb0d4..10350e5 100644 --- a/gio/gfilteroutputstream.h +++ b/gio/gfilteroutputstream.h @@ -44,7 +44,6 @@ G_BEGIN_DECLS * A base class for all output streams that work on an underlying stream. **/ typedef struct _GFilterOutputStreamClass GFilterOutputStreamClass; -typedef struct _GFilterOutputStreamPrivate GFilterOutputStreamPrivate; struct _GFilterOutputStream { @@ -66,8 +65,11 @@ struct _GFilterOutputStreamClass }; -GType g_filter_output_stream_get_type (void) G_GNUC_CONST; -GOutputStream * g_filter_output_stream_get_base_stream (GFilterOutputStream *stream); +GType g_filter_output_stream_get_type (void) G_GNUC_CONST; +GOutputStream * g_filter_output_stream_get_base_stream (GFilterOutputStream *stream); +gboolean g_filter_output_stream_get_close_base_stream (GFilterOutputStream *stream); +void g_filter_output_stream_set_close_base_stream (GFilterOutputStream *stream, + gboolean close_base); G_END_DECLS diff --git a/gio/gio.symbols b/gio/gio.symbols index de2268b..2e8a363 100644 --- a/gio/gio.symbols +++ b/gio/gio.symbols @@ -456,6 +456,8 @@ g_file_output_stream_get_etag #if IN_FILE(__G_FILTER_INPUT_STREAM_C__) g_filter_input_stream_get_type G_GNUC_CONST g_filter_input_stream_get_base_stream +g_filter_input_stream_get_close_base_stream +g_filter_input_stream_set_close_base_stream #endif #endif @@ -463,6 +465,8 @@ g_filter_input_stream_get_base_stream #if IN_FILE(__G_FILTER_OUTPUT_STREAM_C__) g_filter_output_stream_get_type G_GNUC_CONST g_filter_output_stream_get_base_stream +g_filter_output_stream_get_close_base_stream +g_filter_output_stream_set_close_base_stream #endif #endif diff --git a/gio/tests/.gitignore b/gio/tests/.gitignore index e770aaa..8985d06 100644 --- a/gio/tests/.gitignore +++ b/gio/tests/.gitignore @@ -10,3 +10,4 @@ g-file-info live-g-file memory-input-stream memory-output-stream +filter-streams diff --git a/gio/tests/Makefile.am b/gio/tests/Makefile.am index abfe883..5e974a4 100644 --- a/gio/tests/Makefile.am +++ b/gio/tests/Makefile.am @@ -25,6 +25,7 @@ TEST_PROGS += \ data-output-stream \ g-icon \ buffered-input-stream \ + filter-streams \ simple-async-result if OS_UNIX @@ -68,4 +69,7 @@ unix_streams_LDADD = $(progs_ldadd) \ simple_async_result_SOURCES = simple-async-result.c simple_async_result_LDADD = $(progs_ldadd) +filter_streams_SOURCES = filter-streams.c +filter_streams_LDADD = $(progs_ldadd) + DISTCLEAN_FILES = applications/mimeinfo.cache diff --git a/gio/tests/filter-streams.c b/gio/tests/filter-streams.c new file mode 100644 index 0000000..fab17ff --- /dev/null +++ b/gio/tests/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 + */ + +#include +#include + +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(); +} -- 2.7.4