Boost logo

Boost-Commit :

From: Frank.Birbacher_at_[hidden]
Date: 2007-11-02 17:19:49


Author: birbacher
Date: 2007-11-02 17:19:48 EDT (Fri, 02 Nov 2007)
New Revision: 40700
URL: http://svn.boost.org/trac/boost/changeset/40700

Log:
Test case and possible fix for Issue #1002

Text files modified:
   sandbox-branches/birbacher/fix_iostreams/boost/iostreams/close.hpp | 29 ++++++--
   sandbox-branches/birbacher/fix_iostreams/libs/iostreams/doc/functions/close.html | 2
   sandbox-branches/birbacher/fix_iostreams/libs/iostreams/test/auto_close_test.cpp | 124 ++++++++++++++++++++++++++++++---------
   3 files changed, 116 insertions(+), 39 deletions(-)

Modified: sandbox-branches/birbacher/fix_iostreams/boost/iostreams/close.hpp
==============================================================================
--- sandbox-branches/birbacher/fix_iostreams/boost/iostreams/close.hpp (original)
+++ sandbox-branches/birbacher/fix_iostreams/boost/iostreams/close.hpp 2007-11-02 17:19:48 EDT (Fri, 02 Nov 2007)
@@ -101,21 +101,33 @@
 template<>
 struct close_impl<closable_tag> {
     template<typename T>
- static void close(T& t, BOOST_IOS::openmode which)
+ static bool should_close(BOOST_IOS::openmode const which)
     {
         typedef typename category_of<T>::type category;
- const bool in = is_convertible<category, input>::value &&
- !is_convertible<category, output>::value;
- if (in == ((which & BOOST_IOS::in) != 0))
+ static const bool hasIn = is_convertible<category, input>::value;
+ static const bool hasOut = is_convertible<category, output>::value;
+ BOOST_STATIC_ASSERT(hasIn || hasOut); //needs input or output
+
+ if(hasIn && hasOut)
+ return false;
+ return
+ (which & BOOST_IOS::in) && hasIn
+ ||
+ (which & BOOST_IOS::out) && hasOut
+ ;
+ }
+
+ template<typename T>
+ static void close(T& t, BOOST_IOS::openmode which)
+ {
+ if ( should_close<T>(which) )
             t.close();
     }
+
     template<typename T, typename Sink>
     static void close(T& t, Sink& snk, BOOST_IOS::openmode which)
     {
- typedef typename category_of<T>::type category;
- const bool in = is_convertible<category, input>::value &&
- !is_convertible<category, output>::value;
- if (in == ((which & BOOST_IOS::in) != 0)) {
+ if ( should_close<T>(which) ) {
             non_blocking_adapter<Sink> nb(snk);
             t.close(nb);
         }
@@ -126,6 +138,7 @@
 struct close_impl<two_sequence> {
     template<typename T>
     static void close(T& t, BOOST_IOS::openmode which) { t.close(which); }
+
     template<typename T, typename Sink>
     static void close(T& t, Sink& snk, BOOST_IOS::openmode which)
     {

Modified: sandbox-branches/birbacher/fix_iostreams/libs/iostreams/doc/functions/close.html
==============================================================================
--- sandbox-branches/birbacher/fix_iostreams/libs/iostreams/doc/functions/close.html (original)
+++ sandbox-branches/birbacher/fix_iostreams/libs/iostreams/doc/functions/close.html 2007-11-02 17:19:48 EDT (Fri, 02 Nov 2007)
@@ -131,7 +131,7 @@
         <TD>calls <CODE>t.close()</CODE> if <CODE>(which & ios_base::in) != 0</CODE></TD>
     </TR>
     <TR>
- <TD VALIGN="top">convertible to closable_tag and to output but not to bidirectional</TD>
+ <TD VALIGN="top">convertible to closable_tag and to output but not to input</TD>
         <TD>calls <CODE>t.close()</CODE> if <CODE>(which & ios_base::out) != 0</CODE></TD>
     </TR>
 </TABLE>

Modified: sandbox-branches/birbacher/fix_iostreams/libs/iostreams/test/auto_close_test.cpp
==============================================================================
--- sandbox-branches/birbacher/fix_iostreams/libs/iostreams/test/auto_close_test.cpp (original)
+++ sandbox-branches/birbacher/fix_iostreams/libs/iostreams/test/auto_close_test.cpp 2007-11-02 17:19:48 EDT (Fri, 02 Nov 2007)
@@ -1,4 +1,5 @@
 // (C) Copyright Jonathan Turkanis 2004
+// (C) Copyright Frank Birbacher 2007
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
 
@@ -7,6 +8,7 @@
 #include <cstdio> // EOF.
 #include <boost/iostreams/filtering_stream.hpp>
 #include <boost/iostreams/stream.hpp>
+#include <boost/iostreams/tee.hpp>
 #include <boost/shared_ptr.hpp>
 #include <boost/test/test_tools.hpp>
 #include <boost/test/unit_test.hpp>
@@ -19,17 +21,71 @@
 using namespace boost::iostreams::test;
 using boost::unit_test::test_suite;
 
-class closable_source : public source {
-public:
- closable_source() : open_(new bool(true)) { }
- std::streamsize read(char*, std::streamsize) { return 0; }
+/* Implements observers for checking open state of device.
+ * This class shall derive from the real device. The original
+ * open and close methods are then hidden by the ones defined
+ * here. Meant to be used only in this unit test.
+ */
+template<typename Base>
+struct checker : Base
+{
+ checker() : open_(new bool(true)) { }
     void open() { *open_ = true; }
- void close() { *open_ = false; }
+ void close() { if(!open_) throw 0; *open_ = false; }
+ void close(std::ios_base::openmode)
+ { close(); }
     bool is_open() const { return *open_; }
 private:
     boost::shared_ptr<bool> open_;
 };
 
+/* A no-op observable source */
+struct closable_source
+ : public checker<source>
+{
+ std::streamsize read(char*, std::streamsize) { return 0; }
+};
+
+/* A no-op observable sink */
+struct closable_sink
+ : public checker<sink>
+{
+ std::streamsize write(const char*, std::streamsize) { return 0; }
+};
+
+/* A no-op observable bidirectional device */
+struct Empty {}; //Helper
+struct closable_bidir
+ : public checker<Empty>
+{
+ typedef char char_type;
+ struct category
+ : closable_tag
+ , bidirectional_device_tag
+ {};
+
+ std::streamsize read(char*, std::streamsize) { return 0; }
+ std::streamsize write(const char*, std::streamsize) { return 0; }
+};
+
+/* A no-op observable tee device */
+struct closable_tee_sink_base
+{
+ closable_sink s1, s2;
+};
+struct closable_tee_sink
+ : public closable_tee_sink_base
+ , public tee_device<closable_sink, closable_sink>
+{
+ closable_tee_sink()
+ : closable_tee_sink_base() //first to construct
+ , tee_device<closable_sink, closable_sink>(s1, s2)
+ {}
+ bool is_open() const { return s1.is_open() || s2.is_open(); }
+ void open() { s1.open(); s2.open(); }
+};
+
+/* A no-op observable filter */
 class closable_input_filter : public input_filter {
 public:
     closable_input_filter() : open_(new bool(true)) { }
@@ -47,48 +103,53 @@
     boost::shared_ptr<bool> open_;
 };
 
-void auto_close_source()
+////////////////////////////////////////////////////////////////////////////////
+
+/* Test closing a device */
+template<typename Device>
+void auto_close()
 {
     // Rely on auto_close to close source.
- closable_source src;
+ Device dev;
     {
- stream<closable_source> in(src);
- BOOST_CHECK(src.is_open());
- BOOST_CHECK(in.auto_close());
+ stream<Device> strm(dev);
+ BOOST_CHECK(dev.is_open());
+ BOOST_CHECK(strm.auto_close());
     }
- BOOST_CHECK(!src.is_open());
+ BOOST_CHECK(!dev.is_open());
 
     // Use close() to close components.
- src.open();
+ dev.open();
     {
- stream<closable_source> in(src);
- BOOST_CHECK(src.is_open());
- BOOST_CHECK(in.auto_close());
- in.close();
- BOOST_CHECK(!src.is_open());
+ stream<Device> strm(dev);
+ BOOST_CHECK(dev.is_open());
+ BOOST_CHECK(strm.auto_close());
+ strm.close();
+ BOOST_CHECK(!dev.is_open());
     }
 
     // Use close() to close components, with auto_close disabled.
- src.open();
+ dev.open();
     {
- stream<closable_source> in(src);
- BOOST_CHECK(src.is_open());
- in.set_auto_close(false);
- in.close();
- BOOST_CHECK(!src.is_open());
+ stream<Device> strm(dev);
+ BOOST_CHECK(dev.is_open());
+ strm.set_auto_close(false);
+ strm.close();
+ BOOST_CHECK(!dev.is_open());
     }
 
     // Disable auto_close.
- src.open();
+ dev.open();
     {
- stream<closable_source> in(src);
- BOOST_CHECK(src.is_open());
- in.set_auto_close(false);
- BOOST_CHECK(!in.auto_close());
+ stream<Device> strm(dev);
+ BOOST_CHECK(dev.is_open());
+ strm.set_auto_close(false);
+ BOOST_CHECK(!strm.auto_close());
     }
- BOOST_CHECK(src.is_open());
+ BOOST_CHECK(dev.is_open());
 }
 
+/* Test closing a filter */
 void auto_close_filter()
 {
     closable_source src;
@@ -177,7 +238,10 @@
 test_suite* init_unit_test_suite(int, char* [])
 {
     test_suite* test = BOOST_TEST_SUITE("auto_close test");
- test->add(BOOST_TEST_CASE(&auto_close_source));
+ test->add(BOOST_TEST_CASE(&auto_close<closable_source>));
+ test->add(BOOST_TEST_CASE(&auto_close<closable_sink>));
+ test->add(BOOST_TEST_CASE(&auto_close<closable_bidir>));
+ test->add(BOOST_TEST_CASE(&auto_close<closable_tee_sink>));
     test->add(BOOST_TEST_CASE(&auto_close_filter));
     return test;
 }


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk