mirror of
https://github.com/catchorg/Catch2.git
synced 2025-08-01 12:55:40 +02:00
Now fully switched over to Clara-based command line with modified args
This commit is contained in:
@@ -131,61 +131,36 @@ namespace Catch {
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void showUsage( std::ostream& os ) {
|
||||
AllOptions options;
|
||||
inline void showHelp( Clara::CommandLine<ConfigData> 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<ConfigData> 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<int>::max)();
|
||||
}
|
||||
|
@@ -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<ConfigData> makeCommandLineParser() {
|
||||
|
||||
Clara::CommandLine<ConfigData> 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
|
||||
|
@@ -67,6 +67,7 @@ namespace Catch {
|
||||
std::string reporterName;
|
||||
std::string outputFilename;
|
||||
std::string name;
|
||||
std::string processName;
|
||||
|
||||
std::vector<std::string> testsOrTags;
|
||||
};
|
||||
|
@@ -64,7 +64,7 @@ namespace Clara {
|
||||
BoundArgFunction( IArgFunction<ConfigT>* _functionObj ) : functionObj( _functionObj ) {}
|
||||
BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj->clone() ) {}
|
||||
BoundArgFunction& operator = ( BoundArgFunction const& other ) {
|
||||
IArgFunction<ConfigT> newFunctionObj = other.clone();
|
||||
IArgFunction<ConfigT>* newFunctionObj = other.functionObj->clone();
|
||||
delete functionObj;
|
||||
functionObj = newFunctionObj;
|
||||
return *this;
|
||||
@@ -83,6 +83,14 @@ namespace Clara {
|
||||
};
|
||||
|
||||
|
||||
template<typename C>
|
||||
struct NullBinder : IArgFunction<C>{
|
||||
virtual void set( C&, std::string const& ) const {}
|
||||
virtual void setFlag( C& ) const {}
|
||||
virtual bool takesArg() const { return true; }
|
||||
virtual IArgFunction<C>* clone() const { return new NullBinder( *this ); }
|
||||
};
|
||||
|
||||
template<typename C, typename M>
|
||||
struct BoundDataMember : IArgFunction<C>{
|
||||
BoundDataMember( M C::* _member ) : member( _member ) {}
|
||||
@@ -354,13 +362,29 @@ namespace Clara {
|
||||
|
||||
public:
|
||||
|
||||
CommandLine() : m_highestSpecifiedArgPosition( 0 ) {}
|
||||
CommandLine()
|
||||
: m_boundProcessName( new Detail::NullBinder<ConfigT>() ),
|
||||
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<Arg>( new Arg( *other.m_arg ) );
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
ArgBinder bind( F f ) {
|
||||
ArgBinder binder( this, f );
|
||||
return binder;
|
||||
}
|
||||
template<typename F>
|
||||
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<Arg>::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<Parser::Token> parseInto( int argc, char const * const * argv, ConfigT& config ) const {
|
||||
m_boundProcessName.set( config, argv[0] );
|
||||
std::vector<Parser::Token> tokens;
|
||||
Parser parser;
|
||||
parser.parseIntoTokens( argc, argv, tokens );
|
||||
@@ -458,18 +482,23 @@ namespace Clara {
|
||||
typename std::vector<Arg>::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<ConfigT> m_boundProcessName;
|
||||
std::vector<Arg> m_options;
|
||||
std::map<int, Arg> m_positionalArgs;
|
||||
std::auto_ptr<Arg> m_arg;
|
||||
|
Reference in New Issue
Block a user