Allow output stream to be specified on the command line

This commit is contained in:
Phil Nash 2011-01-18 09:20:06 +00:00
parent 925409d7e9
commit 2885339287
10 changed files with 161 additions and 15 deletions

View File

@ -32,6 +32,7 @@
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
4A15D2B712E0418F0005EB03 /* catch_self_test.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = catch_self_test.hpp; path = ../internal/catch_self_test.hpp; sourceTree = SOURCE_ROOT; }; 4A15D2B712E0418F0005EB03 /* catch_self_test.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = catch_self_test.hpp; path = ../internal/catch_self_test.hpp; sourceTree = SOURCE_ROOT; };
4A15D4A812E4DF0D0005EB03 /* catch_stream.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = catch_stream.hpp; path = ../internal/catch_stream.hpp; sourceTree = SOURCE_ROOT; };
4A302DE312D5114900C84B67 /* catch.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = catch.hpp; path = ../catch.hpp; sourceTree = SOURCE_ROOT; }; 4A302DE312D5114900C84B67 /* catch.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = catch.hpp; path = ../catch.hpp; sourceTree = SOURCE_ROOT; };
4A33BCE512CE7F500052A211 /* catch_hub.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = catch_hub.h; path = ../internal/catch_hub.h; sourceTree = SOURCE_ROOT; }; 4A33BCE512CE7F500052A211 /* catch_hub.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = catch_hub.h; path = ../internal/catch_hub.h; sourceTree = SOURCE_ROOT; };
4A33BCF912CE80EC0052A211 /* catch_interfaces_reporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = catch_interfaces_reporter.h; path = ../internal/catch_interfaces_reporter.h; sourceTree = SOURCE_ROOT; }; 4A33BCF912CE80EC0052A211 /* catch_interfaces_reporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = catch_interfaces_reporter.h; path = ../internal/catch_interfaces_reporter.h; sourceTree = SOURCE_ROOT; };
@ -163,6 +164,7 @@
4A6D514B12C8A547008F0415 /* catch_debugger.hpp */, 4A6D514B12C8A547008F0415 /* catch_debugger.hpp */,
4AFC341612809A36003A0C29 /* catch_common.h */, 4AFC341612809A36003A0C29 /* catch_common.h */,
4A992A6512B2156C002B7B66 /* catch_xmlwriter.hpp */, 4A992A6512B2156C002B7B66 /* catch_xmlwriter.hpp */,
4A15D4A812E4DF0D0005EB03 /* catch_stream.hpp */,
); );
name = support; name = support;
sourceTree = "<group>"; sourceTree = "<group>";

View File

@ -24,7 +24,6 @@ TEST_CASE( "selftest/main", "Runs all Catch self tests and checks their results"
CHECK( runner.getReporter().getFailed() == 0 ); CHECK( runner.getReporter().getFailed() == 0 );
runner.runMatching( "./failing/*" ); runner.runMatching( "./failing/*" );
CHECK( runner.getReporter().getSucceeded() == 0 ); CHECK( runner.getReporter().getSucceeded() == 0 );
CHECK( runner.getReporter().getFailed() == 53 ); CHECK( runner.getReporter().getFailed() == 53 );
} }

View File

@ -23,13 +23,17 @@ namespace Catch
{ {
public: public:
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
XmlReporter( const IReporterConfig& config ) XmlReporter
: m_config( config ) (
const IReporterConfig& config
)
: m_config( config )
{ {
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
static std::string getDescription() static std::string getDescription
()
{ {
return "Reports test results as an XML document"; return "Reports test results as an XML document";
} }
@ -37,14 +41,19 @@ namespace Catch
private: // IReporter private: // IReporter
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
virtual void StartTesting() virtual void StartTesting
()
{ {
m_xml = XmlWriter( m_config.stream() ); m_xml = XmlWriter( m_config.stream() );
m_xml.startElement( "AllTests" ); m_xml.startElement( "AllTests" );
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
virtual void EndTesting( std::size_t succeeded, std::size_t failed ) virtual void EndTesting
(
std::size_t succeeded,
std::size_t failed
)
{ {
m_xml.scopedElement( "OverallResults" ) m_xml.scopedElement( "OverallResults" )
.writeAttribute( "successes", succeeded ) .writeAttribute( "successes", succeeded )
@ -52,14 +61,22 @@ namespace Catch
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
virtual void StartGroup( const std::string& groupName ) virtual void StartGroup
(
const std::string& groupName
)
{ {
m_xml.startElement( "Group" ) m_xml.startElement( "Group" )
.writeAttribute( "name", groupName ); .writeAttribute( "name", groupName );
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
virtual void EndGroup( const std::string& /*groupName*/, std::size_t succeeded, std::size_t failed ) virtual void EndGroup
(
const std::string& /*groupName*/,
std::size_t succeeded,
std::size_t failed
)
{ {
m_xml.scopedElement( "OverallResults" ) m_xml.scopedElement( "OverallResults" )
.writeAttribute( "successes", succeeded ) .writeAttribute( "successes", succeeded )

View File

@ -50,7 +50,7 @@ namespace Catch
<< "\t-l, --list <tests | reporters> [xml]\n" << "\t-l, --list <tests | reporters> [xml]\n"
<< "\t-t, --test <testspec> [<testspec>...]\n" << "\t-t, --test <testspec> [<testspec>...]\n"
<< "\t-r, --reporter <reporter name>\n" << "\t-r, --reporter <reporter name>\n"
<< "\t-o, --out <file name>\n" << "\t-o, --out <file name>|<%stream name>\n"
<< "\t-s, --success\n" << "\t-s, --success\n"
<< "\t-b, --break\n\n" << "\t-b, --break\n\n"
<< "For more detail usage please see: https://github.com/philsquared/Catch/wiki/Command-line" << std::endl; << "For more detail usage please see: https://github.com/philsquared/Catch/wiki/Command-line" << std::endl;

View File

@ -152,7 +152,10 @@ namespace Catch
case modeOutput: case modeOutput:
if( m_args.size() == 0 ) if( m_args.size() == 0 )
return setErrorMode( m_command + " expected filename" ); return setErrorMode( m_command + " expected filename" );
m_config.setFilename( m_args[0] ); if( m_args[0][0] == '%' )
m_config.useStream( m_args[0].substr( 1 ) );
else
m_config.setFilename( m_args[0] );
break; break;
case modeSuccess: case modeSuccess:
if( m_args.size() != 0 ) if( m_args.size() != 0 )

View File

@ -23,6 +23,7 @@
namespace Catch namespace Catch
{ {
class Config : public IReporterConfig class Config : public IReporterConfig
{ {
private: private:
@ -59,10 +60,17 @@ namespace Catch
m_listSpec( List::None ), m_listSpec( List::None ),
m_shouldDebugBreak( false ), m_shouldDebugBreak( false ),
m_showHelp( false ), m_showHelp( false ),
m_os( std::cout.rdbuf() ), m_streambuf( std::cout.rdbuf() ),
m_os( m_streambuf ),
m_includeWhat( Include::FailedOnly ) m_includeWhat( Include::FailedOnly )
{} {}
///////////////////////////////////////////////////////////////////////////
~Config()
{
setStreamBuf( NULL );
}
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
void setReporter( const std::string& reporterName ) void setReporter( const std::string& reporterName )
{ {
@ -172,7 +180,18 @@ namespace Catch
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
void setStreamBuf( std::streambuf* buf ) void setStreamBuf( std::streambuf* buf )
{ {
m_os.rdbuf( buf ); // Delete previous stream buf if we own it
if( m_streambuf && dynamic_cast<StreamBufBase*>( m_streambuf ) )
delete m_streambuf;
m_streambuf = buf;
m_os.rdbuf( buf ? buf : std::cout.rdbuf() );
}
///////////////////////////////////////////////////////////////////////////
void useStream( const std::string& streamName )
{
setStreamBuf( Hub::createStreamBuf( streamName ) );
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
@ -189,6 +208,7 @@ namespace Catch
std::vector<std::string> m_testSpecs; std::vector<std::string> m_testSpecs;
bool m_shouldDebugBreak; bool m_shouldDebugBreak;
bool m_showHelp; bool m_showHelp;
std::streambuf* m_streambuf;
mutable std::ostream m_os; mutable std::ostream m_os;
Include::What m_includeWhat; Include::What m_includeWhat;
}; };

View File

@ -15,6 +15,8 @@
#ifndef TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED #ifndef TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED #define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED
#include <iostream>
#if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) #if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
#include <assert.h> #include <assert.h>
@ -83,5 +85,14 @@
inline void DebugBreak(){} inline void DebugBreak(){}
#endif #endif
inline void writeToDebugConsole( const std::string& text )
{
#ifdef _WIN32
::OutputDebugStringA( text.get() );
#else
// !TBD: Need a version for Mac/ XCode and other IDEs
std::cout << text;
#endif
}
#endif // TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED #endif // TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED

View File

@ -24,6 +24,10 @@ namespace Catch
struct ITestCaseRegistry; struct ITestCaseRegistry;
struct IRunner; struct IRunner;
class StreamBufBase : public std::streambuf
{
};
class Hub class Hub
{ {
Hub(); Hub();
@ -49,6 +53,10 @@ namespace Catch
static ITestCaseRegistry& getTestCaseRegistry static ITestCaseRegistry& getTestCaseRegistry
(); ();
static std::streambuf* createStreamBuf
( const std::string& streamName
);
static IRunner& getRunner static IRunner& getRunner
(); ();

View File

@ -13,6 +13,7 @@
#include "catch_reporter_registry.hpp" #include "catch_reporter_registry.hpp"
#include "catch_test_case_registry_impl.hpp" #include "catch_test_case_registry_impl.hpp"
#include "catch_runner_impl.hpp" #include "catch_runner_impl.hpp"
#include "catch_stream.hpp"
namespace Catch namespace Catch
{ {
@ -70,4 +71,18 @@ namespace Catch
{ {
return *me().m_testCaseRegistry.get(); return *me().m_testCaseRegistry.get();
} }
///////////////////////////////////////////////////////////////////////////
std::streambuf* Hub::createStreamBuf
(
const std::string& streamName
)
{
if( streamName == "stdout" ) return std::cout.rdbuf();
if( streamName == "stderr" ) return std::cerr.rdbuf();
if( streamName == "debug" ) return new StreamBufImpl<OutputDebugWriter>;
throw std::domain_error( "Unknown stream: " + streamName );
}
} }

71
internal/catch_stream.hpp Normal file
View File

@ -0,0 +1,71 @@
/*
* catch_stream.hpp
* Catch
*
* Created by Phil on 17/01/2011.
* Copyright 2011 Two Blue Cubes Ltd. All rights reserved.
*
* 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)
*
*/
#ifndef TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED
#include <stdexcept>
namespace Catch
{
template<typename WriterF, size_t bufferSize=256>
class StreamBufImpl : public StreamBufBase
{
char data[bufferSize];
WriterF m_writer;
public:
StreamBufImpl()
{
setp( data, data + sizeof(data) );
}
~StreamBufImpl()
{
sync();
}
private:
int overflow( int c )
{
sync();
if( c != EOF )
{
if( pbase() == epptr() )
m_writer( std::string( 1, (char)c ) );
else
sputc( c );
}
return 0;
}
int sync()
{
if( pbase() != pptr() )
{
m_writer( std::string( pbase(), pptr() - pbase() ) );
setp( pbase(), epptr() );
}
return 0;
}
};
struct OutputDebugWriter
{
void operator()( const std::string &str )
{
writeToDebugConsole( str );
}
};
}
#endif // TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED