glib r7825 - in trunk: docs/reference/gio gio gio/tests



Author: ryanl
Date: Wed Jan 21 14:09:56 2009
New Revision: 7825
URL: http://svn.gnome.org/viewvc/glib?rev=7825&view=rev

Log:
2009-01-20  Ryan Lortie  <desrt desrt ca>

        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



Added:
   trunk/gio/tests/filter-streams.c
Modified:
   trunk/docs/reference/gio/gio-sections.txt
   trunk/gio/ChangeLog
   trunk/gio/gbufferedoutputstream.c
   trunk/gio/gfilterinputstream.c
   trunk/gio/gfilterinputstream.h
   trunk/gio/gfilteroutputstream.c
   trunk/gio/gfilteroutputstream.h
   trunk/gio/gio.symbols
   trunk/gio/tests/.gitignore
   trunk/gio/tests/Makefile.am

Modified: trunk/docs/reference/gio/gio-sections.txt
==============================================================================
--- trunk/docs/reference/gio/gio-sections.txt	(original)
+++ trunk/docs/reference/gio/gio-sections.txt	Wed Jan 21 14:09:56 2009
@@ -518,6 +518,8 @@
 <TITLE>GFilterInputStream</TITLE>
 GFilterInputStream
 g_filter_input_stream_get_base_stream
+g_filter_input_stream_get_close_base_stream
+g_filter_input_stream_set_close_base_stream
 <SUBSECTION Standard>
 GFilterInputStreamClass
 G_FILTER_INPUT_STREAM
@@ -694,6 +696,8 @@
 <TITLE>GFilterOutputStream</TITLE>
 GFilterOutputStream
 g_filter_output_stream_get_base_stream
+g_filter_output_stream_get_close_base_stream
+g_filter_output_stream_set_close_base_stream
 <SUBSECTION Standard>
 GFilterOutputStreamClass
 G_FILTER_OUTPUT_STREAM

Modified: trunk/gio/gbufferedoutputstream.c
==============================================================================
--- trunk/gio/gbufferedoutputstream.c	(original)
+++ trunk/gio/gbufferedoutputstream.c	Wed Jan 21 14:09:56 2009
@@ -508,11 +508,14 @@
 
   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 @@
       /* 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 @@
   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;
 }

Modified: trunk/gio/gfilterinputstream.c
==============================================================================
--- trunk/gio/gfilterinputstream.c	(original)
+++ trunk/gio/gfilterinputstream.c	Wed Jan 21 14:09:56 2009
@@ -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 @@
 
 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 @@
   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_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 @@
       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_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 @@
   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 @@
                              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 @@
 }
 
 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 @@
                                     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__

Modified: trunk/gio/gfilterinputstream.h
==============================================================================
--- trunk/gio/gfilterinputstream.h	(original)
+++ trunk/gio/gfilterinputstream.h	Wed Jan 21 14:09:56 2009
@@ -44,7 +44,6 @@
  * 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 @@
 };
 
 
-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
 

Modified: trunk/gio/gfilteroutputstream.c
==============================================================================
--- trunk/gio/gfilteroutputstream.c	(original)
+++ trunk/gio/gfilteroutputstream.c	Wed Jan 21 14:09:56 2009
@@ -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 @@
 
 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 @@
   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_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 @@
       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_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 @@
   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 @@
                               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 @@
 }
 
 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 @@
                                      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__

Modified: trunk/gio/gfilteroutputstream.h
==============================================================================
--- trunk/gio/gfilteroutputstream.h	(original)
+++ trunk/gio/gfilteroutputstream.h	Wed Jan 21 14:09:56 2009
@@ -44,7 +44,6 @@
  * 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 @@
 };
 
 
-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
 

Modified: trunk/gio/gio.symbols
==============================================================================
--- trunk/gio/gio.symbols	(original)
+++ trunk/gio/gio.symbols	Wed Jan 21 14:09:56 2009
@@ -456,6 +456,8 @@
 #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 @@
 #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
 

Modified: trunk/gio/tests/.gitignore
==============================================================================
--- trunk/gio/tests/.gitignore	(original)
+++ trunk/gio/tests/.gitignore	Wed Jan 21 14:09:56 2009
@@ -10,3 +10,4 @@
 live-g-file
 memory-input-stream
 memory-output-stream
+filter-streams

Modified: trunk/gio/tests/Makefile.am
==============================================================================
--- trunk/gio/tests/Makefile.am	(original)
+++ trunk/gio/tests/Makefile.am	Wed Jan 21 14:09:56 2009
@@ -25,6 +25,7 @@
 	data-output-stream 	\
 	g-icon			\
 	buffered-input-stream	\
+	filter-streams		\
 	simple-async-result
 
 if OS_UNIX
@@ -68,4 +69,7 @@
 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

Added: trunk/gio/tests/filter-streams.c
==============================================================================
--- (empty file)
+++ trunk/gio/tests/filter-streams.c	Wed Jan 21 14:09:56 2009
@@ -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();
+}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]