diff --git a/include/catch_runner.hpp b/include/catch_runner.hpp index bef75564..11266f7f 100644 --- a/include/catch_runner.hpp +++ b/include/catch_runner.hpp @@ -131,61 +131,36 @@ namespace Catch { return result; } - inline void showUsage( std::ostream& os ) { - AllOptions options; + inline void showHelp( Clara::CommandLine const& cli, std::string const& processName ) { - for( AllOptions::const_iterator it = options.begin(); it != options.end(); ++it ) { - OptionParser& opt = **it; - os << " " << opt.optionNames() << " " << opt.argsSynopsis() << "\n"; - } - os << "\nFor more detail usage please see: https://github.com/philsquared/Catch/wiki/Command-line\n" << std::endl; - } + std::cout << "\nCatch v" << libraryVersion.majorVersion << "." + << libraryVersion.minorVersion << " build " + << libraryVersion.buildNumber; + if( libraryVersion.branchName != "master" ) + std::cout << " (" << libraryVersion.branchName << " branch)"; + std::cout << "\n"; - inline void showHelp( const CommandParser& parser ) { - AllOptions options; - Options::HelpOptionParser helpOpt; - bool displayedSpecificOption = false; - for( AllOptions::const_iterator it = options.begin(); it != options.end(); ++it ) { - OptionParser& opt = **it; - if( opt.find( parser ) && opt.optionNames() != helpOpt.optionNames() ) { - displayedSpecificOption = true; - std::cout << "\n" << opt.optionNames() << " " << opt.argsSynopsis() << "\n\n" - << opt.optionSummary() << "\n\n" - << Text( opt.optionDescription(), TextAttributes().setIndent( 2 ) ) << "\n" << std::endl; - } - } - - if( !displayedSpecificOption ) { - std::cout << "\nCATCH v" << libraryVersion.majorVersion << "." - << libraryVersion.minorVersion << " build " - << libraryVersion.buildNumber; - if( libraryVersion.branchName != "master" ) - std::cout << " (" << libraryVersion.branchName << " branch)"; - - std::cout << "\n\n" << parser.exeName() << " is a CATCH host application. Options are as follows:\n\n"; - showUsage( std::cout ); - } + cli.usage( std::cout, processName ); + std::cout << "\nFor more detail usage please see: https://github.com/philsquared/Catch/wiki/Command-line\n" << std::endl; } inline int Main( int argc, char* const argv[], ConfigData configData = ConfigData() ) { + Clara::CommandLine cli = makeCommandLineParser(); + try { - CommandParser parser( argc, argv ); + cli.parseInto( argc, argv, configData ); - if( Command cmd = Options::HelpOptionParser().find( parser ) ) { - if( cmd.argsCount() != 0 ) - cmd.raiseError( "Does not accept arguments" ); - - showHelp( parser ); + if( configData.showHelp ) { + showHelp( cli, argv[0] ); Catch::cleanUp(); return 0; } - - parseCommandLine( argc, argv, configData ); } catch( std::exception& ex ) { - std::cerr << ex.what() << "\n\nUsage: ...\n\n"; - showUsage( std::cerr ); + std::cerr << "\nError in input:\n" + << " " << ex.what() << "\n\n"; + cli.usage( std::cout, argv[0] ); Catch::cleanUp(); return (std::numeric_limits::max)(); } diff --git a/include/internal/catch_commandline.hpp b/include/internal/catch_commandline.hpp index 147b1495..d6d969ed 100644 --- a/include/internal/catch_commandline.hpp +++ b/include/internal/catch_commandline.hpp @@ -655,7 +655,11 @@ namespace Catch { }; inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; } - inline void abortAfterX( ConfigData& config, int x ) { config.abortAfter = x; } + inline void abortAfterX( ConfigData& config, int x ) { + if( x < 1 ) + throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" ); + config.abortAfter = x; + } inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } inline void addWarning( ConfigData& config, std::string const& _warning ) { @@ -670,10 +674,12 @@ namespace Catch { config.verbosity = (ConfigData::Verbosity::Level)level; } - inline void parseCommandLine( int argc, char* const argv[], ConfigData& config ) { + inline Clara::CommandLine makeCommandLineParser() { Clara::CommandLine cli; + cli.bindProcessName( &ConfigData::processName ); + cli.bind( &ConfigData::showHelp ) .describe( "display usage information" ) .shortOpt( "?") @@ -690,7 +696,7 @@ namespace Catch { .shortOpt( "t") .longOpt( "list-tags" ); - cli.bind( &ConfigData::listTags ) + cli.bind( &ConfigData::listReporters ) .describe( "list all reporters" ) .longOpt( "list-reporters" ); @@ -754,12 +760,7 @@ namespace Catch { .describe( "which test or tests to use" ) .argName( "test name, pattern or tags" ); -// cli.parseInto( argc, argv, config ); - - // Legacy way - CommandParser parser( argc, argv ); - AllOptions options; - options.parseIntoConfig( parser, config ); + return cli; } } // end namespace Catch diff --git a/include/internal/catch_config.hpp b/include/internal/catch_config.hpp index c8b93b01..d294e48a 100644 --- a/include/internal/catch_config.hpp +++ b/include/internal/catch_config.hpp @@ -67,6 +67,7 @@ namespace Catch { std::string reporterName; std::string outputFilename; std::string name; + std::string processName; std::vector testsOrTags; }; diff --git a/include/internal/clara.h b/include/internal/clara.h index 7a4e4627..ada6d6ce 100644 --- a/include/internal/clara.h +++ b/include/internal/clara.h @@ -64,7 +64,7 @@ namespace Clara { BoundArgFunction( IArgFunction* _functionObj ) : functionObj( _functionObj ) {} BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj->clone() ) {} BoundArgFunction& operator = ( BoundArgFunction const& other ) { - IArgFunction newFunctionObj = other.clone(); + IArgFunction* newFunctionObj = other.functionObj->clone(); delete functionObj; functionObj = newFunctionObj; return *this; @@ -83,6 +83,14 @@ namespace Clara { }; + template + struct NullBinder : IArgFunction{ + virtual void set( C&, std::string const& ) const {} + virtual void setFlag( C& ) const {} + virtual bool takesArg() const { return true; } + virtual IArgFunction* clone() const { return new NullBinder( *this ); } + }; + template struct BoundDataMember : IArgFunction{ BoundDataMember( M C::* _member ) : member( _member ) {} @@ -354,13 +362,29 @@ namespace Clara { public: - CommandLine() : m_highestSpecifiedArgPosition( 0 ) {} + CommandLine() + : m_boundProcessName( new Detail::NullBinder() ), + m_highestSpecifiedArgPosition( 0 ) + {} + CommandLine( CommandLine const& other ) + : m_boundProcessName( other.m_boundProcessName ), + m_options ( other.m_options ), + m_positionalArgs( other.m_positionalArgs ), + m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ) + { + if( other.m_arg.get() ) + m_arg = std::auto_ptr( new Arg( *other.m_arg ) ); + } template ArgBinder bind( F f ) { ArgBinder binder( this, f ); return binder; } + template + void bindProcessName( F f ) { + m_boundProcessName = Detail::makeBoundField( f ); + } void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = CATCH_CONFIG_CONSOLE_WIDTH ) const { typename std::vector::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it; @@ -418,7 +442,6 @@ namespace Clara { return oss.str(); } - void usage( std::ostream& os, std::string const& procName ) const { os << "usage:\n " << procName << " "; argSynopsis( os ); @@ -435,6 +458,7 @@ namespace Clara { } std::vector parseInto( int argc, char const * const * argv, ConfigT& config ) const { + m_boundProcessName.set( config, argv[0] ); std::vector tokens; Parser parser; parser.parseIntoTokens( argc, argv, tokens ); @@ -458,18 +482,23 @@ namespace Clara { typename std::vector::const_iterator it = m_options.begin(), itEnd = m_options.end(); for(; it != itEnd; ++it ) { Arg const& arg = *it; - - if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) || - ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) { - if( arg.takesArg() ) { - if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional ) - throw std::domain_error( "Expected argument to option " + token.data ); - arg.boundField.set( config, tokens[++i].data ); + + try { + if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) || + ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) { + if( arg.takesArg() ) { + if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional ) + throw std::domain_error( "Expected argument to option " + token.data ); + arg.boundField.set( config, tokens[++i].data ); + } + else { + arg.boundField.setFlag( config ); + } + break; } - else { - arg.boundField.setFlag( config ); - } - break; + } + catch( std::exception& ex ) { + throw std::runtime_error( std::string( ex.what() ) + " while parsing: (" + arg.commands() + ")" ); } } if( it == itEnd ) @@ -507,6 +536,7 @@ namespace Clara { } private: + Detail::BoundArgFunction m_boundProcessName; std::vector m_options; std::map m_positionalArgs; std::auto_ptr m_arg; diff --git a/projects/SelfTest/CmdLineTests.cpp b/projects/SelfTest/CmdLineTests.cpp index 82a40b18..dba17f54 100644 --- a/projects/SelfTest/CmdLineTests.cpp +++ b/projects/SelfTest/CmdLineTests.cpp @@ -24,6 +24,7 @@ std::vector parseInto( Clara::CommandLine& cli, c struct TestOpt { TestOpt() : number( 0 ), index( 0 ), flag( false ) {} + std::string processName; std::string fileName; int number; int index; @@ -49,12 +50,19 @@ TEST_CASE( "cmdline" ) { TestOpt config; Clara::CommandLine cli; + cli.bindProcessName( &TestOpt::processName ); cli.bind( &TestOpt::fileName ) .describe( "specifies output file" ) .shortOpt( "o" ) .longOpt( "output" ) .argName( "filename" ); + SECTION( "process name" ) { + char const * argv[] = { "test", "-o filename.ext" }; + parseInto( cli, argv, config ); + + CHECK( config.processName == "test" ); + } SECTION( "arg separated by spaces" ) { char const * argv[] = { "test", "-o filename.ext" }; parseInto( cli, argv, config ); @@ -169,7 +177,7 @@ TEST_CASE( "cmdline" ) { .argName( "first arg" ) .position( 1 ); - std::cout << cli.usage( "testApp" ) << std::endl; +// std::cout << cli.usage( "testApp" ) << std::endl; const char* argv[] = { "test", "-f", "1st", "-o", "filename", "2nd", "3rd" }; parseInto( cli, argv, config ); @@ -180,205 +188,4 @@ TEST_CASE( "cmdline" ) { } } -struct Config { - - struct Verbosity { enum Level { NoOutput = 0, Quiet, Normal }; }; - struct Warning { enum Types { Nothing = 0x00, NoAssertions = 0x01 }; }; - - Config() - : listTests( false ), - listTags( false ), - listReporters( false ), - showSuccessfulTests( false ), - breakIntoDebugger( false ), - noThrow( false ), - showHelp( false ), - abortAfter( 0 ), - verbosity( Verbosity::Normal ), - warnings( Warning::Nothing ) - {} - - bool listTests; - bool listTags; - bool listReporters; - - bool showSuccessfulTests; - bool breakIntoDebugger; - bool noThrow; - bool showHelp; - - int abortAfter; - - Verbosity::Level verbosity; - Warning::Types warnings; - - std::string reporterName; - std::string fileName; - std::string suiteName; - - std::vector testsOrTags; -}; - -inline void abortAfterFirst( Config& config ) { config.abortAfter = 1; } -inline void abortAfterX( Config& config, int x ) { config.abortAfter = x; } -inline void addTestOrTags( Config& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } - -inline void addWarning( Config& config, std::string const& _warning ) { - if( _warning == "NoAssertions" ) - config.warnings = (Config::Warning::Types)( config.warnings | Config::Warning::NoAssertions ); - else - throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" ); - -} -inline void setVerbosity( Config& config, int level ) { - // !TBD: accept strings? - config.verbosity = (Config::Verbosity::Level)level; -} - - -SCENARIO( "New Catch commandline interface", "[cli]" ) { - - GIVEN( "A built cli parser for Catch" ) { - Clara::CommandLine cli; - - cli.bind( &Config::showHelp ) - .describe( "display usage information" ) - .shortOpt( "?") - .shortOpt( "h") - .longOpt( "help" ); - - cli.bind( &Config::listTests ) - .describe( "list all (or matching) test cases" ) - .shortOpt( "l") - .longOpt( "list-tests" ); - - cli.bind( &Config::listTags ) - .describe( "list all (or matching) tags" ) - .shortOpt( "t") - .longOpt( "list-tags" ); - - cli.bind( &Config::listTags ) - .describe( "list all reporters" ) - .longOpt( "list-reporters" ); - - cli.bind( &Config::showSuccessfulTests ) - .describe( "include successful tests in output" ) - .shortOpt( "s") - .longOpt( "success" ); - - cli.bind( &Config::breakIntoDebugger ) - .describe( "break into debugger on failure" ) - .shortOpt( "b") - .longOpt( "break" ); - - cli.bind( &Config::noThrow ) - .describe( "Skip exception tests" ) - .shortOpt( "e") - .longOpt( "nothrow" ); - - cli.bind( &Config::fileName ) - .describe( "output filename" ) - .shortOpt( "o") - .longOpt( "out" ) - .argName( "filename" ); - - cli.bind( &Config::reporterName ) - .describe( "reporter to use - defaults to console" ) - .shortOpt( "r") - .longOpt( "reporter" ) - .argName( "name[:filename]" ); - - cli.bind( &Config::suiteName ) - .describe( "suite name" ) - .shortOpt( "n") - .longOpt( "name" ) - .argName( "name" ); - - cli.bind( &abortAfterFirst ) - .describe( "abort at first failure" ) - .shortOpt( "a") - .longOpt( "abort" ); - - cli.bind( &abortAfterX ) - .describe( "abort after x failures" ) - .shortOpt( "x") - .longOpt( "abortx" ) - .argName( "number of failures" ); - - cli.bind( &addWarning ) - .describe( "enable warnings" ) - .shortOpt( "w") - .longOpt( "warn" ) - .argName( "warning name" ); - - cli.bind( &setVerbosity ) - .describe( "level of verbosity (0=no output)" ) - .shortOpt( "v") - .longOpt( "verbosity" ) - .argName( "level" ); - - cli.bind( &addTestOrTags ) - .describe( "which test or tests to use" ) - .argName( "test name, pattern or tags" ); - - WHEN( "We ask for usage strings" ) - THEN( "It prints the usage strings" ) - std::cout << cli.usage( "CatchTestApp" ) << std::endl; - - Config config; - - WHEN( "Multiple flags are combined" ) { - - CHECK_FALSE( config.showSuccessfulTests ); - CHECK_FALSE( config.noThrow ); - CHECK_FALSE( config.breakIntoDebugger ); - - const char* argv[] = { "test", "-seb" }; - parseInto( cli, argv, config ); - - THEN( "All the flags are set" ) { - CHECK( config.showSuccessfulTests ); - CHECK( config.noThrow ); - CHECK( config.breakIntoDebugger ); - } - } - WHEN( "A flag is set via a nullary method" ) { - CHECK( config.abortAfter == 0 ); - - const char* argv[] = { "test", "-a" }; - parseInto( cli, argv, config ); - - THEN( "The flag is set" ) - REQUIRE( config.abortAfter == 1 ); - } - WHEN( "A flag is set via a unary method" ) { - CHECK( config.abortAfter == 0 ); - - const char* argv[] = { "test", "-x", "2" }; - parseInto( cli, argv, config ); - - THEN( "The flag is set" ) - REQUIRE( config.abortAfter == 2 ); - } - WHEN( "A positional argument is supplied" ) { - - const char* argv[] = { "test", "[hello]" }; - parseInto( cli, argv, config ); - - THEN( "The argument is in the testOrTags collection" ) { - REQUIRE( config.testsOrTags.size() == 1 ); - REQUIRE( config.testsOrTags[0] == "[hello]" ); - } - } - WHEN( "And enum opt is set by numeric value" ) { - CHECK( config.verbosity == Config::Verbosity::Normal ); - - const char* argv[] = { "test", "-v 0" }; - parseInto( cli, argv, config ); - - THEN( "The member is set to the enum value" ) - REQUIRE( config.verbosity == Config::Verbosity::NoOutput ); - } - } -} #endif diff --git a/projects/SelfTest/MiscTests.cpp b/projects/SelfTest/MiscTests.cpp index dc23bd58..f8bdcbc3 100644 --- a/projects/SelfTest/MiscTests.cpp +++ b/projects/SelfTest/MiscTests.cpp @@ -260,8 +260,7 @@ inline unsigned int Factorial( unsigned int number ) return number > 1 ? Factorial(number-1)*number : 1; } -TEST_CASE( "example/factorial", "The Factorial function should return the factorial of the number passed in" ) -{ +TEST_CASE( "Factorials are computed", "[factorial]" ) { REQUIRE( Factorial(0) == 1 ); REQUIRE( Factorial(1) == 1 ); REQUIRE( Factorial(2) == 2 ); diff --git a/projects/SelfTest/TestMain.cpp b/projects/SelfTest/TestMain.cpp index befe5a66..1272f597 100644 --- a/projects/SelfTest/TestMain.cpp +++ b/projects/SelfTest/TestMain.cpp @@ -71,8 +71,8 @@ TEST_CASE( "meta/Misc/Sections", "looped tests" ) { template void parseIntoConfig( const char * (&argv)[size], Catch::ConfigData& config ) { - static Catch::AllOptions options; - options.parseIntoConfig( Catch::CommandParser( size, argv ), config ); + Clara::CommandLine parser = Catch::makeCommandLineParser(); + parser.parseInto( size, argv, config ); } template @@ -89,11 +89,11 @@ std::string parseIntoConfigAndReturnError( const char * (&argv)[size], Catch::Co inline Catch::TestCase fakeTestCase( const char* name ){ return Catch::makeTestCase( NULL, "", name, "", CATCH_INTERNAL_LINEINFO ); } -TEST_CASE( "selftest/parser/2", "ConfigData" ) { +TEST_CASE( "Process can be configured on command line", "[config][command-line]" ) { Catch::ConfigData config; - SECTION( "default", "" ) { + SECTION( "default - no arguments", "" ) { const char* argv[] = { "test" }; CHECK_NOTHROW( parseIntoConfig( argv, config ) ); @@ -104,8 +104,8 @@ TEST_CASE( "selftest/parser/2", "ConfigData" ) { } SECTION( "test lists", "" ) { - SECTION( "-t/1", "Specify one test case using -t" ) { - const char* argv[] = { "test", "-t", "test1" }; + SECTION( "1 test", "Specify one test case using" ) { + const char* argv[] = { "test", "test1" }; CHECK_NOTHROW( parseIntoConfig( argv, config ) ); Catch::Config cfg( config ); @@ -113,8 +113,8 @@ TEST_CASE( "selftest/parser/2", "ConfigData" ) { REQUIRE( cfg.filters()[0].shouldInclude( fakeTestCase( "notIncluded" ) ) == false ); REQUIRE( cfg.filters()[0].shouldInclude( fakeTestCase( "test1" ) ) ); } - SECTION( "-t/exclude:1", "Specify one test case exclusion using -t exclude:" ) { - const char* argv[] = { "test", "-t", "exclude:test1" }; + SECTION( "Specify one test case exclusion using exclude:", "" ) { + const char* argv[] = { "test", "exclude:test1" }; CHECK_NOTHROW( parseIntoConfig( argv, config ) ); Catch::Config cfg( config ); @@ -123,28 +123,8 @@ TEST_CASE( "selftest/parser/2", "ConfigData" ) { REQUIRE( cfg.filters()[0].shouldInclude( fakeTestCase( "alwaysIncluded" ) ) ); } - SECTION( "--test/1", "Specify one test case using --test" ) { - const char* argv[] = { "test", "--test", "test1" }; - CHECK_NOTHROW( parseIntoConfig( argv, config ) ); - - Catch::Config cfg( config ); - REQUIRE( cfg.filters().size() == 1 ); - REQUIRE( cfg.filters()[0].shouldInclude( fakeTestCase( "notIncluded" ) ) == false ); - REQUIRE( cfg.filters()[0].shouldInclude( fakeTestCase( "test1" ) ) ); - } - - SECTION( "--test/exclude:1", "Specify one test case exclusion using --test exclude:" ) { - const char* argv[] = { "test", "--test", "exclude:test1" }; - CHECK_NOTHROW( parseIntoConfig( argv, config ) ); - - Catch::Config cfg( config ); - REQUIRE( cfg.filters().size() == 1 ); - REQUIRE( cfg.filters()[0].shouldInclude( fakeTestCase( "test1" ) ) == false ); - REQUIRE( cfg.filters()[0].shouldInclude( fakeTestCase( "alwaysIncluded" ) ) ); - } - - SECTION( "--test/exclude:2", "Specify one test case exclusion using --test ~" ) { - const char* argv[] = { "test", "--test", "~test1" }; + SECTION( "Specify one test case exclusion using ~", "" ) { + const char* argv[] = { "test", "~test1" }; CHECK_NOTHROW( parseIntoConfig( argv, config ) ); Catch::Config cfg( config ); @@ -153,7 +133,7 @@ TEST_CASE( "selftest/parser/2", "ConfigData" ) { REQUIRE( cfg.filters()[0].shouldInclude( fakeTestCase( "alwaysIncluded" ) ) ); } - SECTION( "-t/2", "Specify two test cases using -t" ) { + SECTION( "Specify two test cases using -t", "" ) { const char* argv[] = { "test", "-t", "test1", "test2" }; CHECK_NOTHROW( parseIntoConfig( argv, config ) ); @@ -163,11 +143,6 @@ TEST_CASE( "selftest/parser/2", "ConfigData" ) { REQUIRE( cfg.filters()[0].shouldInclude( fakeTestCase( "test1" ) ) ); REQUIRE( cfg.filters()[0].shouldInclude( fakeTestCase( "test2" ) ) ); } - - SECTION( "-t/0", "When no test names are supplied it is an error" ) { - const char* argv[] = { "test", "-t" }; - REQUIRE_THAT( parseIntoConfigAndReturnError( argv, config ), Contains( "at least 1" ) ); - } } SECTION( "reporter", "" ) { @@ -189,10 +164,6 @@ TEST_CASE( "selftest/parser/2", "ConfigData" ) { REQUIRE( config.reporterName == "junit" ); } - SECTION( "-r/error", "reporter config only accepts one argument" ) { - const char* argv[] = { "test", "-r", "one", "two" }; - REQUIRE_THAT( parseIntoConfigAndReturnError( argv, config ), Contains( "1 argument" ) ); - } } SECTION( "debugger", "" ) { @@ -208,42 +179,34 @@ TEST_CASE( "selftest/parser/2", "ConfigData" ) { REQUIRE( config.shouldDebugBreak ); } - SECTION( "-b", "break option has no arguments" ) { - const char* argv[] = { "test", "-b", "unexpected" }; - REQUIRE_THAT( parseIntoConfigAndReturnError( argv, config ), Contains( "0 arguments" ) ); - } } SECTION( "abort", "" ) { - SECTION( "-a", "" ) { + SECTION( "-a aborts after first failure", "" ) { const char* argv[] = { "test", "-a" }; CHECK_NOTHROW( parseIntoConfig( argv, config ) ); REQUIRE( config.abortAfter == 1 ); } - SECTION( "-a/2", "" ) { - const char* argv[] = { "test", "-a", "2" }; + SECTION( "-x 2 aborts after two failures", "" ) { + const char* argv[] = { "test", "-x", "2" }; CHECK_NOTHROW( parseIntoConfig( argv, config ) ); REQUIRE( config.abortAfter == 2 ); } - SECTION( "-a/error/0", "" ) { - const char* argv[] = { "test", "-a", "0" }; + SECTION( "-x must be greater than zero", "" ) { + const char* argv[] = { "test", "-x", "0" }; REQUIRE_THAT( parseIntoConfigAndReturnError( argv, config ), Contains( "greater than zero" ) ); } - SECTION( "-a/error/non numeric", "" ) { - const char* argv[] = { "test", "-a", "oops" }; - REQUIRE_THAT( parseIntoConfigAndReturnError( argv, config ), Contains( "greater than zero" ) ); - } - SECTION( "-a/error/two args", "abortAfter only takes one argument" ) { - const char* argv[] = { "test", "-a", "1", "2" }; - REQUIRE_THAT( parseIntoConfigAndReturnError( argv, config ), Contains( "0 and 1 argument" ) ); + SECTION( "-x must be numeric", "" ) { + const char* argv[] = { "test", "-x", "oops" }; + REQUIRE_THAT( parseIntoConfigAndReturnError( argv, config ), Contains( "-x" ) ); } } SECTION( "nothrow", "" ) { - SECTION( "-nt", "" ) { - const char* argv[] = { "test", "-nt" }; + SECTION( "-e", "" ) { + const char* argv[] = { "test", "-e" }; CHECK_NOTHROW( parseIntoConfig( argv, config ) ); REQUIRE( config.noThrow == true ); @@ -272,8 +235,8 @@ TEST_CASE( "selftest/parser/2", "ConfigData" ) { } SECTION( "combinations", "" ) { - SECTION( "-a -b", "" ) { - const char* argv[] = { "test", "-a", "-b", "-nt" }; + SECTION( "Single character flags can be combined", "" ) { + const char* argv[] = { "test", "-abe" }; CHECK_NOTHROW( parseIntoConfig( argv, config ) ); CHECK( config.abortAfter == 1 );