/* * Created by Phil on 08/11/2010. * Copyright 2010 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_CONFIG_HPP_INCLUDED #define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED #include "catch_test_spec.h" #include "catch_context.h" #include "catch_interfaces_config.h" #include "catch_stream.h" #include #include #include #include #ifndef CATCH_CONFIG_CONSOLE_WIDTH #define CATCH_CONFIG_CONSOLE_WIDTH 80 #endif namespace CatchOverrides { class ConfigGuard { public: ConfigGuard() : origConfig(Catch::getCurrentContext().getConfig()) {} ~ConfigGuard() { Catch::getCurrentMutableContext().setConfig(origConfig); } const Catch::Ptr& value() const {return origConfig;} private: ConfigGuard(const ConfigGuard&); ConfigGuard& operator=(const ConfigGuard&); const Catch::Ptr origConfig; }; enum OverrideType { OverrideUpdate, OverrideReset}; // Note: ordered; update must be before reset template class Config { typedef std::map, bool> BoolLineData; typedef std::map FileBoolLineData; typedef std::map, int> LineData; typedef std::map FileLineData; typedef std::multimap, std::string> StringLineData; typedef std::map FileStringLineData; public: bool includeSuccessfulResults(const std::string& file, int c) const { bool result(false); FileBoolLineData::const_iterator it = showSuccessfulTestsData.find(file); if( it != showSuccessfulTestsData.end() ) { BoolLineData::const_iterator start = it->second.begin(); BoolLineData::const_iterator end = it->second.end(); for( BoolLineData::const_iterator lineIt = it->second.begin(); lineIt != it->second.end(); ++lineIt ) { const std::pair& current = lineIt->first; if( current.second == OverrideReset ) { if( c == current.first ) { result = lineIt->second; end = lineIt; break; } else start = lineIt; } } for( BoolLineData::const_iterator lineIt = start; lineIt != end; ++lineIt ) { const std::pair& current = lineIt->first; if( current.second == OverrideUpdate ) { if( c < current.first ) break; result = lineIt->second; } } } return result; } void insertSuccessfulResults(const std::string& file, OverrideType overRide, int c, bool v) { FileBoolLineData::iterator it = showSuccessfulTestsData.find(file); if( it == showSuccessfulTestsData.end() ) { BoolLineData tmp; std::pair current = std::make_pair(c, overRide); tmp.insert(std::make_pair(current,v)); showSuccessfulTestsData.insert(std::make_pair(file, tmp)); } else { std::pair current = std::make_pair(c, overRide); BoolLineData::iterator lineIt = it->second.find(current); if( lineIt == it->second.end() ) { it->second.insert(std::make_pair(current,v)); } else { lineIt->second = v; } } } bool warnAboutMissingAssertions(const std::string& file, int c) const { bool result(false); FileBoolLineData::const_iterator it = missingAssertionData.find(file); if( it != missingAssertionData.end() ) { BoolLineData::const_iterator start = it->second.begin(); BoolLineData::const_iterator end = it->second.end(); for( BoolLineData::const_iterator lineIt = it->second.begin(); lineIt != it->second.end(); ++lineIt ) { const std::pair& current = lineIt->first; if( current.second == OverrideReset ) { if( c == current.first ) { result = lineIt->second; end = lineIt; break; } else start = lineIt; } } for( BoolLineData::const_iterator lineIt = start; lineIt != end; ++lineIt ) { const std::pair& current = lineIt->first; if( current.second == OverrideUpdate ) { if( c < current.first ) break; result = lineIt->second; } } } return result; } void insertMissingAssertions(const std::string& file, OverrideType overRide, int c, bool v) { FileBoolLineData::iterator it = missingAssertionData.find(file); if( it == missingAssertionData.end() ) { BoolLineData tmp; std::pair current = std::make_pair(c, overRide); tmp.insert(std::make_pair(current,v)); missingAssertionData.insert(std::make_pair(file, tmp)); } else { std::pair current = std::make_pair(c, overRide); BoolLineData::iterator lineIt = it->second.find(current); if( lineIt == it->second.end() ) { it->second.insert(std::make_pair(current,v)); } else { lineIt->second = v; } } } int abortAfter(const std::string& file, int c) const { int result(-1); FileLineData::const_iterator it = abortAfterData.find(file); if( it != abortAfterData.end() ) { LineData::const_iterator start = it->second.begin(); LineData::const_iterator end = it->second.end(); for( LineData::const_iterator lineIt = it->second.begin(); lineIt != it->second.end(); ++lineIt ) { const std::pair& current = lineIt->first; if( current.second == OverrideReset ) { if( c == current.first ) { result = lineIt->second; end = lineIt; break; } else start = lineIt; } } for( LineData::const_iterator lineIt = start; lineIt != end; ++lineIt ) { const std::pair& current = lineIt->first; if( current.second == OverrideUpdate ) { if( c < current.first ) break; result = lineIt->second; } } } return result; } void insertAbortAfter(const std::string& file, OverrideType overRide, int c, int v) { FileLineData::iterator it = abortAfterData.find(file); if( it == abortAfterData.end() ) { LineData tmp; std::pair current = std::make_pair(c, overRide); tmp.insert(std::make_pair(current,v)); abortAfterData.insert(std::make_pair(file, tmp)); } else { std::pair current = std::make_pair(c, overRide); LineData::iterator lineIt = it->second.find(current); if( lineIt == it->second.end() ) { it->second.insert(std::make_pair(current,v)); } else { lineIt->second = v; } } } std::vector listOfTests(const std::string& file, int c) const { std::vector result; FileStringLineData::const_iterator it = testData.find(file); if( it != testData.end() ) { StringLineData::const_iterator start = it->second.begin(); StringLineData::const_iterator end = it->second.end(); for( StringLineData::const_iterator lineIt = it->second.begin(); lineIt != it->second.end(); ++lineIt ) { const std::pair& current = lineIt->first; if( current.second == OverrideReset ) { if( c == current.first ) { end = lineIt; break; } else start = lineIt; } } for( StringLineData::const_iterator lineIt = start; lineIt != end; ++lineIt ) { const std::pair& current = lineIt->first; if( current.second == OverrideUpdate ) { if( c < current.first ) break; result.push_back(lineIt->second); } } } return result; } void insertTest(const std::string& file, OverrideType overRide, int c, const std::string& v) { FileStringLineData::iterator it = testData.find(file); if( it == testData.end() ) { StringLineData tmp; std::pair current = std::make_pair(c, overRide); tmp.insert(std::make_pair(current,v)); testData.insert(std::make_pair(file, tmp)); } else { std::pair current = std::make_pair(c, overRide); it->second.insert(std::make_pair(current,v)); } } static Config& instance() { if( !s_instance ) { s_instance = new Config(); } return *s_instance; } private: FileBoolLineData showSuccessfulTestsData; FileBoolLineData missingAssertionData; FileLineData abortAfterData; FileStringLineData testData; static Config* s_instance; }; template Config* Config::s_instance = NULL; template struct ConfigReset { ConfigReset( const std::string& file, int c, int defaultAbortAfter ) { Config::instance().insertSuccessfulResults(file, OverrideReset, c, false); Config::instance().insertMissingAssertions(file, OverrideReset, c, false); Config::instance().insertAbortAfter(file, OverrideReset, c, defaultAbortAfter); Config::instance().insertTest(file, OverrideReset, c, ""); } }; template struct ConfigShowSuccessfulTests { template ConfigShowSuccessfulTests( const std::string& file, int c, U v ) { Config::instance().insertSuccessfulResults(file, OverrideUpdate, c, v ? true : false); } }; template struct ConfigWarnMissingAssertions { template ConfigWarnMissingAssertions( const std::string& file, int c, U v ) { Config::instance().insertMissingAssertions(file, OverrideUpdate, c, v ? true : false); } }; template struct ConfigAbortAfter { template ConfigAbortAfter( const std::string& file, int c, U v ) { Config::instance().insertAbortAfter(file, OverrideUpdate, c, v); } }; template struct ConfigAddTest { template ConfigAddTest( const std::string& file, int c, U v ) { Config::instance().insertTest(file, OverrideUpdate, c, v); } }; } namespace Catch { struct ConfigData { ConfigData() : listTests( false ), listTags( false ), listReporters( false ), listTestNamesOnly( false ), showSuccessfulTests( false ), shouldDebugBreak( false ), noThrow( false ), showHelp( false ), abortAfter( -1 ), verbosity( Verbosity::Normal ), warnings( WarnAbout::Nothing ), showDurations( ShowDurations::DefaultForReporter ) {} explicit ConfigData(const IConfig* other) : listTests( false ), listTags( false ), listReporters( false ), showSuccessfulTests( other ? other->includeSuccessfulResults() : false ), shouldDebugBreak( false ), noThrow( other ? !other->allowThrows() : false ), showHelp( false ), abortAfter( -1 ), verbosity( Verbosity::Normal ), warnings( other ? (other->warnAboutMissingAssertions() ? WarnAbout::NoAssertions : WarnAbout::Nothing) : WarnAbout::Nothing ), showDurations( other ? other->showDurations() : ShowDurations::DefaultForReporter ), name( other ? other->name() : std::string() ) {} bool listTests; bool listTags; bool listReporters; bool listTestNamesOnly; bool showSuccessfulTests; bool shouldDebugBreak; bool noThrow; bool showHelp; int abortAfter; Verbosity::Level verbosity; WarnAbout::What warnings; ShowDurations::OrNot showDurations; std::string reporterName; std::string outputFilename; std::string name; std::string processName; std::vector testsOrTags; }; class Config : public SharedImpl { private: Config( Config const& other ); Config& operator = ( Config const& other ); virtual void dummy(); public: Config() : m_os( std::cout.rdbuf() ) {} Config( ConfigData const& data ) : m_data( data ), m_os( std::cout.rdbuf() ) { if( !data.testsOrTags.empty() ) { std::string groupName; for( std::size_t i = 0; i < data.testsOrTags.size(); ++i ) { if( i != 0 ) groupName += " "; groupName += data.testsOrTags[i]; } TestCaseFilters filters( groupName ); for( std::size_t i = 0; i < data.testsOrTags.size(); ++i ) { std::string filter = data.testsOrTags[i]; if( startsWith( filter, "[" ) || startsWith( filter, "~[" ) ) filters.addTags( filter ); else filters.addFilter( TestCaseFilter( filter ) ); } m_filterSets.push_back( filters ); } } virtual ~Config() { m_os.rdbuf( std::cout.rdbuf() ); m_stream.release(); } void setFilename( std::string const& filename ) { m_data.outputFilename = filename; } std::string const& getFilename() const { return m_data.outputFilename ; } bool listTests() const { return m_data.listTests; } bool listTestNamesOnly() const { return m_data.listTestNamesOnly; } bool listTags() const { return m_data.listTags; } bool listReporters() const { return m_data.listReporters; } std::string getProcessName() const { return m_data.processName; } bool shouldDebugBreak() const { return m_data.shouldDebugBreak; } void setStreamBuf( std::streambuf* buf ) { m_os.rdbuf( buf ? buf : std::cout.rdbuf() ); } void useStream( std::string const& streamName ) { Stream stream = createStream( streamName ); setStreamBuf( stream.streamBuf ); m_stream.release(); m_stream = stream; } std::string getReporterName() const { return m_data.reporterName; } void addTestSpec( std::string const& testSpec ) { TestCaseFilters filters( testSpec ); filters.addFilter( TestCaseFilter( testSpec ) ); m_filterSets.push_back( filters ); } int abortAfter() const { return m_data.abortAfter; } std::vector const& filters() const { return m_filterSets; } bool showHelp() const { return m_data.showHelp; } // IConfig interface virtual bool allowThrows() const { return !m_data.noThrow; } virtual std::ostream& stream() const { return m_os; } 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; } virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; } private: ConfigData m_data; Stream m_stream; mutable std::ostream m_os; std::vector m_filterSets; }; } // end namespace Catch #endif // TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED