Refactored stream related stuff
- simpler, polymorphic hierarchy-based, approach
- less bitty conditionals spread across the code
- all resolved up-front so now config class is immutable
(it had evolved the way it was and in need of a clean-up sweep for a long time)
diff --git a/include/catch_session.hpp b/include/catch_session.hpp
index 1f37b5a..c63f517 100644
--- a/include/catch_session.hpp
+++ b/include/catch_session.hpp
@@ -52,25 +52,11 @@
         return reporters;
     }
     
-    void openStreamInto( Ptr<Config> const& config, std::ofstream& ofs ) {
-        // Open output file, if specified
-        if( !config->getFilename().empty() ) {
-            ofs.open( config->getFilename().c_str() );
-            if( ofs.fail() ) {
-                std::ostringstream oss;
-                oss << "Unable to open file: '" << config->getFilename() << "'";
-                throw std::domain_error( oss.str() );
-            }
-            config->setStreamBuf( ofs.rdbuf() );
-        }
-    }
     
     Totals runTests( Ptr<Config> const& config ) {
 
         Ptr<IConfig const> iconfig = config.get();
         
-        std::ofstream ofs;
-        openStreamInto( config, ofs );
         Ptr<IStreamingReporter> reporter = makeReporter( config );
         reporter = addListeners( iconfig, reporter );
         
diff --git a/include/internal/catch_config.hpp b/include/internal/catch_config.hpp
index 6b2b04a..eca1036 100644
--- a/include/internal/catch_config.hpp
+++ b/include/internal/catch_config.hpp
@@ -85,12 +85,11 @@
     public:
 
         Config()
-        :   m_os( Catch::cout().rdbuf() )
         {}
 
         Config( ConfigData const& data )
         :   m_data( data ),
-            m_os( Catch::cout().rdbuf() )
+            m_stream( openStream() )
         {
             if( !data.testsOrTags.empty() ) {
                 TestSpecParser parser( ITagAliasRegistry::get() );
@@ -101,12 +100,6 @@
         }
 
         virtual ~Config() {
-            m_os.rdbuf( Catch::cout().rdbuf() );
-            m_stream.release();
-        }
-
-        void setFilename( std::string const& filename ) {
-            m_data.outputFilename = filename;
         }
 
         std::string const& getFilename() const {
@@ -122,17 +115,6 @@
 
         bool shouldDebugBreak() const { return m_data.shouldDebugBreak; }
 
-        void setStreamBuf( std::streambuf* buf ) {
-            m_os.rdbuf( buf ? buf : Catch::cout().rdbuf() );
-        }
-
-        void useStream( std::string const& streamName ) {
-            Stream stream = createStream( streamName );
-            setStreamBuf( stream.streamBuf );
-            m_stream.release();
-            m_stream = stream;
-        }
-
         std::vector<std::string> getReporterNames() const { return m_data.reporterNames; }
 
         int abortAfter() const { return m_data.abortAfter; }
@@ -144,7 +126,7 @@
 
         // IConfig interface
         virtual bool allowThrows() const        { return !m_data.noThrow; }
-        virtual std::ostream& stream() const    { return m_os; }
+        virtual std::ostream& stream() const    { return m_stream->stream(); }
         virtual std::string name() const        { return m_data.name.empty() ? m_data.processName : m_data.name; }
         virtual bool includeSuccessfulResults() const   { return m_data.showSuccessfulTests; }
         virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; }
@@ -154,10 +136,22 @@
         virtual bool forceColour() const { return m_data.forceColour; }
 
     private:
+        
+        IStream const* openStream() {
+            if( m_data.outputFilename.empty() )
+                return new CoutStream();
+            else if( m_data.outputFilename[0] == '%' ) {
+                if( m_data.outputFilename == "%debug" )
+                    return new DebugOutStream();
+                else
+                    throw std::domain_error( "Unrecognised stream: " + m_data.outputFilename );
+            }
+            else
+                return new FileStream( m_data.outputFilename );
+        }
         ConfigData m_data;
 
-        Stream m_stream;
-        mutable std::ostream m_os;
+        std::auto_ptr<IStream const> m_stream;
         TestSpec m_testSpec;
     };
 
diff --git a/include/internal/catch_context_impl.hpp b/include/internal/catch_context_impl.hpp
index a3ac2ae..030f29e 100644
--- a/include/internal/catch_context_impl.hpp
+++ b/include/internal/catch_context_impl.hpp
@@ -95,14 +95,6 @@
         return getCurrentMutableContext();
     }
 
-    Stream createStream( std::string const& streamName ) {
-        if( streamName == "stdout" ) return Stream( Catch::cout().rdbuf(), false );
-        if( streamName == "stderr" ) return Stream( Catch::cerr().rdbuf(), false );
-        if( streamName == "debug" ) return Stream( new StreamBufImpl<OutputDebugWriter>, true );
-
-        throw std::domain_error( "Unknown stream: " + streamName );
-    }
-
     void cleanUpContext() {
         delete currentContext;
         currentContext = CATCH_NULL;
diff --git a/include/internal/catch_impl.hpp b/include/internal/catch_impl.hpp
index 3ff5ac0..170b480 100644
--- a/include/internal/catch_impl.hpp
+++ b/include/internal/catch_impl.hpp
@@ -45,6 +45,7 @@
 namespace Catch {
     NonCopyable::~NonCopyable() {}
     IShared::~IShared() {}
+    IStream::~IStream() CATCH_NOEXCEPT {}
     StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {}
     IContext::~IContext() {}
     IResultCapture::~IResultCapture() {}
diff --git a/include/internal/catch_stream.h b/include/internal/catch_stream.h
index 402a661..a69c841 100644
--- a/include/internal/catch_stream.h
+++ b/include/internal/catch_stream.h
@@ -9,28 +9,52 @@
 #ifndef TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
 #define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
 
-#include <streambuf>
+#include "catch_compiler_capabilities.h"
+#include "catch_streambuf.h"
 
-#ifdef __clang__
-#pragma clang diagnostic ignored "-Wpadded"
-#endif
+#include <streambuf>
+#include <ostream>
+#include <fstream>
 
 namespace Catch {
 
-    class Stream {
-    public:
-        Stream();
-        Stream( std::streambuf* _streamBuf, bool _isOwned );
-        void release();
-
-        std::streambuf* streamBuf;
-
-    private:
-        bool isOwned;
-    };
-
     std::ostream& cout();
     std::ostream& cerr();
+
+    
+    struct IStream {
+        virtual ~IStream() CATCH_NOEXCEPT;
+        virtual std::ostream& stream() const = 0;
+    };
+
+    class FileStream : public IStream {
+        mutable std::ofstream m_ofs;
+    public:
+        FileStream( std::string const& filename );
+    public: // IStream
+        virtual std::ostream& stream() const CATCH_OVERRIDE;
+    };
+    
+
+    class CoutStream : public IStream {
+        mutable std::ostream m_os;
+    public:
+        CoutStream();
+
+    public: // IStream
+        virtual std::ostream& stream() const CATCH_OVERRIDE;
+    };
+
+    
+    class DebugOutStream : public IStream {
+        std::auto_ptr<StreamBufBase> m_streamBuf;
+        mutable std::ostream m_os;
+    public:
+        DebugOutStream();
+
+    public: // IStream
+        virtual std::ostream& stream() const CATCH_OVERRIDE;
+    };
 }
 
 #endif // TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
diff --git a/include/internal/catch_stream.hpp b/include/internal/catch_stream.hpp
index 4293348..e6bf7b0 100644
--- a/include/internal/catch_stream.hpp
+++ b/include/internal/catch_stream.hpp
@@ -10,7 +10,6 @@
 #define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED
 
 #include "catch_stream.h"
-#include "catch_streambuf.h"
 #include "catch_debugger.h"
 
 #include <stdexcept>
@@ -57,29 +56,47 @@
 
     ///////////////////////////////////////////////////////////////////////////
 
-    struct OutputDebugWriter {
 
+    FileStream::FileStream( std::string const& filename ) {
+        m_ofs.open( filename.c_str() );
+        if( m_ofs.fail() ) {
+            std::ostringstream oss;
+            oss << "Unable to open file: '" << filename << "'";
+            throw std::domain_error( oss.str() );
+        }
+    }
+    
+    std::ostream& FileStream::stream() const {
+        return m_ofs;
+    }
+    
+    struct OutputDebugWriter {
+        
         void operator()( std::string const&str ) {
             writeToDebugConsole( str );
         }
     };
-
-    Stream::Stream()
-    : streamBuf( CATCH_NULL ), isOwned( false )
+    
+    DebugOutStream::DebugOutStream()
+    :   m_streamBuf( new StreamBufImpl<OutputDebugWriter>() ),
+        m_os( m_streamBuf.get() )
     {}
-
-    Stream::Stream( std::streambuf* _streamBuf, bool _isOwned )
-    : streamBuf( _streamBuf ), isOwned( _isOwned )
-    {}
-
-    void Stream::release() {
-        if( isOwned ) {
-            delete streamBuf;
-            streamBuf = CATCH_NULL;
-            isOwned = false;
-        }
+    
+    std::ostream& DebugOutStream::stream() const {
+        return m_os;
     }
+    
+    // Store the streambuf from cout up-front because
+    // cout may get redirected when running tests
+    CoutStream::CoutStream()
+    :   m_os( Catch::cout().rdbuf() )
+    {}
 
+    std::ostream& CoutStream::stream() const {
+        return m_os;
+    }
+    
+    
 #ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement this functions
     std::ostream& cout() {
         return std::cout;
diff --git a/projects/SelfTest/SurrogateCpps/catch_stream.cpp b/projects/SelfTest/SurrogateCpps/catch_stream.cpp
index 9911aec..7aaffa1 100644
--- a/projects/SelfTest/SurrogateCpps/catch_stream.cpp
+++ b/projects/SelfTest/SurrogateCpps/catch_stream.cpp
@@ -1,2 +1,3 @@
 // This file is only here to verify (to the extent possible) the self sufficiency of the header
+#include "catch_suppress_warnings.h"
 #include "catch_stream.h"