Now fully switched over to Clara-based command line with modified args

This commit is contained in:
Phil Nash
2013-06-04 08:37:28 +01:00
parent 130ec986c7
commit aee9b75e37
7 changed files with 105 additions and 329 deletions

View File

@@ -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)();
}

View File

@@ -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

View File

@@ -67,6 +67,7 @@ namespace Catch {
std::string reporterName;
std::string outputFilename;
std::string name;
std::string processName;
std::vector<std::string> testsOrTags;
};

View File

@@ -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;