diff --git a/include/catch_runner.hpp b/include/catch_runner.hpp index 450e071e..4164a0e6 100644 --- a/include/catch_runner.hpp +++ b/include/catch_runner.hpp @@ -85,6 +85,7 @@ namespace Catch { << "\t-b, --break\n" << "\t-n, --name \n" << "\t-a, --abort [#]\n\n" + << "\t-nt, --nothrow\n\n" << "For more detail usage please see: https://github.com/philsquared/Catch/wiki/Command-line" << std::endl; } inline void showHelp( std::string exeName ) { @@ -98,22 +99,39 @@ namespace Catch { } inline int Main( int argc, char* const argv[], Config& config ) { - - parseIntoConfig( CommandParser( argc, argv ), config ); + + try { + CommandParser parser( argc, argv ); - if( !config.getMessage().empty() ) { - std::cerr << config.getMessage() << + "\n\nUsage: ...\n\n"; + if( Command cmd = parser.find( "-h", "-?", "--help" ) ) { + if( cmd.argsCount() != 0 ) + cmd.raiseError( "Does not accept arguments" ); + + showHelp( argv[0] ); + Catch::Context::cleanUp(); + return 0; + } + + parseIntoConfig( parser, config.data() ); + + // !TBD: wire up (do this lazily?) + if( !config.data().reporter.empty() ) + config.setReporter( config.data().reporter ); + + if( !config.data().stream.empty() ) { + if( config.data().stream[0] == '%' ) + config.useStream( config.data().stream.substr( 1 ) ); + else + config.setFilename( config.data().stream ); + } + } + catch( std::exception& ex ) { + std::cerr << ex.what() << + "\n\nUsage: ...\n\n"; showUsage( std::cerr ); Catch::Context::cleanUp(); return (std::numeric_limits::max)(); } - - // Handle help - if( config.showHelp() ) { - showHelp( argv[0] ); - Catch::Context::cleanUp(); - return 0; - } + return Main( config ); } diff --git a/include/internal/catch_commandline.hpp b/include/internal/catch_commandline.hpp index 41aa91c8..49928f4c 100644 --- a/include/internal/catch_commandline.hpp +++ b/include/internal/catch_commandline.hpp @@ -88,107 +88,92 @@ namespace Catch { std::size_t m_argc; char const * const * m_argv; }; - - inline bool parseIntoConfig( const CommandParser& parser, Config& config ) { + + inline void parseIntoConfig( const CommandParser& parser, ConfigData& config ) { + + if( Command cmd = parser.find( "-l", "--list" ) ) { + if( cmd.argsCount() > 2 ) + cmd.raiseError( "Expected upto 2 arguments" ); - try { - if( Command cmd = parser.find( "-l", "--list" ) ) { - if( cmd.argsCount() > 2 ) - cmd.raiseError( "Expected upto 2 arguments" ); - - List::What listSpec = List::All; - if( cmd.argsCount() >= 1 ) { - if( cmd[0] == "tests" ) - listSpec = List::Tests; - else if( cmd[0] == "reporters" ) - listSpec = List::Reports; - else - cmd.raiseError( "Expected [tests] or [reporters]" ); - } - if( cmd.argsCount() >= 2 ) { - if( cmd[1] == "xml" ) - listSpec = static_cast( listSpec | List::AsXml ); - else if( cmd[1] == "text" ) - listSpec = static_cast( listSpec | List::AsText ); - else - cmd.raiseError( "Expected [xml] or [text]" ); - } - config.setListSpec( static_cast( config.getListSpec() | listSpec ) ); - } - - if( Command cmd = parser.find( "-t", "--test" ) ) { - if( cmd.argsCount() == 0 ) - cmd.raiseError( "Expected at least one argument" ); - for( std::size_t i = 0; i < cmd.argsCount(); ++i ) - config.addTestSpec( cmd[i] ); - } - - if( Command cmd = parser.find( "-r", "--reporter" ) ) { - if( cmd.argsCount() != 1 ) - cmd.raiseError( "Expected one argument" ); - config.setReporter( cmd[0] ); - } - - if( Command cmd = parser.find( "-o", "--out" ) ) { - if( cmd.argsCount() == 0 ) - cmd.raiseError( "Expected filename" ); - if( cmd[0][0] == '%' ) - config.useStream( cmd[0].substr( 1 ) ); + List::What listSpec = List::All; + if( cmd.argsCount() >= 1 ) { + if( cmd[0] == "tests" ) + config.listSpec = List::Tests; + else if( cmd[0] == "reporters" ) + config.listSpec = List::Reports; else - config.setFilename( cmd[0] ); + cmd.raiseError( "Expected [tests] or [reporters]" ); } - - if( Command cmd = parser.find( "-s", "--success" ) ) { - if( cmd.argsCount() != 0 ) - cmd.raiseError( "Does not accept arguments" ); - config.setIncludeWhichResults( Include::SuccessfulResults ); + if( cmd.argsCount() >= 2 ) { + if( cmd[1] == "xml" ) + config.listSpec = static_cast( listSpec | List::AsXml ); + else if( cmd[1] == "text" ) + config.listSpec = static_cast( listSpec | List::AsText ); + else + cmd.raiseError( "Expected [xml] or [text]" ); } - - if( Command cmd = parser.find( "-b", "--break" ) ) { - if( cmd.argsCount() != 0 ) - cmd.raiseError( "Does not accept arguments" ); - config.setShouldDebugBreak( true ); - } - - if( Command cmd = parser.find( "-n", "--name" ) ) { - if( cmd.argsCount() != 1 ) - cmd.raiseError( "Expected a name" ); - config.setName( cmd[0] ); - } - - if( Command cmd = parser.find( "-h", "-?", "--help" ) ) { - if( cmd.argsCount() != 0 ) - cmd.raiseError( "Does not accept arguments" ); - config.setShowHelp( true ); - } - - if( Command cmd = parser.find( "-a", "--abort" ) ) { - if( cmd.argsCount() > 1 ) - cmd.raiseError( "Only accepts 0-1 arguments" ); - int threshold = 1; - if( cmd.argsCount() == 1 ) - { - std::stringstream ss; - ss << cmd[0]; - ss >> threshold; - } - config.setCutoff( threshold ); - } - - if( Command cmd = parser.find( "-nt", "--nothrow" ) ) { - if( cmd.argsCount() != 0 ) - cmd.raiseError( "Does not accept arguments" ); - config.setAllowThrows( false ); - } - } - catch( std::exception& ex ) { - config.setError( ex.what() ); - return false; - } - return true; + + if( Command cmd = parser.find( "-t", "--test" ) ) { + if( cmd.argsCount() == 0 ) + cmd.raiseError( "Expected at least one argument" ); + for( std::size_t i = 0; i < cmd.argsCount(); ++i ) + config.testSpecs.push_back( cmd[i] ); + } + + if( Command cmd = parser.find( "-r", "--reporter" ) ) { + if( cmd.argsCount() != 1 ) + cmd.raiseError( "Expected one argument" ); + config.reporter = cmd[0]; + } + + if( Command cmd = parser.find( "-o", "--out" ) ) { + if( cmd.argsCount() == 0 ) + cmd.raiseError( "Expected filename" ); + if( cmd[0][0] == '%' ) + config.stream = cmd[0].substr( 1 ); + else + config.outputFilename = cmd[0]; + } + + if( Command cmd = parser.find( "-s", "--success" ) ) { + if( cmd.argsCount() != 0 ) + cmd.raiseError( "Does not accept arguments" ); + config.includeWhichResults = Include::SuccessfulResults; + } + + if( Command cmd = parser.find( "-b", "--break" ) ) { + if( cmd.argsCount() != 0 ) + cmd.raiseError( "Does not accept arguments" ); + config.shouldDebugBreak = true; + } + + if( Command cmd = parser.find( "-n", "--name" ) ) { + if( cmd.argsCount() != 1 ) + cmd.raiseError( "Expected a name" ); + config.name = cmd[0]; + } + + if( Command cmd = parser.find( "-a", "--abort" ) ) { + if( cmd.argsCount() > 1 ) + cmd.raiseError( "Only accepts 0-1 arguments" ); + int threshold = 1; + if( cmd.argsCount() == 1 ) { + std::stringstream ss; + ss << cmd[0]; + ss >> threshold; + } + config.cutoff = threshold; + } + + if( Command cmd = parser.find( "-nt", "--nothrow" ) ) { + if( cmd.argsCount() != 0 ) + cmd.raiseError( "Does not accept arguments" ); + config.allowThrows = false; + } + } - + } // end namespace Catch #endif // TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED diff --git a/include/internal/catch_config.hpp b/include/internal/catch_config.hpp index 9c9661e2..15abcd70 100644 --- a/include/internal/catch_config.hpp +++ b/include/internal/catch_config.hpp @@ -38,6 +38,28 @@ namespace Catch { AsMask = 0xf0 }; }; + struct ConfigData { + ConfigData() + : listSpec( List::None ), + shouldDebugBreak( false ), + includeWhichResults( Include::FailedOnly ), + cutoff( -1 ), + allowThrows( true ) + {} + + std::string reporter; + std::string outputFilename; + List::What listSpec; + std::vector testSpecs; + bool shouldDebugBreak; + std::string stream; + Include::WhichResults includeWhichResults; + std::string name; + int cutoff; + bool allowThrows; + }; + + class Config : public IReporterConfig, public IConfig { private: Config( const Config& other ); @@ -45,14 +67,14 @@ namespace Catch { public: Config() - : m_listSpec( List::None ), - m_shouldDebugBreak( false ), - m_showHelp( false ), + : m_streambuf( NULL ), + m_os( std::cout.rdbuf() ) + {} + + Config( const ConfigData& data ) + : m_data( data ), m_streambuf( NULL ), - m_os( std::cout.rdbuf() ), - m_includeWhichResults( Include::FailedOnly ), - m_cutoff( -1 ), - m_allowThrows( true ) + m_os( std::cout.rdbuf() ) {} ~Config() { @@ -62,44 +84,28 @@ namespace Catch { void setReporter( const std::string& reporterName ) { if( m_reporter.get() ) - return setError( "Only one reporter may be specified" ); + throw std::domain_error( "Only one reporter may be specified" ); setReporter( getCurrentContext().getReporterRegistry().create( reporterName, *this ) ); } - - void addTestSpec( const std::string& testSpec ) { - m_testSpecs.push_back( testSpec ); + + void setFilename( const std::string& filename ) { + m_data.outputFilename = filename; } bool testsSpecified() const { - return !m_testSpecs.empty(); + return !m_data.testSpecs.empty(); } const std::vector& getTestSpecs() const { - return m_testSpecs; + return m_data.testSpecs; } List::What getListSpec( void ) const { - return m_listSpec; + return m_data.listSpec; } - void setListSpec( List::What listSpec ) { - m_listSpec = listSpec; - } - - void setFilename( const std::string& filename ) { - m_filename = filename; - } - const std::string& getFilename() const { - return m_filename; - } - - const std::string& getMessage() const { - return m_message; - } - - void setError( const std::string& errorMessage ) { - m_message = errorMessage; + return m_data.outputFilename ; } void setReporter( IReporter* reporter ) { @@ -113,39 +119,19 @@ namespace Catch { } List::What listWhat() const { - return static_cast( m_listSpec & List::WhatMask ); + return static_cast( m_data.listSpec & List::WhatMask ); } List::What listAs() const { - return static_cast( m_listSpec & List::AsMask ); - } - - void setIncludeWhichResults( Include::WhichResults includeWhichResults ) { - m_includeWhichResults = includeWhichResults; - } - - void setShouldDebugBreak( bool shouldDebugBreakFlag ) { - m_shouldDebugBreak = shouldDebugBreakFlag; - } - - void setName( const std::string& name ) { - m_name = name; + return static_cast( m_data.listSpec & List::AsMask ); } std::string getName() const { - return m_name; + return m_data.name; } bool shouldDebugBreak() const { - return m_shouldDebugBreak; - } - - void setShowHelp( bool showHelpFlag ) { - m_showHelp = showHelpFlag; - } - - bool showHelp() const { - return m_showHelp; + return m_data.shouldDebugBreak; } virtual std::ostream& stream() const { @@ -164,53 +150,30 @@ namespace Catch { } virtual bool includeSuccessfulResults() const { - return m_includeWhichResults == Include::SuccessfulResults; + return m_data.includeWhichResults == Include::SuccessfulResults; } int getCutoff() const { - return m_cutoff; - } - - void setCutoff( int cutoff ) { - m_cutoff = cutoff; - } - - void setAllowThrows( bool allowThrows ) { - m_allowThrows = allowThrows; + return m_data.cutoff; } virtual bool allowThrows() const { - return m_allowThrows; + return m_data.allowThrows; + } + + ConfigData& data() { + return m_data; } private: + ConfigData m_data; + + // !TBD Move these out of here Ptr m_reporter; - std::string m_filename; - std::string m_message; - List::What m_listSpec; - std::vector m_testSpecs; - bool m_shouldDebugBreak; - bool m_showHelp; std::streambuf* m_streambuf; mutable std::ostream m_os; - Include::WhichResults m_includeWhichResults; - std::string m_name; - int m_cutoff; - bool m_allowThrows; }; - - struct NewConfig { - std::string reporter; - std::string outputFilename; - List::What listSpec; - std::vector testSpecs; - bool shouldDebugBreak; - bool showHelp; - Include::WhichResults includeWhichResults; - std::string name; - }; - - + } // end namespace Catch diff --git a/include/internal/catch_runner_impl.hpp b/include/internal/catch_runner_impl.hpp index a95922c7..885bd61d 100644 --- a/include/internal/catch_runner_impl.hpp +++ b/include/internal/catch_runner_impl.hpp @@ -61,7 +61,8 @@ namespace Catch { m_config( config ), m_reporter( config.getReporter() ), m_prevRunner( &m_context.getRunner() ), - m_prevResultCapture( &m_context.getResultCapture() ) + m_prevResultCapture( &m_context.getResultCapture() ), + m_prevConfig( m_context.getConfig() ) { m_context.setRunner( this ); m_context.setConfig( &m_config ); @@ -74,6 +75,7 @@ namespace Catch { m_context.setRunner( m_prevRunner ); m_context.setConfig( NULL ); m_context.setResultCapture( m_prevResultCapture ); + m_context.setConfig( m_prevConfig ); } virtual void runAll( bool runHiddenTests = false ) { @@ -293,6 +295,7 @@ namespace Catch { std::vector m_info; IRunner* m_prevRunner; IResultCapture* m_prevResultCapture; + const IConfig* m_prevConfig; }; } // end namespace Catch diff --git a/projects/SelfTest/TestMain.cpp b/projects/SelfTest/TestMain.cpp index 23691b55..b0183ef1 100644 --- a/projects/SelfTest/TestMain.cpp +++ b/projects/SelfTest/TestMain.cpp @@ -60,200 +60,154 @@ TEST_CASE( "meta/Misc/Sections", "looped tests" ) { #include "../../include/reporters/catch_reporter_junit.hpp" template -bool parseIntoConfig( const char * (&argv)[size], Catch::Config& config ) { - return Catch::parseIntoConfig( Catch::CommandParser( size, argv ), config ); +void parseIntoConfig( const char * (&argv)[size], Catch::ConfigData& config ) { + Catch::parseIntoConfig( Catch::CommandParser( size, argv ), config ); } -TEST_CASE( "selftest/parser", "" ) { +template +std::string parseIntoConfigAndReturnError( const char * (&argv)[size], Catch::ConfigData& config ) { + try { + Catch::parseIntoConfig( Catch::CommandParser( size, argv ), config ); + } + catch( std::exception& ex ) { + return ex.what(); + } + return ""; +} + +TEST_CASE( "selftest/parser/2", "ConfigData" ) { + + Catch::ConfigData config; SECTION( "default", "" ) { const char* argv[] = { "test" }; - Catch::Config config; - CHECK( parseIntoConfig( argv, config ) ); + CHECK_NOTHROW( parseIntoConfig( argv, config ) ); - CHECK( config.getTestSpecs().empty() ); - CHECK( config.shouldDebugBreak() == false ); - CHECK( config.showHelp() == false ); - CHECK( config.getCutoff() == -1 ); - CHECK( config.allowThrows() == true ); - CHECK( dynamic_cast( config.getReporter().get() ) ); + CHECK( config.testSpecs.empty() ); + CHECK( config.shouldDebugBreak == false ); + CHECK( config.cutoff == -1 ); + CHECK( config.allowThrows == true ); + CHECK( config.reporter.empty() ); } SECTION( "test lists", "" ) { SECTION( "-t/1", "Specify one test case using -t" ) { const char* argv[] = { "test", "-t", "test1" }; - Catch::Config config; - CHECK( parseIntoConfig( argv, config ) ); + CHECK_NOTHROW( parseIntoConfig( argv, config ) ); - REQUIRE( config.getTestSpecs().size() == 1 ); - REQUIRE( config.getTestSpecs()[0] == "test1" ); + REQUIRE( config.testSpecs.size() == 1 ); + REQUIRE( config.testSpecs[0] == "test1" ); } SECTION( "--test/1", "Specify one test case using --test" ) { const char* argv[] = { "test", "--test", "test1" }; - Catch::Config config; - CHECK( parseIntoConfig( argv, config ) ); + CHECK_NOTHROW( parseIntoConfig( argv, config ) ); - REQUIRE( config.getTestSpecs().size() == 1 ); - REQUIRE( config.getTestSpecs()[0] == "test1" ); + REQUIRE( config.testSpecs.size() == 1 ); + REQUIRE( config.testSpecs[0] == "test1" ); } SECTION( "-t/2", "Specify two test cases using -t" ) { const char* argv[] = { "test", "-t", "test1", "test2" }; - Catch::Config config; - CHECK( parseIntoConfig( argv, config ) ); + CHECK_NOTHROW( parseIntoConfig( argv, config ) ); - REQUIRE( config.getTestSpecs().size() == 2 ); - REQUIRE( config.getTestSpecs()[0] == "test1" ); - REQUIRE( config.getTestSpecs()[1] == "test2" ); + REQUIRE( config.testSpecs.size() == 2 ); + REQUIRE( config.testSpecs[0] == "test1" ); + REQUIRE( config.testSpecs[1] == "test2" ); } SECTION( "-t/0", "When no test names are supplied it is an error" ) { const char* argv[] = { "test", "-t" }; - Catch::Config config; - CHECK( parseIntoConfig( argv, config ) == false ); - - REQUIRE_THAT( config.getMessage(), Contains( "at least one" ) ); + REQUIRE_THAT( parseIntoConfigAndReturnError( argv, config ), Contains( "at least one" ) ); } } SECTION( "reporter", "" ) { SECTION( "-r/basic", "" ) { - const char* argv[] = { "test", "-reporter", "basic" }; - Catch::Config config; - CHECK( parseIntoConfig( argv, config ) ); + const char* argv[] = { "test", "-r", "basic" }; + CHECK_NOTHROW( parseIntoConfig( argv, config ) ); - REQUIRE( dynamic_cast( config.getReporter().get() ) ); + REQUIRE( config.reporter == "basic" ); } SECTION( "-r/xml", "" ) { const char* argv[] = { "test", "-r", "xml" }; - Catch::Config config; - CHECK( parseIntoConfig( argv, config ) ); + CHECK_NOTHROW( parseIntoConfig( argv, config ) ); - REQUIRE( dynamic_cast( config.getReporter().get() ) ); + REQUIRE( config.reporter == "xml" ); } - SECTION( "-r/junit", "" ) { - const char* argv[] = { "test", "-r", "junit" }; - Catch::Config config; - CHECK( parseIntoConfig( argv, config ) ); + SECTION( "--reporter/junit", "" ) { + const char* argv[] = { "test", "--reporter", "junit" }; + CHECK_NOTHROW( parseIntoConfig( argv, config ) ); - REQUIRE( dynamic_cast( config.getReporter().get() ) ); + REQUIRE( config.reporter == "junit" ); } SECTION( "-r/error", "reporter config only accepts one argument" ) { const char* argv[] = { "test", "-r", "one", "two" }; - Catch::Config config; - CHECK( parseIntoConfig( argv, config ) == false ); - - REQUIRE_THAT( config.getMessage(), Contains( "one argument" ) ); + REQUIRE_THAT( parseIntoConfigAndReturnError( argv, config ), Contains( "one argument" ) ); } } SECTION( "debugger", "" ) { SECTION( "-b", "" ) { const char* argv[] = { "test", "-b" }; - Catch::Config config; - CHECK( parseIntoConfig( argv, config ) ); + CHECK_NOTHROW( parseIntoConfig( argv, config ) ); - REQUIRE( config.shouldDebugBreak() == true ); + REQUIRE( config.shouldDebugBreak == true ); } SECTION( "--break", "" ) { const char* argv[] = { "test", "--break" }; - Catch::Config config; - CHECK( parseIntoConfig( argv, config ) ); + CHECK_NOTHROW( parseIntoConfig( argv, config ) ); - REQUIRE( config.shouldDebugBreak() ); + REQUIRE( config.shouldDebugBreak ); } SECTION( "-b", "break option has no arguments" ) { const char* argv[] = { "test", "-b", "unexpected" }; - Catch::Config config; - CHECK( parseIntoConfig( argv, config ) == false ); - - REQUIRE_THAT( config.getMessage(), Contains( "not accept" ) ); + REQUIRE_THAT( parseIntoConfigAndReturnError( argv, config ), Contains( "not accept" ) ); } } - - SECTION( "help", "" ) { - SECTION( "-h", "" ) { - const char* argv[] = { "test", "-h" }; - Catch::Config config; - CHECK( parseIntoConfig( argv, config ) ); - - REQUIRE( config.showHelp() ); - } - SECTION( "-?", "" ) { - const char* argv[] = { "test", "-?" }; - Catch::Config config; - CHECK( parseIntoConfig( argv, config ) ); - - REQUIRE( config.showHelp() ); - } - SECTION( "--help", "" ) { - const char* argv[] = { "test", "--help" }; - Catch::Config config; - CHECK( parseIntoConfig( argv, config ) ); - - REQUIRE( config.showHelp() ); - } - SECTION( "-h", "help option has no arguments" ) { - const char* argv[] = { "test", "-h", "unexpected" }; - Catch::Config config; - CHECK( parseIntoConfig( argv, config ) == false ); - - REQUIRE_THAT( config.getMessage(), Contains( "not accept" ) ); - } - } - + SECTION( "abort", "" ) { SECTION( "-a", "" ) { const char* argv[] = { "test", "-a" }; - Catch::Config config; - CHECK( parseIntoConfig( argv, config ) ); + CHECK_NOTHROW( parseIntoConfig( argv, config ) ); - REQUIRE( config.getCutoff() == 1 ); + REQUIRE( config.cutoff == 1 ); } SECTION( "-a/2", "" ) { const char* argv[] = { "test", "-a", "2" }; - Catch::Config config; - CHECK( parseIntoConfig( argv, config ) ); + CHECK_NOTHROW( parseIntoConfig( argv, config ) ); - REQUIRE( config.getCutoff() == 2 ); + REQUIRE( config.cutoff == 2 ); } SECTION( "-a/error", "cutoff only takes one argument" ) { const char* argv[] = { "test", "-a", "1", "2" }; - Catch::Config config; - CHECK( parseIntoConfig( argv, config ) == false ); - - REQUIRE_THAT( config.getMessage(), Contains( "accepts" ) ); + REQUIRE_THAT( parseIntoConfigAndReturnError( argv, config ), Contains( "accepts" ) ); } } SECTION( "nothrow", "" ) { SECTION( "-nt", "" ) { const char* argv[] = { "test", "-nt" }; - Catch::Config config; - CHECK( parseIntoConfig( argv, config ) ); + CHECK_NOTHROW( parseIntoConfig( argv, config ) ); - REQUIRE( config.allowThrows() == false ); + REQUIRE( config.allowThrows == false ); } SECTION( "--nothrow", "" ) { const char* argv[] = { "test", "--nothrow" }; - Catch::Config config; - CHECK( parseIntoConfig( argv, config ) ); + CHECK_NOTHROW( parseIntoConfig( argv, config ) ); - REQUIRE( config.allowThrows() == false ); + REQUIRE( config.allowThrows == false ); } } SECTION( "combinations", "" ) { SECTION( "-a -b", "" ) { const char* argv[] = { "test", "-a", "-b", "-nt" }; - Catch::Config config; - CHECK( parseIntoConfig( argv, config ) ); + CHECK_NOTHROW( parseIntoConfig( argv, config ) ); - CHECK( config.getCutoff() == 1 ); - CHECK( config.shouldDebugBreak() ); - CHECK( config.allowThrows() == false ); + CHECK( config.cutoff == 1 ); + CHECK( config.shouldDebugBreak ); + CHECK( config.allowThrows == false ); } - } - + } }