mirror of
https://github.com/catchorg/Catch2.git
synced 2024-11-22 05:16:10 +01:00
Split out IStream out of catch_stream.hpp
This commit is contained in:
parent
05e85c5652
commit
98bb638fb2
@ -76,6 +76,7 @@ set(INTERNAL_HEADERS
|
||||
${SOURCES_DIR}/internal/catch_exception_translator_registry.hpp
|
||||
${SOURCES_DIR}/internal/catch_fatal_condition_handler.hpp
|
||||
${SOURCES_DIR}/internal/catch_floating_point_helpers.hpp
|
||||
${SOURCES_DIR}/internal/catch_istream.hpp
|
||||
${SOURCES_DIR}/internal/catch_unique_name.hpp
|
||||
${SOURCES_DIR}/internal/catch_sharding.hpp
|
||||
${SOURCES_DIR}/generators/catch_generator_exception.hpp
|
||||
@ -181,6 +182,7 @@ set(IMPL_SOURCES
|
||||
${SOURCES_DIR}/internal/catch_exception_translator_registry.cpp
|
||||
${SOURCES_DIR}/internal/catch_fatal_condition_handler.cpp
|
||||
${SOURCES_DIR}/internal/catch_floating_point_helpers.cpp
|
||||
${SOURCES_DIR}/internal/catch_istream.cpp
|
||||
${SOURCES_DIR}/generators/internal/catch_generators_combined_tu.cpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_combined_tu.cpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_reporter.cpp
|
||||
|
@ -67,6 +67,7 @@
|
||||
#include <catch2/internal/catch_exception_translator_registry.hpp>
|
||||
#include <catch2/internal/catch_fatal_condition_handler.hpp>
|
||||
#include <catch2/internal/catch_floating_point_helpers.hpp>
|
||||
#include <catch2/internal/catch_istream.hpp>
|
||||
#include <catch2/internal/catch_lazy_expr.hpp>
|
||||
#include <catch2/internal/catch_leak_detector.hpp>
|
||||
#include <catch2/internal/catch_list.hpp>
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <catch2/interfaces/catch_interfaces_reporter_factory.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
#include <catch2/internal/catch_stdstreams.hpp>
|
||||
#include <catch2/internal/catch_istream.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <catch2/catch_test_case_info.hpp>
|
||||
#include <catch2/reporters/catch_reporter_helpers.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
#include <catch2/internal/catch_istream.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
@ -44,6 +45,8 @@ namespace Catch {
|
||||
return m_customOptions;
|
||||
}
|
||||
|
||||
ReporterConfig::~ReporterConfig() = default;
|
||||
|
||||
AssertionStats::AssertionStats( AssertionResult const& _assertionResult,
|
||||
std::vector<MessageInfo> const& _infoMessages,
|
||||
Totals const& _totals )
|
||||
|
@ -40,6 +40,10 @@ namespace Catch {
|
||||
ColourMode colourMode,
|
||||
std::map<std::string, std::string> customOptions );
|
||||
|
||||
ReporterConfig( ReporterConfig&& ) = default;
|
||||
ReporterConfig& operator=( ReporterConfig&& ) = default;
|
||||
~ReporterConfig(); // = default
|
||||
|
||||
Detail::unique_ptr<IStream> takeStream() &&;
|
||||
IConfig const* fullConfig() const;
|
||||
ColourMode colourMode() const;
|
||||
|
@ -15,7 +15,7 @@
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/internal/catch_errno_guard.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_config.hpp>
|
||||
#include <catch2/internal/catch_stream.hpp>
|
||||
#include <catch2/internal/catch_istream.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
#include <catch2/internal/catch_context.hpp>
|
||||
#include <catch2/internal/catch_platform.hpp>
|
||||
|
158
src/catch2/internal/catch_istream.cpp
Normal file
158
src/catch2/internal/catch_istream.cpp
Normal file
@ -0,0 +1,158 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/internal/catch_istream.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/internal/catch_debug_console.hpp>
|
||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||
#include <catch2/internal/catch_stdstreams.hpp>
|
||||
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
Catch::IStream::~IStream() = default;
|
||||
|
||||
namespace Detail {
|
||||
namespace {
|
||||
template<typename WriterF, std::size_t bufferSize=256>
|
||||
class StreamBufImpl : public std::streambuf {
|
||||
char data[bufferSize];
|
||||
WriterF m_writer;
|
||||
|
||||
public:
|
||||
StreamBufImpl() {
|
||||
setp( data, data + sizeof(data) );
|
||||
}
|
||||
|
||||
~StreamBufImpl() noexcept {
|
||||
StreamBufImpl::sync();
|
||||
}
|
||||
|
||||
private:
|
||||
int overflow( int c ) override {
|
||||
sync();
|
||||
|
||||
if( c != EOF ) {
|
||||
if( pbase() == epptr() )
|
||||
m_writer( std::string( 1, static_cast<char>( c ) ) );
|
||||
else
|
||||
sputc( static_cast<char>( c ) );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sync() override {
|
||||
if( pbase() != pptr() ) {
|
||||
m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) );
|
||||
setp( pbase(), epptr() );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct OutputDebugWriter {
|
||||
|
||||
void operator()( std::string const& str ) {
|
||||
if ( !str.empty() ) {
|
||||
writeToDebugConsole( str );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class FileStream : public IStream {
|
||||
std::ofstream m_ofs;
|
||||
public:
|
||||
FileStream( std::string const& filename ) {
|
||||
m_ofs.open( filename.c_str() );
|
||||
CATCH_ENFORCE( !m_ofs.fail(), "Unable to open file: '" << filename << '\'' );
|
||||
}
|
||||
~FileStream() override = default;
|
||||
public: // IStream
|
||||
std::ostream& stream() override {
|
||||
return m_ofs;
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CoutStream : public IStream {
|
||||
std::ostream m_os;
|
||||
public:
|
||||
// Store the streambuf from cout up-front because
|
||||
// cout may get redirected when running tests
|
||||
CoutStream() : m_os( Catch::cout().rdbuf() ) {}
|
||||
~CoutStream() override = default;
|
||||
|
||||
public: // IStream
|
||||
std::ostream& stream() override { return m_os; }
|
||||
bool isConsole() const override { return true; }
|
||||
};
|
||||
|
||||
class CerrStream : public IStream {
|
||||
std::ostream m_os;
|
||||
|
||||
public:
|
||||
// Store the streambuf from cerr up-front because
|
||||
// cout may get redirected when running tests
|
||||
CerrStream(): m_os( Catch::cerr().rdbuf() ) {}
|
||||
~CerrStream() override = default;
|
||||
|
||||
public: // IStream
|
||||
std::ostream& stream() override { return m_os; }
|
||||
bool isConsole() const override { return true; }
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class DebugOutStream : public IStream {
|
||||
Detail::unique_ptr<StreamBufImpl<OutputDebugWriter>> m_streamBuf;
|
||||
std::ostream m_os;
|
||||
public:
|
||||
DebugOutStream()
|
||||
: m_streamBuf( Detail::make_unique<StreamBufImpl<OutputDebugWriter>>() ),
|
||||
m_os( m_streamBuf.get() )
|
||||
{}
|
||||
|
||||
~DebugOutStream() override = default;
|
||||
|
||||
public: // IStream
|
||||
std::ostream& stream() override { return m_os; }
|
||||
};
|
||||
|
||||
} // unnamed namespace
|
||||
} // namespace Detail
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
auto makeStream( std::string const& filename ) -> Detail::unique_ptr<IStream> {
|
||||
if ( filename.empty() || filename == "-" ) {
|
||||
return Detail::make_unique<Detail::CoutStream>();
|
||||
}
|
||||
if( filename[0] == '%' ) {
|
||||
if ( filename == "%debug" ) {
|
||||
return Detail::make_unique<Detail::DebugOutStream>();
|
||||
} else if ( filename == "%stderr" ) {
|
||||
return Detail::make_unique<Detail::CerrStream>();
|
||||
} else if ( filename == "%stdout" ) {
|
||||
return Detail::make_unique<Detail::CoutStream>();
|
||||
} else {
|
||||
CATCH_ERROR( "Unrecognised stream: '" << filename << '\'' );
|
||||
}
|
||||
}
|
||||
return Detail::make_unique<Detail::FileStream>( filename );
|
||||
}
|
||||
|
||||
}
|
54
src/catch2/internal/catch_istream.hpp
Normal file
54
src/catch2/internal/catch_istream.hpp
Normal file
@ -0,0 +1,54 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_ISTREAM_HPP_INCLUDED
|
||||
#define CATCH_ISTREAM_HPP_INCLUDED
|
||||
|
||||
#include <catch2/internal/catch_noncopyable.hpp>
|
||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||
|
||||
#include <iosfwd>
|
||||
#include <cstddef>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
class IStream {
|
||||
public:
|
||||
virtual ~IStream(); // = default
|
||||
virtual std::ostream& stream() = 0;
|
||||
/**
|
||||
* Best guess on whether the instance is writing to a console (e.g. via stdout/stderr)
|
||||
*
|
||||
* This is useful for e.g. Win32 colour support, because the Win32
|
||||
* API manipulates console directly, unlike POSIX escape codes,
|
||||
* that can be written anywhere.
|
||||
*
|
||||
* Due to variety of ways to change where the stdout/stderr is
|
||||
* _actually_ being written, users should always assume that
|
||||
* the answer might be wrong.
|
||||
*/
|
||||
virtual bool isConsole() const { return false; }
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a stream wrapper that writes to specific file.
|
||||
*
|
||||
* Also recognizes 4 special filenames
|
||||
* * `-` for stdout
|
||||
* * `%stdout` for stdout
|
||||
* * `%stderr` for stderr
|
||||
* * `%debug` for platform specific debugging output
|
||||
*
|
||||
* \throws if passed an unrecognized %-prefixed stream
|
||||
*/
|
||||
auto makeStream( std::string const& filename ) -> Detail::unique_ptr<IStream>;
|
||||
|
||||
}
|
||||
|
||||
#endif // CATCH_STREAM_HPP_INCLUDED
|
@ -5,158 +5,16 @@
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/internal/catch_stream.hpp>
|
||||
#include <catch2/internal/catch_debug_console.hpp>
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
#include <catch2/internal/catch_singletons.hpp>
|
||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||
#include <catch2/internal/catch_stdstreams.hpp>
|
||||
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
Catch::IStream::~IStream() = default;
|
||||
|
||||
namespace Detail {
|
||||
namespace {
|
||||
template<typename WriterF, std::size_t bufferSize=256>
|
||||
class StreamBufImpl : public std::streambuf {
|
||||
char data[bufferSize];
|
||||
WriterF m_writer;
|
||||
|
||||
public:
|
||||
StreamBufImpl() {
|
||||
setp( data, data + sizeof(data) );
|
||||
}
|
||||
|
||||
~StreamBufImpl() noexcept {
|
||||
StreamBufImpl::sync();
|
||||
}
|
||||
|
||||
private:
|
||||
int overflow( int c ) override {
|
||||
sync();
|
||||
|
||||
if( c != EOF ) {
|
||||
if( pbase() == epptr() )
|
||||
m_writer( std::string( 1, static_cast<char>( c ) ) );
|
||||
else
|
||||
sputc( static_cast<char>( c ) );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sync() override {
|
||||
if( pbase() != pptr() ) {
|
||||
m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) );
|
||||
setp( pbase(), epptr() );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct OutputDebugWriter {
|
||||
|
||||
void operator()( std::string const& str ) {
|
||||
if ( !str.empty() ) {
|
||||
writeToDebugConsole( str );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class FileStream : public IStream {
|
||||
std::ofstream m_ofs;
|
||||
public:
|
||||
FileStream( std::string const& filename ) {
|
||||
m_ofs.open( filename.c_str() );
|
||||
CATCH_ENFORCE( !m_ofs.fail(), "Unable to open file: '" << filename << '\'' );
|
||||
}
|
||||
~FileStream() override = default;
|
||||
public: // IStream
|
||||
std::ostream& stream() override {
|
||||
return m_ofs;
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CoutStream : public IStream {
|
||||
std::ostream m_os;
|
||||
public:
|
||||
// Store the streambuf from cout up-front because
|
||||
// cout may get redirected when running tests
|
||||
CoutStream() : m_os( Catch::cout().rdbuf() ) {}
|
||||
~CoutStream() override = default;
|
||||
|
||||
public: // IStream
|
||||
std::ostream& stream() override { return m_os; }
|
||||
bool isConsole() const override { return true; }
|
||||
};
|
||||
|
||||
class CerrStream : public IStream {
|
||||
std::ostream m_os;
|
||||
|
||||
public:
|
||||
// Store the streambuf from cerr up-front because
|
||||
// cout may get redirected when running tests
|
||||
CerrStream(): m_os( Catch::cerr().rdbuf() ) {}
|
||||
~CerrStream() override = default;
|
||||
|
||||
public: // IStream
|
||||
std::ostream& stream() override { return m_os; }
|
||||
bool isConsole() const override { return true; }
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class DebugOutStream : public IStream {
|
||||
Detail::unique_ptr<StreamBufImpl<OutputDebugWriter>> m_streamBuf;
|
||||
std::ostream m_os;
|
||||
public:
|
||||
DebugOutStream()
|
||||
: m_streamBuf( Detail::make_unique<StreamBufImpl<OutputDebugWriter>>() ),
|
||||
m_os( m_streamBuf.get() )
|
||||
{}
|
||||
|
||||
~DebugOutStream() override = default;
|
||||
|
||||
public: // IStream
|
||||
std::ostream& stream() override { return m_os; }
|
||||
};
|
||||
|
||||
} // unnamed namespace
|
||||
} // namespace Detail
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
auto makeStream( std::string const& filename ) -> Detail::unique_ptr<IStream> {
|
||||
if ( filename.empty() || filename == "-" ) {
|
||||
return Detail::make_unique<Detail::CoutStream>();
|
||||
}
|
||||
if( filename[0] == '%' ) {
|
||||
if ( filename == "%debug" ) {
|
||||
return Detail::make_unique<Detail::DebugOutStream>();
|
||||
} else if ( filename == "%stderr" ) {
|
||||
return Detail::make_unique<Detail::CerrStream>();
|
||||
} else if ( filename == "%stdout" ) {
|
||||
return Detail::make_unique<Detail::CoutStream>();
|
||||
} else {
|
||||
CATCH_ERROR( "Unrecognised stream: '" << filename << '\'' );
|
||||
}
|
||||
}
|
||||
return Detail::make_unique<Detail::FileStream>( filename );
|
||||
}
|
||||
|
||||
|
||||
// This class encapsulates the idea of a pool of ostringstreams that can be reused.
|
||||
struct StringStreams {
|
||||
std::vector<Detail::unique_ptr<std::ostringstream>> m_streams;
|
||||
|
@ -9,7 +9,6 @@
|
||||
#define CATCH_STREAM_HPP_INCLUDED
|
||||
|
||||
#include <catch2/internal/catch_noncopyable.hpp>
|
||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||
|
||||
#include <iosfwd>
|
||||
#include <cstddef>
|
||||
@ -18,37 +17,6 @@
|
||||
|
||||
namespace Catch {
|
||||
|
||||
class IStream {
|
||||
public:
|
||||
virtual ~IStream(); // = default
|
||||
virtual std::ostream& stream() = 0;
|
||||
/**
|
||||
* Best guess on whether the instance is writing to a console (e.g. via stdout/stderr)
|
||||
*
|
||||
* This is useful for e.g. Win32 colour support, because the Win32
|
||||
* API manipulates console directly, unlike POSIX escape codes,
|
||||
* that can be written anywhere.
|
||||
*
|
||||
* Due to variety of ways to change where the stdout/stderr is
|
||||
* _actually_ being written, users should always assume that
|
||||
* the answer might be wrong.
|
||||
*/
|
||||
virtual bool isConsole() const { return false; }
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a stream wrapper that writes to specific file.
|
||||
*
|
||||
* Also recognizes 4 special filenames
|
||||
* * `-` for stdout
|
||||
* * `%stdout` for stdout
|
||||
* * `%stderr` for stderr
|
||||
* * `%debug` for platform specific debugging output
|
||||
*
|
||||
* \throws if passed an unrecognized %-prefixed stream
|
||||
*/
|
||||
auto makeStream( std::string const& filename ) -> Detail::unique_ptr<IStream>;
|
||||
|
||||
class ReusableStringStream : Detail::NonCopyable {
|
||||
std::size_t m_index;
|
||||
std::ostream* m_oss;
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
#include <catch2/reporters/catch_reporter_helpers.hpp>
|
||||
#include <catch2/internal/catch_console_colour.hpp>
|
||||
#include <catch2/internal/catch_stream.hpp>
|
||||
#include <catch2/internal/catch_istream.hpp>
|
||||
|
||||
|
||||
namespace Catch {
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/internal/catch_console_colour.hpp>
|
||||
#include <catch2/internal/catch_istream.hpp>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/internal/catch_list.hpp>
|
||||
#include <catch2/internal/catch_reporter_registry.hpp>
|
||||
#include <catch2/internal/catch_stream.hpp>
|
||||
#include <catch2/internal/catch_istream.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
#include <catch2/reporters/catch_reporter_helpers.hpp>
|
||||
#include <catch2/reporters/catch_reporter_event_listener.hpp>
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <catch2/internal/catch_stream.hpp>
|
||||
#include <catch2/internal/catch_istream.hpp>
|
||||
|
||||
TEST_CASE( "Cout stream properly declares it writes to stdout", "[streams]" ) {
|
||||
REQUIRE( Catch::makeStream( "-" )->isConsole() );
|
||||
|
Loading…
Reference in New Issue
Block a user